xref: /aosp_15_r20/hardware/interfaces/audio/aidl/default/alsa/Utils.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #include <map>
18*4d7e907cSAndroid Build Coastguard Worker #include <set>
19*4d7e907cSAndroid Build Coastguard Worker 
20*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "AHAL_AlsaUtils"
21*4d7e907cSAndroid Build Coastguard Worker #include <Utils.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/media/audio/common/AudioFormatType.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/media/audio/common/PcmType.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <audio_utils/primitives.h>
26*4d7e907cSAndroid Build Coastguard Worker #include <cutils/compiler.h>
27*4d7e907cSAndroid Build Coastguard Worker 
28*4d7e907cSAndroid Build Coastguard Worker #include "Utils.h"
29*4d7e907cSAndroid Build Coastguard Worker #include "core-impl/utils.h"
30*4d7e907cSAndroid Build Coastguard Worker 
31*4d7e907cSAndroid Build Coastguard Worker using aidl::android::hardware::audio::common::getChannelCount;
32*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioChannelLayout;
33*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDeviceAddress;
34*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioFormatDescription;
35*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioFormatType;
36*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioIoFlags;
37*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioPortExt;
38*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::PcmType;
39*4d7e907cSAndroid Build Coastguard Worker 
40*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::audio::core::alsa {
41*4d7e907cSAndroid Build Coastguard Worker 
42*4d7e907cSAndroid Build Coastguard Worker const float kUnityGainFloat = 1.0f;
43*4d7e907cSAndroid Build Coastguard Worker 
DeviceProxy()44*4d7e907cSAndroid Build Coastguard Worker DeviceProxy::DeviceProxy() : mProfile(nullptr), mProxy(nullptr, alsaProxyDeleter) {}
45*4d7e907cSAndroid Build Coastguard Worker 
DeviceProxy(const DeviceProfile & deviceProfile)46*4d7e907cSAndroid Build Coastguard Worker DeviceProxy::DeviceProxy(const DeviceProfile& deviceProfile)
47*4d7e907cSAndroid Build Coastguard Worker     : mProfile(new alsa_device_profile), mProxy(new alsa_device_proxy, alsaProxyDeleter) {
48*4d7e907cSAndroid Build Coastguard Worker     profile_init(mProfile.get(), deviceProfile.direction);
49*4d7e907cSAndroid Build Coastguard Worker     mProfile->card = deviceProfile.card;
50*4d7e907cSAndroid Build Coastguard Worker     mProfile->device = deviceProfile.device;
51*4d7e907cSAndroid Build Coastguard Worker     memset(mProxy.get(), 0, sizeof(alsa_device_proxy));
52*4d7e907cSAndroid Build Coastguard Worker }
53*4d7e907cSAndroid Build Coastguard Worker 
alsaProxyDeleter(alsa_device_proxy * proxy)54*4d7e907cSAndroid Build Coastguard Worker void DeviceProxy::alsaProxyDeleter(alsa_device_proxy* proxy) {
55*4d7e907cSAndroid Build Coastguard Worker     if (proxy != nullptr) {
56*4d7e907cSAndroid Build Coastguard Worker         proxy_close(proxy);
57*4d7e907cSAndroid Build Coastguard Worker         delete proxy;
58*4d7e907cSAndroid Build Coastguard Worker     }
59*4d7e907cSAndroid Build Coastguard Worker }
60*4d7e907cSAndroid Build Coastguard Worker 
61*4d7e907cSAndroid Build Coastguard Worker namespace {
62*4d7e907cSAndroid Build Coastguard Worker 
63*4d7e907cSAndroid Build Coastguard Worker using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
64*4d7e907cSAndroid Build Coastguard Worker using AudioFormatDescToPcmFormatMap = std::map<AudioFormatDescription, enum pcm_format>;
65*4d7e907cSAndroid Build Coastguard Worker using PcmFormatToAudioFormatDescMap = std::map<enum pcm_format, AudioFormatDescription>;
66*4d7e907cSAndroid Build Coastguard Worker 
getInvalidChannelLayout()67*4d7e907cSAndroid Build Coastguard Worker AudioChannelLayout getInvalidChannelLayout() {
68*4d7e907cSAndroid Build Coastguard Worker     static const AudioChannelLayout invalidChannelLayout =
69*4d7e907cSAndroid Build Coastguard Worker             AudioChannelLayout::make<AudioChannelLayout::Tag::invalid>(0);
70*4d7e907cSAndroid Build Coastguard Worker     return invalidChannelLayout;
71*4d7e907cSAndroid Build Coastguard Worker }
72*4d7e907cSAndroid Build Coastguard Worker 
make_ChannelCountToMaskMap(const std::set<AudioChannelLayout> & channelMasks)73*4d7e907cSAndroid Build Coastguard Worker static AudioChannelCountToMaskMap make_ChannelCountToMaskMap(
74*4d7e907cSAndroid Build Coastguard Worker         const std::set<AudioChannelLayout>& channelMasks) {
75*4d7e907cSAndroid Build Coastguard Worker     AudioChannelCountToMaskMap channelMaskToCountMap;
76*4d7e907cSAndroid Build Coastguard Worker     for (const auto& channelMask : channelMasks) {
77*4d7e907cSAndroid Build Coastguard Worker         channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask);
78*4d7e907cSAndroid Build Coastguard Worker     }
79*4d7e907cSAndroid Build Coastguard Worker     return channelMaskToCountMap;
80*4d7e907cSAndroid Build Coastguard Worker }
81*4d7e907cSAndroid Build Coastguard Worker 
82*4d7e907cSAndroid Build Coastguard Worker #define DEFINE_CHANNEL_LAYOUT_MASK(n) \
83*4d7e907cSAndroid Build Coastguard Worker     AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(AudioChannelLayout::LAYOUT_##n)
84*4d7e907cSAndroid Build Coastguard Worker 
getSupportedChannelOutLayoutMap()85*4d7e907cSAndroid Build Coastguard Worker const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() {
86*4d7e907cSAndroid Build Coastguard Worker     static const std::set<AudioChannelLayout> supportedOutChannelLayouts = {
87*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_LAYOUT_MASK(MONO),
88*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
89*4d7e907cSAndroid Build Coastguard Worker     };
90*4d7e907cSAndroid Build Coastguard Worker     static const AudioChannelCountToMaskMap outLayouts =
91*4d7e907cSAndroid Build Coastguard Worker             make_ChannelCountToMaskMap(supportedOutChannelLayouts);
92*4d7e907cSAndroid Build Coastguard Worker     return outLayouts;
93*4d7e907cSAndroid Build Coastguard Worker }
94*4d7e907cSAndroid Build Coastguard Worker 
getSupportedChannelInLayoutMap()95*4d7e907cSAndroid Build Coastguard Worker const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() {
96*4d7e907cSAndroid Build Coastguard Worker     static const std::set<AudioChannelLayout> supportedInChannelLayouts = {
97*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_LAYOUT_MASK(MONO),
98*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
99*4d7e907cSAndroid Build Coastguard Worker     };
100*4d7e907cSAndroid Build Coastguard Worker     static const AudioChannelCountToMaskMap inLayouts =
101*4d7e907cSAndroid Build Coastguard Worker             make_ChannelCountToMaskMap(supportedInChannelLayouts);
102*4d7e907cSAndroid Build Coastguard Worker     return inLayouts;
103*4d7e907cSAndroid Build Coastguard Worker }
104*4d7e907cSAndroid Build Coastguard Worker 
105*4d7e907cSAndroid Build Coastguard Worker #undef DEFINE_CHANNEL_LAYOUT_MASK
106*4d7e907cSAndroid Build Coastguard Worker #define DEFINE_CHANNEL_INDEX_MASK(n) \
107*4d7e907cSAndroid Build Coastguard Worker     AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(AudioChannelLayout::INDEX_MASK_##n)
108*4d7e907cSAndroid Build Coastguard Worker 
getSupportedChannelIndexLayoutMap()109*4d7e907cSAndroid Build Coastguard Worker const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() {
110*4d7e907cSAndroid Build Coastguard Worker     static const std::set<AudioChannelLayout> supportedIndexChannelLayouts = {
111*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(1),  DEFINE_CHANNEL_INDEX_MASK(2),
112*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(3),  DEFINE_CHANNEL_INDEX_MASK(4),
113*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(5),  DEFINE_CHANNEL_INDEX_MASK(6),
114*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(7),  DEFINE_CHANNEL_INDEX_MASK(8),
115*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(9),  DEFINE_CHANNEL_INDEX_MASK(10),
116*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(11), DEFINE_CHANNEL_INDEX_MASK(12),
117*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(13), DEFINE_CHANNEL_INDEX_MASK(14),
118*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(15), DEFINE_CHANNEL_INDEX_MASK(16),
119*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(17), DEFINE_CHANNEL_INDEX_MASK(18),
120*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(19), DEFINE_CHANNEL_INDEX_MASK(20),
121*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(21), DEFINE_CHANNEL_INDEX_MASK(22),
122*4d7e907cSAndroid Build Coastguard Worker             DEFINE_CHANNEL_INDEX_MASK(23), DEFINE_CHANNEL_INDEX_MASK(24),
123*4d7e907cSAndroid Build Coastguard Worker     };
124*4d7e907cSAndroid Build Coastguard Worker     static const AudioChannelCountToMaskMap indexLayouts =
125*4d7e907cSAndroid Build Coastguard Worker             make_ChannelCountToMaskMap(supportedIndexChannelLayouts);
126*4d7e907cSAndroid Build Coastguard Worker     return indexLayouts;
127*4d7e907cSAndroid Build Coastguard Worker }
128*4d7e907cSAndroid Build Coastguard Worker 
129*4d7e907cSAndroid Build Coastguard Worker #undef DEFINE_CHANNEL_INDEX_MASK
130*4d7e907cSAndroid Build Coastguard Worker 
make_AudioFormatDescription(AudioFormatType type)131*4d7e907cSAndroid Build Coastguard Worker AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
132*4d7e907cSAndroid Build Coastguard Worker     AudioFormatDescription result;
133*4d7e907cSAndroid Build Coastguard Worker     result.type = type;
134*4d7e907cSAndroid Build Coastguard Worker     return result;
135*4d7e907cSAndroid Build Coastguard Worker }
136*4d7e907cSAndroid Build Coastguard Worker 
make_AudioFormatDescription(PcmType pcm)137*4d7e907cSAndroid Build Coastguard Worker AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {
138*4d7e907cSAndroid Build Coastguard Worker     auto result = make_AudioFormatDescription(AudioFormatType::PCM);
139*4d7e907cSAndroid Build Coastguard Worker     result.pcm = pcm;
140*4d7e907cSAndroid Build Coastguard Worker     return result;
141*4d7e907cSAndroid Build Coastguard Worker }
142*4d7e907cSAndroid Build Coastguard Worker 
getAudioFormatDescriptorToPcmFormatMap()143*4d7e907cSAndroid Build Coastguard Worker const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() {
144*4d7e907cSAndroid Build Coastguard Worker     static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = {
145*4d7e907cSAndroid Build Coastguard Worker             {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE},
146*4d7e907cSAndroid Build Coastguard Worker             {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_LE},
147*4d7e907cSAndroid Build Coastguard Worker             {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_3LE},
148*4d7e907cSAndroid Build Coastguard Worker             {make_AudioFormatDescription(PcmType::INT_32_BIT), PCM_FORMAT_S32_LE},
149*4d7e907cSAndroid Build Coastguard Worker             {make_AudioFormatDescription(PcmType::FLOAT_32_BIT), PCM_FORMAT_FLOAT_LE},
150*4d7e907cSAndroid Build Coastguard Worker     };
151*4d7e907cSAndroid Build Coastguard Worker     return formatDescToPcmFormatMap;
152*4d7e907cSAndroid Build Coastguard Worker }
153*4d7e907cSAndroid Build Coastguard Worker 
make_PcmFormatToAudioFormatDescMap(const AudioFormatDescToPcmFormatMap & formatDescToPcmFormatMap)154*4d7e907cSAndroid Build Coastguard Worker static PcmFormatToAudioFormatDescMap make_PcmFormatToAudioFormatDescMap(
155*4d7e907cSAndroid Build Coastguard Worker         const AudioFormatDescToPcmFormatMap& formatDescToPcmFormatMap) {
156*4d7e907cSAndroid Build Coastguard Worker     PcmFormatToAudioFormatDescMap result;
157*4d7e907cSAndroid Build Coastguard Worker     for (const auto& formatPair : formatDescToPcmFormatMap) {
158*4d7e907cSAndroid Build Coastguard Worker         result.emplace(formatPair.second, formatPair.first);
159*4d7e907cSAndroid Build Coastguard Worker     }
160*4d7e907cSAndroid Build Coastguard Worker     return result;
161*4d7e907cSAndroid Build Coastguard Worker }
162*4d7e907cSAndroid Build Coastguard Worker 
getPcmFormatToAudioFormatDescMap()163*4d7e907cSAndroid Build Coastguard Worker const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() {
164*4d7e907cSAndroid Build Coastguard Worker     static const PcmFormatToAudioFormatDescMap pcmFormatToFormatDescMap =
165*4d7e907cSAndroid Build Coastguard Worker             make_PcmFormatToAudioFormatDescMap(getAudioFormatDescriptorToPcmFormatMap());
166*4d7e907cSAndroid Build Coastguard Worker     return pcmFormatToFormatDescMap;
167*4d7e907cSAndroid Build Coastguard Worker }
168*4d7e907cSAndroid Build Coastguard Worker 
applyGainToInt16Buffer(void * buffer,const size_t bufferSizeBytes,const float gain,int channelCount)169*4d7e907cSAndroid Build Coastguard Worker void applyGainToInt16Buffer(void* buffer, const size_t bufferSizeBytes, const float gain,
170*4d7e907cSAndroid Build Coastguard Worker                             int channelCount) {
171*4d7e907cSAndroid Build Coastguard Worker     const uint16_t unityGainQ4_12 = u4_12_from_float(kUnityGainFloat);
172*4d7e907cSAndroid Build Coastguard Worker     const uint16_t vl = u4_12_from_float(gain);
173*4d7e907cSAndroid Build Coastguard Worker     const uint32_t vrl = (vl << 16) | vl;
174*4d7e907cSAndroid Build Coastguard Worker     int numFrames = 0;
175*4d7e907cSAndroid Build Coastguard Worker     if (channelCount == 2) {
176*4d7e907cSAndroid Build Coastguard Worker         numFrames = bufferSizeBytes / sizeof(uint32_t);
177*4d7e907cSAndroid Build Coastguard Worker         if (numFrames == 0) {
178*4d7e907cSAndroid Build Coastguard Worker             return;
179*4d7e907cSAndroid Build Coastguard Worker         }
180*4d7e907cSAndroid Build Coastguard Worker         uint32_t* intBuffer = (uint32_t*)buffer;
181*4d7e907cSAndroid Build Coastguard Worker         if (CC_UNLIKELY(vl > unityGainQ4_12)) {
182*4d7e907cSAndroid Build Coastguard Worker             do {
183*4d7e907cSAndroid Build Coastguard Worker                 int32_t l = mulRL(1, *intBuffer, vrl) >> 12;
184*4d7e907cSAndroid Build Coastguard Worker                 int32_t r = mulRL(0, *intBuffer, vrl) >> 12;
185*4d7e907cSAndroid Build Coastguard Worker                 l = clamp16(l);
186*4d7e907cSAndroid Build Coastguard Worker                 r = clamp16(r);
187*4d7e907cSAndroid Build Coastguard Worker                 *intBuffer++ = (r << 16) | (l & 0xFFFF);
188*4d7e907cSAndroid Build Coastguard Worker             } while (--numFrames);
189*4d7e907cSAndroid Build Coastguard Worker         } else {
190*4d7e907cSAndroid Build Coastguard Worker             do {
191*4d7e907cSAndroid Build Coastguard Worker                 int32_t l = mulRL(1, *intBuffer, vrl) >> 12;
192*4d7e907cSAndroid Build Coastguard Worker                 int32_t r = mulRL(0, *intBuffer, vrl) >> 12;
193*4d7e907cSAndroid Build Coastguard Worker                 *intBuffer++ = (r << 16) | (l & 0xFFFF);
194*4d7e907cSAndroid Build Coastguard Worker             } while (--numFrames);
195*4d7e907cSAndroid Build Coastguard Worker         }
196*4d7e907cSAndroid Build Coastguard Worker     } else {
197*4d7e907cSAndroid Build Coastguard Worker         numFrames = bufferSizeBytes / sizeof(uint16_t);
198*4d7e907cSAndroid Build Coastguard Worker         if (numFrames == 0) {
199*4d7e907cSAndroid Build Coastguard Worker             return;
200*4d7e907cSAndroid Build Coastguard Worker         }
201*4d7e907cSAndroid Build Coastguard Worker         int16_t* intBuffer = (int16_t*)buffer;
202*4d7e907cSAndroid Build Coastguard Worker         if (CC_UNLIKELY(vl > unityGainQ4_12)) {
203*4d7e907cSAndroid Build Coastguard Worker             do {
204*4d7e907cSAndroid Build Coastguard Worker                 int32_t mono = mul(*intBuffer, static_cast<int16_t>(vl)) >> 12;
205*4d7e907cSAndroid Build Coastguard Worker                 *intBuffer++ = clamp16(mono);
206*4d7e907cSAndroid Build Coastguard Worker             } while (--numFrames);
207*4d7e907cSAndroid Build Coastguard Worker         } else {
208*4d7e907cSAndroid Build Coastguard Worker             do {
209*4d7e907cSAndroid Build Coastguard Worker                 int32_t mono = mul(*intBuffer, static_cast<int16_t>(vl)) >> 12;
210*4d7e907cSAndroid Build Coastguard Worker                 *intBuffer++ = static_cast<int16_t>(mono & 0xFFFF);
211*4d7e907cSAndroid Build Coastguard Worker             } while (--numFrames);
212*4d7e907cSAndroid Build Coastguard Worker         }
213*4d7e907cSAndroid Build Coastguard Worker     }
214*4d7e907cSAndroid Build Coastguard Worker }
215*4d7e907cSAndroid Build Coastguard Worker 
applyGainToInt32Buffer(int32_t * typedBuffer,const size_t bufferSizeBytes,const float gain)216*4d7e907cSAndroid Build Coastguard Worker void applyGainToInt32Buffer(int32_t* typedBuffer, const size_t bufferSizeBytes, const float gain) {
217*4d7e907cSAndroid Build Coastguard Worker     int numSamples = bufferSizeBytes / sizeof(int32_t);
218*4d7e907cSAndroid Build Coastguard Worker     if (numSamples == 0) {
219*4d7e907cSAndroid Build Coastguard Worker         return;
220*4d7e907cSAndroid Build Coastguard Worker     }
221*4d7e907cSAndroid Build Coastguard Worker     if (CC_UNLIKELY(gain > kUnityGainFloat)) {
222*4d7e907cSAndroid Build Coastguard Worker         do {
223*4d7e907cSAndroid Build Coastguard Worker             float multiplied = (*typedBuffer) * gain;
224*4d7e907cSAndroid Build Coastguard Worker             if (multiplied > INT32_MAX) {
225*4d7e907cSAndroid Build Coastguard Worker                 *typedBuffer++ = INT32_MAX;
226*4d7e907cSAndroid Build Coastguard Worker             } else if (multiplied < INT32_MIN) {
227*4d7e907cSAndroid Build Coastguard Worker                 *typedBuffer++ = INT32_MIN;
228*4d7e907cSAndroid Build Coastguard Worker             } else {
229*4d7e907cSAndroid Build Coastguard Worker                 *typedBuffer++ = multiplied;
230*4d7e907cSAndroid Build Coastguard Worker             }
231*4d7e907cSAndroid Build Coastguard Worker         } while (--numSamples);
232*4d7e907cSAndroid Build Coastguard Worker     } else {
233*4d7e907cSAndroid Build Coastguard Worker         do {
234*4d7e907cSAndroid Build Coastguard Worker             *typedBuffer++ = (*typedBuffer) * gain;
235*4d7e907cSAndroid Build Coastguard Worker         } while (--numSamples);
236*4d7e907cSAndroid Build Coastguard Worker     }
237*4d7e907cSAndroid Build Coastguard Worker }
238*4d7e907cSAndroid Build Coastguard Worker 
applyGainToFloatBuffer(float * floatBuffer,const size_t bufferSizeBytes,const float gain)239*4d7e907cSAndroid Build Coastguard Worker void applyGainToFloatBuffer(float* floatBuffer, const size_t bufferSizeBytes, const float gain) {
240*4d7e907cSAndroid Build Coastguard Worker     int numSamples = bufferSizeBytes / sizeof(float);
241*4d7e907cSAndroid Build Coastguard Worker     if (numSamples == 0) {
242*4d7e907cSAndroid Build Coastguard Worker         return;
243*4d7e907cSAndroid Build Coastguard Worker     }
244*4d7e907cSAndroid Build Coastguard Worker     if (CC_UNLIKELY(gain > kUnityGainFloat)) {
245*4d7e907cSAndroid Build Coastguard Worker         do {
246*4d7e907cSAndroid Build Coastguard Worker             *floatBuffer++ = std::clamp((*floatBuffer) * gain, -kUnityGainFloat, kUnityGainFloat);
247*4d7e907cSAndroid Build Coastguard Worker         } while (--numSamples);
248*4d7e907cSAndroid Build Coastguard Worker     } else {
249*4d7e907cSAndroid Build Coastguard Worker         do {
250*4d7e907cSAndroid Build Coastguard Worker             *floatBuffer++ = (*floatBuffer) * gain;
251*4d7e907cSAndroid Build Coastguard Worker         } while (--numSamples);
252*4d7e907cSAndroid Build Coastguard Worker     }
253*4d7e907cSAndroid Build Coastguard Worker }
254*4d7e907cSAndroid Build Coastguard Worker 
255*4d7e907cSAndroid Build Coastguard Worker }  // namespace
256*4d7e907cSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const DeviceProfile & device)257*4d7e907cSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const DeviceProfile& device) {
258*4d7e907cSAndroid Build Coastguard Worker     return os << "<" << device.card << "," << device.device << ">";
259*4d7e907cSAndroid Build Coastguard Worker }
260*4d7e907cSAndroid Build Coastguard Worker 
getChannelLayoutMaskFromChannelCount(unsigned int channelCount,int isInput)261*4d7e907cSAndroid Build Coastguard Worker AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) {
262*4d7e907cSAndroid Build Coastguard Worker     return findValueOrDefault(
263*4d7e907cSAndroid Build Coastguard Worker             isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
264*4d7e907cSAndroid Build Coastguard Worker             channelCount, getInvalidChannelLayout());
265*4d7e907cSAndroid Build Coastguard Worker }
266*4d7e907cSAndroid Build Coastguard Worker 
getChannelIndexMaskFromChannelCount(unsigned int channelCount)267*4d7e907cSAndroid Build Coastguard Worker AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) {
268*4d7e907cSAndroid Build Coastguard Worker     return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount,
269*4d7e907cSAndroid Build Coastguard Worker                               getInvalidChannelLayout());
270*4d7e907cSAndroid Build Coastguard Worker }
271*4d7e907cSAndroid Build Coastguard Worker 
getChannelCountFromChannelMask(const AudioChannelLayout & channelMask,bool isInput)272*4d7e907cSAndroid Build Coastguard Worker unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) {
273*4d7e907cSAndroid Build Coastguard Worker     switch (channelMask.getTag()) {
274*4d7e907cSAndroid Build Coastguard Worker         case AudioChannelLayout::Tag::layoutMask: {
275*4d7e907cSAndroid Build Coastguard Worker             return findKeyOrDefault(
276*4d7e907cSAndroid Build Coastguard Worker                     isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
277*4d7e907cSAndroid Build Coastguard Worker                     static_cast<unsigned>(getChannelCount(channelMask)), 0u /*defaultValue*/);
278*4d7e907cSAndroid Build Coastguard Worker         }
279*4d7e907cSAndroid Build Coastguard Worker         case AudioChannelLayout::Tag::indexMask: {
280*4d7e907cSAndroid Build Coastguard Worker             return findKeyOrDefault(getSupportedChannelIndexLayoutMap(),
281*4d7e907cSAndroid Build Coastguard Worker                                     static_cast<unsigned>(getChannelCount(channelMask)),
282*4d7e907cSAndroid Build Coastguard Worker                                     0u /*defaultValue*/);
283*4d7e907cSAndroid Build Coastguard Worker         }
284*4d7e907cSAndroid Build Coastguard Worker         case AudioChannelLayout::Tag::none:
285*4d7e907cSAndroid Build Coastguard Worker         case AudioChannelLayout::Tag::invalid:
286*4d7e907cSAndroid Build Coastguard Worker         case AudioChannelLayout::Tag::voiceMask:
287*4d7e907cSAndroid Build Coastguard Worker         default:
288*4d7e907cSAndroid Build Coastguard Worker             return 0;
289*4d7e907cSAndroid Build Coastguard Worker     }
290*4d7e907cSAndroid Build Coastguard Worker }
291*4d7e907cSAndroid Build Coastguard Worker 
getChannelMasksFromProfile(const alsa_device_profile * profile)292*4d7e907cSAndroid Build Coastguard Worker std::vector<AudioChannelLayout> getChannelMasksFromProfile(const alsa_device_profile* profile) {
293*4d7e907cSAndroid Build Coastguard Worker     const bool isInput = profile->direction == PCM_IN;
294*4d7e907cSAndroid Build Coastguard Worker     std::vector<AudioChannelLayout> channels;
295*4d7e907cSAndroid Build Coastguard Worker     for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) {
296*4d7e907cSAndroid Build Coastguard Worker         auto layoutMask =
297*4d7e907cSAndroid Build Coastguard Worker                 alsa::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput);
298*4d7e907cSAndroid Build Coastguard Worker         if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) {
299*4d7e907cSAndroid Build Coastguard Worker             channels.push_back(layoutMask);
300*4d7e907cSAndroid Build Coastguard Worker         }
301*4d7e907cSAndroid Build Coastguard Worker         auto indexMask = alsa::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]);
302*4d7e907cSAndroid Build Coastguard Worker         if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) {
303*4d7e907cSAndroid Build Coastguard Worker             channels.push_back(indexMask);
304*4d7e907cSAndroid Build Coastguard Worker         }
305*4d7e907cSAndroid Build Coastguard Worker     }
306*4d7e907cSAndroid Build Coastguard Worker     return channels;
307*4d7e907cSAndroid Build Coastguard Worker }
308*4d7e907cSAndroid Build Coastguard Worker 
getDeviceProfile(const::aidl::android::media::audio::common::AudioDevice & audioDevice,bool isInput)309*4d7e907cSAndroid Build Coastguard Worker std::optional<DeviceProfile> getDeviceProfile(
310*4d7e907cSAndroid Build Coastguard Worker         const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput) {
311*4d7e907cSAndroid Build Coastguard Worker     if (audioDevice.address.getTag() != AudioDeviceAddress::Tag::alsa) {
312*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": not alsa address: " << audioDevice.toString();
313*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
314*4d7e907cSAndroid Build Coastguard Worker     }
315*4d7e907cSAndroid Build Coastguard Worker     auto& alsaAddress = audioDevice.address.get<AudioDeviceAddress::Tag::alsa>();
316*4d7e907cSAndroid Build Coastguard Worker     if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) {
317*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__
318*4d7e907cSAndroid Build Coastguard Worker                    << ": malformed alsa address: " << ::android::internal::ToString(alsaAddress);
319*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
320*4d7e907cSAndroid Build Coastguard Worker     }
321*4d7e907cSAndroid Build Coastguard Worker     return DeviceProfile{.card = alsaAddress[0],
322*4d7e907cSAndroid Build Coastguard Worker                          .device = alsaAddress[1],
323*4d7e907cSAndroid Build Coastguard Worker                          .direction = isInput ? PCM_IN : PCM_OUT,
324*4d7e907cSAndroid Build Coastguard Worker                          .isExternal = !audioDevice.type.connection.empty()};
325*4d7e907cSAndroid Build Coastguard Worker }
326*4d7e907cSAndroid Build Coastguard Worker 
getDeviceProfile(const::aidl::android::media::audio::common::AudioPort & audioPort)327*4d7e907cSAndroid Build Coastguard Worker std::optional<DeviceProfile> getDeviceProfile(
328*4d7e907cSAndroid Build Coastguard Worker         const ::aidl::android::media::audio::common::AudioPort& audioPort) {
329*4d7e907cSAndroid Build Coastguard Worker     if (audioPort.ext.getTag() != AudioPortExt::Tag::device) {
330*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": port id " << audioPort.id << " is not a device port";
331*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
332*4d7e907cSAndroid Build Coastguard Worker     }
333*4d7e907cSAndroid Build Coastguard Worker     auto& devicePort = audioPort.ext.get<AudioPortExt::Tag::device>();
334*4d7e907cSAndroid Build Coastguard Worker     return getDeviceProfile(devicePort.device, audioPort.flags.getTag() == AudioIoFlags::input);
335*4d7e907cSAndroid Build Coastguard Worker }
336*4d7e907cSAndroid Build Coastguard Worker 
getPcmConfig(const StreamContext & context,bool isInput)337*4d7e907cSAndroid Build Coastguard Worker std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput) {
338*4d7e907cSAndroid Build Coastguard Worker     struct pcm_config config;
339*4d7e907cSAndroid Build Coastguard Worker     config.channels = alsa::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
340*4d7e907cSAndroid Build Coastguard Worker     if (config.channels == 0) {
341*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
342*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
343*4d7e907cSAndroid Build Coastguard Worker     }
344*4d7e907cSAndroid Build Coastguard Worker     config.format = alsa::aidl2c_AudioFormatDescription_pcm_format(context.getFormat());
345*4d7e907cSAndroid Build Coastguard Worker     if (config.format == PCM_FORMAT_INVALID) {
346*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
347*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
348*4d7e907cSAndroid Build Coastguard Worker     }
349*4d7e907cSAndroid Build Coastguard Worker     config.rate = context.getSampleRate();
350*4d7e907cSAndroid Build Coastguard Worker     if (config.rate == 0) {
351*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
352*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
353*4d7e907cSAndroid Build Coastguard Worker     }
354*4d7e907cSAndroid Build Coastguard Worker     return config;
355*4d7e907cSAndroid Build Coastguard Worker }
356*4d7e907cSAndroid Build Coastguard Worker 
getSampleRatesFromProfile(const alsa_device_profile * profile)357*4d7e907cSAndroid Build Coastguard Worker std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile) {
358*4d7e907cSAndroid Build Coastguard Worker     std::vector<int> sampleRates;
359*4d7e907cSAndroid Build Coastguard Worker     for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) &&
360*4d7e907cSAndroid Build Coastguard Worker                     profile->sample_rates[i] != 0;
361*4d7e907cSAndroid Build Coastguard Worker          i++) {
362*4d7e907cSAndroid Build Coastguard Worker         sampleRates.push_back(profile->sample_rates[i]);
363*4d7e907cSAndroid Build Coastguard Worker     }
364*4d7e907cSAndroid Build Coastguard Worker     return sampleRates;
365*4d7e907cSAndroid Build Coastguard Worker }
366*4d7e907cSAndroid Build Coastguard Worker 
openProxyForAttachedDevice(const DeviceProfile & deviceProfile,struct pcm_config * pcmConfig,size_t bufferFrameCount)367*4d7e907cSAndroid Build Coastguard Worker DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
368*4d7e907cSAndroid Build Coastguard Worker                                        struct pcm_config* pcmConfig, size_t bufferFrameCount) {
369*4d7e907cSAndroid Build Coastguard Worker     if (deviceProfile.isExternal) {
370*4d7e907cSAndroid Build Coastguard Worker         LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
371*4d7e907cSAndroid Build Coastguard Worker     }
372*4d7e907cSAndroid Build Coastguard Worker     DeviceProxy proxy(deviceProfile);
373*4d7e907cSAndroid Build Coastguard Worker     if (!profile_fill_builtin_device_info(proxy.getProfile(), pcmConfig, bufferFrameCount)) {
374*4d7e907cSAndroid Build Coastguard Worker         LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
375*4d7e907cSAndroid Build Coastguard Worker     }
376*4d7e907cSAndroid Build Coastguard Worker     if (int err = proxy_prepare_from_default_config(proxy.get(), proxy.getProfile()); err != 0) {
377*4d7e907cSAndroid Build Coastguard Worker         LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
378*4d7e907cSAndroid Build Coastguard Worker                    << " error=" << err;
379*4d7e907cSAndroid Build Coastguard Worker         return DeviceProxy();
380*4d7e907cSAndroid Build Coastguard Worker     }
381*4d7e907cSAndroid Build Coastguard Worker     if (int err = proxy_open(proxy.get()); err != 0) {
382*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
383*4d7e907cSAndroid Build Coastguard Worker                    << " error=" << err;
384*4d7e907cSAndroid Build Coastguard Worker         return DeviceProxy();
385*4d7e907cSAndroid Build Coastguard Worker     }
386*4d7e907cSAndroid Build Coastguard Worker     return proxy;
387*4d7e907cSAndroid Build Coastguard Worker }
388*4d7e907cSAndroid Build Coastguard Worker 
openProxyForExternalDevice(const DeviceProfile & deviceProfile,struct pcm_config * pcmConfig,bool requireExactMatch)389*4d7e907cSAndroid Build Coastguard Worker DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
390*4d7e907cSAndroid Build Coastguard Worker                                        struct pcm_config* pcmConfig, bool requireExactMatch) {
391*4d7e907cSAndroid Build Coastguard Worker     if (!deviceProfile.isExternal) {
392*4d7e907cSAndroid Build Coastguard Worker         LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
393*4d7e907cSAndroid Build Coastguard Worker     }
394*4d7e907cSAndroid Build Coastguard Worker     auto proxy = readAlsaDeviceInfo(deviceProfile);
395*4d7e907cSAndroid Build Coastguard Worker     if (proxy.get() == nullptr) {
396*4d7e907cSAndroid Build Coastguard Worker         return proxy;
397*4d7e907cSAndroid Build Coastguard Worker     }
398*4d7e907cSAndroid Build Coastguard Worker     if (int err = proxy_prepare(proxy.get(), proxy.getProfile(), pcmConfig, requireExactMatch);
399*4d7e907cSAndroid Build Coastguard Worker         err != 0) {
400*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
401*4d7e907cSAndroid Build Coastguard Worker                    << " error=" << err;
402*4d7e907cSAndroid Build Coastguard Worker         return DeviceProxy();
403*4d7e907cSAndroid Build Coastguard Worker     }
404*4d7e907cSAndroid Build Coastguard Worker     if (int err = proxy_open(proxy.get()); err != 0) {
405*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
406*4d7e907cSAndroid Build Coastguard Worker                    << " error=" << err;
407*4d7e907cSAndroid Build Coastguard Worker         return DeviceProxy();
408*4d7e907cSAndroid Build Coastguard Worker     }
409*4d7e907cSAndroid Build Coastguard Worker     return proxy;
410*4d7e907cSAndroid Build Coastguard Worker }
411*4d7e907cSAndroid Build Coastguard Worker 
readAlsaDeviceInfo(const DeviceProfile & deviceProfile)412*4d7e907cSAndroid Build Coastguard Worker DeviceProxy readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
413*4d7e907cSAndroid Build Coastguard Worker     DeviceProxy proxy(deviceProfile);
414*4d7e907cSAndroid Build Coastguard Worker     if (!profile_read_device_info(proxy.getProfile())) {
415*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
416*4d7e907cSAndroid Build Coastguard Worker         return DeviceProxy();
417*4d7e907cSAndroid Build Coastguard Worker     }
418*4d7e907cSAndroid Build Coastguard Worker     return proxy;
419*4d7e907cSAndroid Build Coastguard Worker }
420*4d7e907cSAndroid Build Coastguard Worker 
resetTransferredFrames(DeviceProxy & proxy,uint64_t frames)421*4d7e907cSAndroid Build Coastguard Worker void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
422*4d7e907cSAndroid Build Coastguard Worker     if (proxy.get() != nullptr) {
423*4d7e907cSAndroid Build Coastguard Worker         proxy.get()->transferred = frames;
424*4d7e907cSAndroid Build Coastguard Worker     }
425*4d7e907cSAndroid Build Coastguard Worker }
426*4d7e907cSAndroid Build Coastguard Worker 
c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy)427*4d7e907cSAndroid Build Coastguard Worker AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
428*4d7e907cSAndroid Build Coastguard Worker     return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
429*4d7e907cSAndroid Build Coastguard Worker }
430*4d7e907cSAndroid Build Coastguard Worker 
aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription & aidl)431*4d7e907cSAndroid Build Coastguard Worker pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) {
432*4d7e907cSAndroid Build Coastguard Worker     return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID);
433*4d7e907cSAndroid Build Coastguard Worker }
434*4d7e907cSAndroid Build Coastguard Worker 
applyGain(void * buffer,float gain,size_t bufferSizeBytes,enum pcm_format pcmFormat,int channelCount)435*4d7e907cSAndroid Build Coastguard Worker void applyGain(void* buffer, float gain, size_t bufferSizeBytes, enum pcm_format pcmFormat,
436*4d7e907cSAndroid Build Coastguard Worker                int channelCount) {
437*4d7e907cSAndroid Build Coastguard Worker     if (channelCount != 1 && channelCount != 2) {
438*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << ": unsupported channel count " << channelCount;
439*4d7e907cSAndroid Build Coastguard Worker         return;
440*4d7e907cSAndroid Build Coastguard Worker     }
441*4d7e907cSAndroid Build Coastguard Worker     if (!getPcmFormatToAudioFormatDescMap().contains(pcmFormat)) {
442*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << ": unsupported pcm format " << pcmFormat;
443*4d7e907cSAndroid Build Coastguard Worker         return;
444*4d7e907cSAndroid Build Coastguard Worker     }
445*4d7e907cSAndroid Build Coastguard Worker     if (std::abs(gain - kUnityGainFloat) < 1e-6) {
446*4d7e907cSAndroid Build Coastguard Worker         return;
447*4d7e907cSAndroid Build Coastguard Worker     }
448*4d7e907cSAndroid Build Coastguard Worker     switch (pcmFormat) {
449*4d7e907cSAndroid Build Coastguard Worker         case PCM_FORMAT_S16_LE:
450*4d7e907cSAndroid Build Coastguard Worker             applyGainToInt16Buffer(buffer, bufferSizeBytes, gain, channelCount);
451*4d7e907cSAndroid Build Coastguard Worker             break;
452*4d7e907cSAndroid Build Coastguard Worker         case PCM_FORMAT_FLOAT_LE: {
453*4d7e907cSAndroid Build Coastguard Worker             float* floatBuffer = (float*)buffer;
454*4d7e907cSAndroid Build Coastguard Worker             applyGainToFloatBuffer(floatBuffer, bufferSizeBytes, gain);
455*4d7e907cSAndroid Build Coastguard Worker         } break;
456*4d7e907cSAndroid Build Coastguard Worker         case PCM_FORMAT_S24_LE:
457*4d7e907cSAndroid Build Coastguard Worker             // PCM_FORMAT_S24_LE buffer is composed of signed fixed-point 32-bit Q8.23 data with
458*4d7e907cSAndroid Build Coastguard Worker             // min and max limits of the same bit representation as min and max limits of
459*4d7e907cSAndroid Build Coastguard Worker             // PCM_FORMAT_S32_LE buffer.
460*4d7e907cSAndroid Build Coastguard Worker         case PCM_FORMAT_S32_LE: {
461*4d7e907cSAndroid Build Coastguard Worker             int32_t* typedBuffer = (int32_t*)buffer;
462*4d7e907cSAndroid Build Coastguard Worker             applyGainToInt32Buffer(typedBuffer, bufferSizeBytes, gain);
463*4d7e907cSAndroid Build Coastguard Worker         } break;
464*4d7e907cSAndroid Build Coastguard Worker         case PCM_FORMAT_S24_3LE: {
465*4d7e907cSAndroid Build Coastguard Worker             int numSamples = bufferSizeBytes / (sizeof(uint8_t) * 3);
466*4d7e907cSAndroid Build Coastguard Worker             if (numSamples == 0) {
467*4d7e907cSAndroid Build Coastguard Worker                 return;
468*4d7e907cSAndroid Build Coastguard Worker             }
469*4d7e907cSAndroid Build Coastguard Worker             std::unique_ptr<int32_t[]> typedBuffer(new int32_t[numSamples]);
470*4d7e907cSAndroid Build Coastguard Worker             memcpy_to_i32_from_p24(typedBuffer.get(), (uint8_t*)buffer, numSamples);
471*4d7e907cSAndroid Build Coastguard Worker             applyGainToInt32Buffer(typedBuffer.get(), numSamples * sizeof(int32_t), gain);
472*4d7e907cSAndroid Build Coastguard Worker             memcpy_to_p24_from_i32((uint8_t*)buffer, typedBuffer.get(), numSamples);
473*4d7e907cSAndroid Build Coastguard Worker         } break;
474*4d7e907cSAndroid Build Coastguard Worker         default:
475*4d7e907cSAndroid Build Coastguard Worker             LOG(FATAL) << __func__ << ": unsupported pcm format " << pcmFormat;
476*4d7e907cSAndroid Build Coastguard Worker             break;
477*4d7e907cSAndroid Build Coastguard Worker     }
478*4d7e907cSAndroid Build Coastguard Worker }
479*4d7e907cSAndroid Build Coastguard Worker 
480*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl::android::hardware::audio::core::alsa
481