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