• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <map>
18 #include <set>
19 
20 #define LOG_TAG "AHAL_AlsaUtils"
21 #include <Utils.h>
22 #include <aidl/android/media/audio/common/AudioFormatType.h>
23 #include <aidl/android/media/audio/common/PcmType.h>
24 #include <android-base/logging.h>
25 
26 #include "Utils.h"
27 #include "core-impl/utils.h"
28 
29 using aidl::android::hardware::audio::common::getChannelCount;
30 using aidl::android::media::audio::common::AudioChannelLayout;
31 using aidl::android::media::audio::common::AudioDeviceAddress;
32 using aidl::android::media::audio::common::AudioFormatDescription;
33 using aidl::android::media::audio::common::AudioFormatType;
34 using aidl::android::media::audio::common::AudioIoFlags;
35 using aidl::android::media::audio::common::AudioPortExt;
36 using aidl::android::media::audio::common::PcmType;
37 
38 namespace aidl::android::hardware::audio::core::alsa {
39 
DeviceProxy()40 DeviceProxy::DeviceProxy() : mProfile(nullptr), mProxy(nullptr, alsaProxyDeleter) {}
41 
DeviceProxy(const DeviceProfile & deviceProfile)42 DeviceProxy::DeviceProxy(const DeviceProfile& deviceProfile)
43     : mProfile(new alsa_device_profile), mProxy(new alsa_device_proxy, alsaProxyDeleter) {
44     profile_init(mProfile.get(), deviceProfile.direction);
45     mProfile->card = deviceProfile.card;
46     mProfile->device = deviceProfile.device;
47     memset(mProxy.get(), 0, sizeof(alsa_device_proxy));
48 }
49 
alsaProxyDeleter(alsa_device_proxy * proxy)50 void DeviceProxy::alsaProxyDeleter(alsa_device_proxy* proxy) {
51     if (proxy != nullptr) {
52         proxy_close(proxy);
53         delete proxy;
54     }
55 }
56 
57 namespace {
58 
59 using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
60 using AudioFormatDescToPcmFormatMap = std::map<AudioFormatDescription, enum pcm_format>;
61 using PcmFormatToAudioFormatDescMap = std::map<enum pcm_format, AudioFormatDescription>;
62 
getInvalidChannelLayout()63 AudioChannelLayout getInvalidChannelLayout() {
64     static const AudioChannelLayout invalidChannelLayout =
65             AudioChannelLayout::make<AudioChannelLayout::Tag::invalid>(0);
66     return invalidChannelLayout;
67 }
68 
make_ChannelCountToMaskMap(const std::set<AudioChannelLayout> & channelMasks)69 static AudioChannelCountToMaskMap make_ChannelCountToMaskMap(
70         const std::set<AudioChannelLayout>& channelMasks) {
71     AudioChannelCountToMaskMap channelMaskToCountMap;
72     for (const auto& channelMask : channelMasks) {
73         channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask);
74     }
75     return channelMaskToCountMap;
76 }
77 
78 #define DEFINE_CHANNEL_LAYOUT_MASK(n) \
79     AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(AudioChannelLayout::LAYOUT_##n)
80 
getSupportedChannelOutLayoutMap()81 const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() {
82     static const std::set<AudioChannelLayout> supportedOutChannelLayouts = {
83             DEFINE_CHANNEL_LAYOUT_MASK(MONO),          DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
84             DEFINE_CHANNEL_LAYOUT_MASK(2POINT1),       DEFINE_CHANNEL_LAYOUT_MASK(QUAD),
85             DEFINE_CHANNEL_LAYOUT_MASK(PENTA),         DEFINE_CHANNEL_LAYOUT_MASK(5POINT1),
86             DEFINE_CHANNEL_LAYOUT_MASK(6POINT1),       DEFINE_CHANNEL_LAYOUT_MASK(7POINT1),
87             DEFINE_CHANNEL_LAYOUT_MASK(7POINT1POINT4), DEFINE_CHANNEL_LAYOUT_MASK(22POINT2),
88     };
89     static const AudioChannelCountToMaskMap outLayouts =
90             make_ChannelCountToMaskMap(supportedOutChannelLayouts);
91     return outLayouts;
92 }
93 
getSupportedChannelInLayoutMap()94 const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() {
95     static const std::set<AudioChannelLayout> supportedInChannelLayouts = {
96             DEFINE_CHANNEL_LAYOUT_MASK(MONO),
97             DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
98     };
99     static const AudioChannelCountToMaskMap inLayouts =
100             make_ChannelCountToMaskMap(supportedInChannelLayouts);
101     return inLayouts;
102 }
103 
104 #undef DEFINE_CHANNEL_LAYOUT_MASK
105 #define DEFINE_CHANNEL_INDEX_MASK(n) \
106     AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(AudioChannelLayout::INDEX_MASK_##n)
107 
getSupportedChannelIndexLayoutMap()108 const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() {
109     static const std::set<AudioChannelLayout> supportedIndexChannelLayouts = {
110             DEFINE_CHANNEL_INDEX_MASK(1),  DEFINE_CHANNEL_INDEX_MASK(2),
111             DEFINE_CHANNEL_INDEX_MASK(3),  DEFINE_CHANNEL_INDEX_MASK(4),
112             DEFINE_CHANNEL_INDEX_MASK(5),  DEFINE_CHANNEL_INDEX_MASK(6),
113             DEFINE_CHANNEL_INDEX_MASK(7),  DEFINE_CHANNEL_INDEX_MASK(8),
114             DEFINE_CHANNEL_INDEX_MASK(9),  DEFINE_CHANNEL_INDEX_MASK(10),
115             DEFINE_CHANNEL_INDEX_MASK(11), DEFINE_CHANNEL_INDEX_MASK(12),
116             DEFINE_CHANNEL_INDEX_MASK(13), DEFINE_CHANNEL_INDEX_MASK(14),
117             DEFINE_CHANNEL_INDEX_MASK(15), DEFINE_CHANNEL_INDEX_MASK(16),
118             DEFINE_CHANNEL_INDEX_MASK(17), DEFINE_CHANNEL_INDEX_MASK(18),
119             DEFINE_CHANNEL_INDEX_MASK(19), DEFINE_CHANNEL_INDEX_MASK(20),
120             DEFINE_CHANNEL_INDEX_MASK(21), DEFINE_CHANNEL_INDEX_MASK(22),
121             DEFINE_CHANNEL_INDEX_MASK(23), DEFINE_CHANNEL_INDEX_MASK(24),
122     };
123     static const AudioChannelCountToMaskMap indexLayouts =
124             make_ChannelCountToMaskMap(supportedIndexChannelLayouts);
125     return indexLayouts;
126 }
127 
128 #undef DEFINE_CHANNEL_INDEX_MASK
129 
make_AudioFormatDescription(AudioFormatType type)130 AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
131     AudioFormatDescription result;
132     result.type = type;
133     return result;
134 }
135 
make_AudioFormatDescription(PcmType pcm)136 AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {
137     auto result = make_AudioFormatDescription(AudioFormatType::PCM);
138     result.pcm = pcm;
139     return result;
140 }
141 
getAudioFormatDescriptorToPcmFormatMap()142 const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() {
143     static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = {
144             {make_AudioFormatDescription(PcmType::UINT_8_BIT), PCM_FORMAT_S8},
145             {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE},
146             {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_LE},
147             {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_3LE},
148             {make_AudioFormatDescription(PcmType::INT_32_BIT), PCM_FORMAT_S32_LE},
149             {make_AudioFormatDescription(PcmType::FLOAT_32_BIT), PCM_FORMAT_FLOAT_LE},
150     };
151     return formatDescToPcmFormatMap;
152 }
153 
make_PcmFormatToAudioFormatDescMap(const AudioFormatDescToPcmFormatMap & formatDescToPcmFormatMap)154 static PcmFormatToAudioFormatDescMap make_PcmFormatToAudioFormatDescMap(
155         const AudioFormatDescToPcmFormatMap& formatDescToPcmFormatMap) {
156     PcmFormatToAudioFormatDescMap result;
157     for (const auto& formatPair : formatDescToPcmFormatMap) {
158         result.emplace(formatPair.second, formatPair.first);
159     }
160     return result;
161 }
162 
getPcmFormatToAudioFormatDescMap()163 const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() {
164     static const PcmFormatToAudioFormatDescMap pcmFormatToFormatDescMap =
165             make_PcmFormatToAudioFormatDescMap(getAudioFormatDescriptorToPcmFormatMap());
166     return pcmFormatToFormatDescMap;
167 }
168 
169 }  // namespace
170 
operator <<(std::ostream & os,const DeviceProfile & device)171 std::ostream& operator<<(std::ostream& os, const DeviceProfile& device) {
172     return os << "<" << device.card << "," << device.device << ">";
173 }
174 
getChannelLayoutMaskFromChannelCount(unsigned int channelCount,int isInput)175 AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) {
176     return findValueOrDefault(
177             isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
178             channelCount, getInvalidChannelLayout());
179 }
180 
getChannelIndexMaskFromChannelCount(unsigned int channelCount)181 AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) {
182     return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount,
183                               getInvalidChannelLayout());
184 }
185 
getChannelCountFromChannelMask(const AudioChannelLayout & channelMask,bool isInput)186 unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) {
187     switch (channelMask.getTag()) {
188         case AudioChannelLayout::Tag::layoutMask: {
189             return findKeyOrDefault(
190                     isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
191                     static_cast<unsigned>(getChannelCount(channelMask)), 0u /*defaultValue*/);
192         }
193         case AudioChannelLayout::Tag::indexMask: {
194             return findKeyOrDefault(getSupportedChannelIndexLayoutMap(),
195                                     static_cast<unsigned>(getChannelCount(channelMask)),
196                                     0u /*defaultValue*/);
197         }
198         case AudioChannelLayout::Tag::none:
199         case AudioChannelLayout::Tag::invalid:
200         case AudioChannelLayout::Tag::voiceMask:
201         default:
202             return 0;
203     }
204 }
205 
getChannelMasksFromProfile(const alsa_device_profile * profile)206 std::vector<AudioChannelLayout> getChannelMasksFromProfile(const alsa_device_profile* profile) {
207     const bool isInput = profile->direction == PCM_IN;
208     std::vector<AudioChannelLayout> channels;
209     for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) {
210         auto layoutMask =
211                 alsa::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput);
212         if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) {
213             channels.push_back(layoutMask);
214         }
215         auto indexMask = alsa::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]);
216         if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) {
217             channels.push_back(indexMask);
218         }
219     }
220     return channels;
221 }
222 
getDeviceProfile(const::aidl::android::media::audio::common::AudioDevice & audioDevice,bool isInput)223 std::optional<DeviceProfile> getDeviceProfile(
224         const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput) {
225     if (audioDevice.address.getTag() != AudioDeviceAddress::Tag::alsa) {
226         LOG(ERROR) << __func__ << ": not alsa address: " << audioDevice.toString();
227         return std::nullopt;
228     }
229     auto& alsaAddress = audioDevice.address.get<AudioDeviceAddress::Tag::alsa>();
230     if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) {
231         LOG(ERROR) << __func__
232                    << ": malformed alsa address: " << ::android::internal::ToString(alsaAddress);
233         return std::nullopt;
234     }
235     return DeviceProfile{.card = alsaAddress[0],
236                          .device = alsaAddress[1],
237                          .direction = isInput ? PCM_IN : PCM_OUT,
238                          .isExternal = !audioDevice.type.connection.empty()};
239 }
240 
getDeviceProfile(const::aidl::android::media::audio::common::AudioPort & audioPort)241 std::optional<DeviceProfile> getDeviceProfile(
242         const ::aidl::android::media::audio::common::AudioPort& audioPort) {
243     if (audioPort.ext.getTag() != AudioPortExt::Tag::device) {
244         LOG(ERROR) << __func__ << ": port id " << audioPort.id << " is not a device port";
245         return std::nullopt;
246     }
247     auto& devicePort = audioPort.ext.get<AudioPortExt::Tag::device>();
248     return getDeviceProfile(devicePort.device, audioPort.flags.getTag() == AudioIoFlags::input);
249 }
250 
getPcmConfig(const StreamContext & context,bool isInput)251 std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput) {
252     struct pcm_config config;
253     config.channels = alsa::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
254     if (config.channels == 0) {
255         LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
256         return std::nullopt;
257     }
258     config.format = alsa::aidl2c_AudioFormatDescription_pcm_format(context.getFormat());
259     if (config.format == PCM_FORMAT_INVALID) {
260         LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
261         return std::nullopt;
262     }
263     config.rate = context.getSampleRate();
264     if (config.rate == 0) {
265         LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
266         return std::nullopt;
267     }
268     return config;
269 }
270 
getSampleRatesFromProfile(const alsa_device_profile * profile)271 std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile) {
272     std::vector<int> sampleRates;
273     for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) &&
274                     profile->sample_rates[i] != 0;
275          i++) {
276         sampleRates.push_back(profile->sample_rates[i]);
277     }
278     return sampleRates;
279 }
280 
openProxyForAttachedDevice(const DeviceProfile & deviceProfile,struct pcm_config * pcmConfig,size_t bufferFrameCount)281 DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
282                                        struct pcm_config* pcmConfig, size_t bufferFrameCount) {
283     if (deviceProfile.isExternal) {
284         LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
285     }
286     DeviceProxy proxy(deviceProfile);
287     if (!profile_fill_builtin_device_info(proxy.getProfile(), pcmConfig, bufferFrameCount)) {
288         LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
289     }
290     if (int err = proxy_prepare_from_default_config(proxy.get(), proxy.getProfile()); err != 0) {
291         LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
292                    << " error=" << err;
293         return DeviceProxy();
294     }
295     if (int err = proxy_open(proxy.get()); err != 0) {
296         LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
297                    << " error=" << err;
298         return DeviceProxy();
299     }
300     return proxy;
301 }
302 
openProxyForExternalDevice(const DeviceProfile & deviceProfile,struct pcm_config * pcmConfig,bool requireExactMatch)303 DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
304                                        struct pcm_config* pcmConfig, bool requireExactMatch) {
305     if (!deviceProfile.isExternal) {
306         LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
307     }
308     auto proxy = readAlsaDeviceInfo(deviceProfile);
309     if (proxy.get() == nullptr) {
310         return proxy;
311     }
312     if (int err = proxy_prepare(proxy.get(), proxy.getProfile(), pcmConfig, requireExactMatch);
313         err != 0) {
314         LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
315                    << " error=" << err;
316         return DeviceProxy();
317     }
318     if (int err = proxy_open(proxy.get()); err != 0) {
319         LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
320                    << " error=" << err;
321         return DeviceProxy();
322     }
323     return proxy;
324 }
325 
readAlsaDeviceInfo(const DeviceProfile & deviceProfile)326 DeviceProxy readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
327     DeviceProxy proxy(deviceProfile);
328     if (!profile_read_device_info(proxy.getProfile())) {
329         LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
330         return DeviceProxy();
331     }
332     return proxy;
333 }
334 
resetTransferredFrames(DeviceProxy & proxy,uint64_t frames)335 void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
336     if (proxy.get() != nullptr) {
337         proxy.get()->transferred = frames;
338     }
339 }
340 
c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy)341 AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
342     return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
343 }
344 
aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription & aidl)345 pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) {
346     return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID);
347 }
348 
349 }  // namespace aidl::android::hardware::audio::core::alsa
350