1 /*
2  * Copyright (C) 2017 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 #define LOG_TAG "RecordBufferConverter"
18 //#define LOG_NDEBUG 0
19 
20 #include <audio_utils/primitives.h>
21 #include <audio_utils/format.h>
22 #include <media/AudioMixer.h>  // for UNITY_GAIN_FLOAT
23 #include <media/AudioResampler.h>
24 #include <media/BufferProviders.h>
25 #include <media/RecordBufferConverter.h>
26 #include <utils/Log.h>
27 
28 #ifndef ARRAY_SIZE
29 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
30 #endif
31 
32 template <typename T>
max(const T & a,const T & b)33 static inline T max(const T& a, const T& b)
34 {
35     return a > b ? a : b;
36 }
37 
38 namespace android {
39 
RecordBufferConverter(audio_channel_mask_t srcChannelMask,audio_format_t srcFormat,uint32_t srcSampleRate,audio_channel_mask_t dstChannelMask,audio_format_t dstFormat,uint32_t dstSampleRate)40 RecordBufferConverter::RecordBufferConverter(
41         audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
42         uint32_t srcSampleRate,
43         audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
44         uint32_t dstSampleRate) :
45             mSrcChannelMask(AUDIO_CHANNEL_INVALID), // updateParameters will set following vars
46             // mSrcFormat
47             // mSrcSampleRate
48             // mDstChannelMask
49             // mDstFormat
50             // mDstSampleRate
51             // mSrcChannelCount
52             // mDstChannelCount
53             // mDstFrameSize
54             mBuf(NULL), mBufFrames(0), mBufFrameSize(0),
55             mResampler(NULL),
56             mIsLegacyDownmix(false),
57             mIsLegacyUpmix(false),
58             mRequiresFloat(false),
59             mInputConverterProvider(NULL)
60 {
61     (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate,
62             dstChannelMask, dstFormat, dstSampleRate);
63 }
64 
~RecordBufferConverter()65 RecordBufferConverter::~RecordBufferConverter() {
66     free(mBuf);
67     delete mResampler;
68     delete mInputConverterProvider;
69 }
70 
reset()71 void RecordBufferConverter::reset() {
72     if (mResampler != NULL) {
73         mResampler->reset();
74     }
75 }
76 
convert(void * dst,AudioBufferProvider * provider,size_t frames)77 size_t RecordBufferConverter::convert(void *dst,
78         AudioBufferProvider *provider, size_t frames)
79 {
80     if (mInputConverterProvider != NULL) {
81         mInputConverterProvider->setBufferProvider(provider);
82         provider = mInputConverterProvider;
83     }
84 
85     if (mResampler == NULL) {
86         ALOGV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
87                 mSrcSampleRate, mSrcFormat, mDstFormat);
88 
89         AudioBufferProvider::Buffer buffer;
90         for (size_t i = frames; i > 0; ) {
91             buffer.frameCount = i;
92             status_t status = provider->getNextBuffer(&buffer);
93             if (status != OK || buffer.frameCount == 0) {
94                 frames -= i; // cannot fill request.
95                 break;
96             }
97             // format convert to destination buffer
98             convertNoResampler(dst, buffer.raw, buffer.frameCount);
99 
100             dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize;
101             i -= buffer.frameCount;
102             provider->releaseBuffer(&buffer);
103         }
104     } else {
105          ALOGV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
106                  mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat);
107 
108          // reallocate buffer if needed
109          if (mBufFrameSize != 0 && mBufFrames < frames) {
110              free(mBuf);
111              mBufFrames = frames;
112              (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
113          }
114         // resampler accumulates, but we only have one source track
115         memset(mBuf, 0, frames * mBufFrameSize);
116         frames = mResampler->resample((int32_t*)mBuf, frames, provider);
117         // format convert to destination buffer
118         convertResampler(dst, mBuf, frames);
119     }
120     // Release unused frames in the InputConverterProvider buffer so that
121     // the RecordThread is able to properly account for consumed frames.
122     if (mInputConverterProvider != nullptr) {
123         mInputConverterProvider->reset();
124     }
125     return frames;
126 }
127 
updateParameters(audio_channel_mask_t srcChannelMask,audio_format_t srcFormat,uint32_t srcSampleRate,audio_channel_mask_t dstChannelMask,audio_format_t dstFormat,uint32_t dstSampleRate)128 status_t RecordBufferConverter::updateParameters(
129         audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
130         uint32_t srcSampleRate,
131         audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
132         uint32_t dstSampleRate)
133 {
134     // quick evaluation if there is any change.
135     if (mSrcFormat == srcFormat
136             && mSrcChannelMask == srcChannelMask
137             && mSrcSampleRate == srcSampleRate
138             && mDstFormat == dstFormat
139             && mDstChannelMask == dstChannelMask
140             && mDstSampleRate == dstSampleRate) {
141         return NO_ERROR;
142     }
143 
144     ALOGV("RecordBufferConverter updateParameters srcMask:%#x dstMask:%#x"
145             "  srcFormat:%#x dstFormat:%#x  srcRate:%u dstRate:%u",
146             srcChannelMask, dstChannelMask, srcFormat, dstFormat, srcSampleRate, dstSampleRate);
147     const bool valid =
148             audio_is_input_channel(srcChannelMask)
149             && audio_is_input_channel(dstChannelMask)
150             && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat)
151             && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat)
152             && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX)
153             ; // no upsampling checks for now
154     if (!valid) {
155         return BAD_VALUE;
156     }
157 
158     mSrcFormat = srcFormat;
159     mSrcChannelMask = srcChannelMask;
160     mSrcSampleRate = srcSampleRate;
161     mDstFormat = dstFormat;
162     mDstChannelMask = dstChannelMask;
163     mDstSampleRate = dstSampleRate;
164 
165     // compute derived parameters
166     mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
167     mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
168     mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat);
169 
170     // do we need to resample?
171     delete mResampler;
172     mResampler = NULL;
173     if (mSrcSampleRate != mDstSampleRate) {
174         mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT,
175                 mSrcChannelCount, mDstSampleRate);
176         mResampler->setSampleRate(mSrcSampleRate);
177         mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
178     }
179 
180     // are we running legacy channel conversion modes?
181     mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO
182                             || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK)
183                    && mDstChannelMask == AUDIO_CHANNEL_IN_MONO;
184     mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO
185                    && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO
186                             || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK);
187 
188     // do we need to process in float?
189     mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix;
190 
191     // do we need a staging buffer to convert for destination (we can still optimize this)?
192     // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity
193     if (mResampler != NULL) {
194         mBufFrameSize = max(mSrcChannelCount, (uint32_t)FCC_2)
195                 * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
196     } else if (mIsLegacyUpmix || mIsLegacyDownmix) { // legacy modes always float
197         mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
198     } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) {
199         mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat);
200     } else {
201         mBufFrameSize = 0;
202     }
203     mBufFrames = 0; // force the buffer to be resized.
204 
205     // do we need an input converter buffer provider to give us float?
206     delete mInputConverterProvider;
207     mInputConverterProvider = NULL;
208     if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) {
209         mInputConverterProvider = new ReformatBufferProvider(
210                 audio_channel_count_from_in_mask(mSrcChannelMask),
211                 mSrcFormat,
212                 AUDIO_FORMAT_PCM_FLOAT,
213                 256 /* provider buffer frame count */);
214     }
215 
216     // do we need a remixer to do channel mask conversion
217     if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) {
218         (void) memcpy_by_index_array_initialization_from_channel_mask(
219                 mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask);
220     }
221     return NO_ERROR;
222 }
223 
convertNoResampler(void * dst,const void * src,size_t frames)224 void RecordBufferConverter::convertNoResampler(
225         void *dst, const void *src, size_t frames)
226 {
227     // src is native type unless there is legacy upmix or downmix, whereupon it is float.
228     if (mBufFrameSize != 0 && mBufFrames < frames) {
229         free(mBuf);
230         mBufFrames = frames;
231         (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
232     }
233     // do we need to do legacy upmix and downmix?
234     if (mIsLegacyUpmix || mIsLegacyDownmix) {
235         void *dstBuf = mBuf != NULL ? mBuf : dst;
236         if (mIsLegacyUpmix) {
237             upmix_to_stereo_float_from_mono_float((float *)dstBuf,
238                     (const float *)src, frames);
239         } else /*mIsLegacyDownmix */ {
240             downmix_to_mono_float_from_stereo_float((float *)dstBuf,
241                     (const float *)src, frames);
242         }
243         if (mBuf != NULL) {
244             memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT,
245                     frames * mDstChannelCount);
246         }
247         return;
248     }
249     // do we need to do channel mask conversion?
250     if (mSrcChannelMask != mDstChannelMask) {
251         void *dstBuf = mBuf != NULL ? mBuf : dst;
252         memcpy_by_index_array(dstBuf, mDstChannelCount,
253                 src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames);
254         if (dstBuf == dst) {
255             return; // format is the same
256         }
257     }
258     // convert to destination buffer
259     const void *convertBuf = mBuf != NULL ? mBuf : src;
260     memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat,
261             frames * mDstChannelCount);
262 }
263 
convertResampler(void * dst,void * src,size_t frames)264 void RecordBufferConverter::convertResampler(
265         void *dst, /*not-a-const*/ void *src, size_t frames)
266 {
267     // src buffer format is ALWAYS float when entering this routine
268     if (mIsLegacyUpmix) {
269         ; // mono to stereo already handled by resampler
270     } else if (mIsLegacyDownmix
271             || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) {
272         // the resampler outputs stereo for mono input channel (a feature?)
273         // must convert to mono
274         downmix_to_mono_float_from_stereo_float((float *)src,
275                 (const float *)src, frames);
276     } else if (mSrcChannelMask != mDstChannelMask) {
277         // convert to mono channel again for channel mask conversion (could be skipped
278         // with further optimization).
279         if (mSrcChannelCount == 1) {
280             downmix_to_mono_float_from_stereo_float((float *)src,
281                 (const float *)src, frames);
282         }
283         // convert to destination format (in place, OK as float is larger than other types)
284         if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
285             memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
286                     frames * mSrcChannelCount);
287         }
288         // channel convert and save to dst
289         memcpy_by_index_array(dst, mDstChannelCount,
290                 src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames);
291         return;
292     }
293     // convert to destination format and save to dst
294     memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
295             frames * mDstChannelCount);
296 }
297 
298 // ----------------------------------------------------------------------------
299 } // namespace android
300