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
32template <typename T>
33static inline T max(const T& a, const T& b)
34{
35    return a > b ? a : b;
36}
37
38namespace android {
39
40RecordBufferConverter::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
65RecordBufferConverter::~RecordBufferConverter() {
66    free(mBuf);
67    delete mResampler;
68    delete mInputConverterProvider;
69}
70
71void RecordBufferConverter::reset() {
72    if (mResampler != NULL) {
73        mResampler->reset();
74    }
75}
76
77size_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    return frames;
121}
122
123status_t RecordBufferConverter::updateParameters(
124        audio_channel_mask_t srcChannelMask, audio_format_t srcFormat,
125        uint32_t srcSampleRate,
126        audio_channel_mask_t dstChannelMask, audio_format_t dstFormat,
127        uint32_t dstSampleRate)
128{
129    // quick evaluation if there is any change.
130    if (mSrcFormat == srcFormat
131            && mSrcChannelMask == srcChannelMask
132            && mSrcSampleRate == srcSampleRate
133            && mDstFormat == dstFormat
134            && mDstChannelMask == dstChannelMask
135            && mDstSampleRate == dstSampleRate) {
136        return NO_ERROR;
137    }
138
139    ALOGV("RecordBufferConverter updateParameters srcMask:%#x dstMask:%#x"
140            "  srcFormat:%#x dstFormat:%#x  srcRate:%u dstRate:%u",
141            srcChannelMask, dstChannelMask, srcFormat, dstFormat, srcSampleRate, dstSampleRate);
142    const bool valid =
143            audio_is_input_channel(srcChannelMask)
144            && audio_is_input_channel(dstChannelMask)
145            && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat)
146            && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat)
147            && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX)
148            ; // no upsampling checks for now
149    if (!valid) {
150        return BAD_VALUE;
151    }
152
153    mSrcFormat = srcFormat;
154    mSrcChannelMask = srcChannelMask;
155    mSrcSampleRate = srcSampleRate;
156    mDstFormat = dstFormat;
157    mDstChannelMask = dstChannelMask;
158    mDstSampleRate = dstSampleRate;
159
160    // compute derived parameters
161    mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
162    mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
163    mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat);
164
165    // do we need to resample?
166    delete mResampler;
167    mResampler = NULL;
168    if (mSrcSampleRate != mDstSampleRate) {
169        mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT,
170                mSrcChannelCount, mDstSampleRate);
171        mResampler->setSampleRate(mSrcSampleRate);
172        mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
173    }
174
175    // are we running legacy channel conversion modes?
176    mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO
177                            || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK)
178                   && mDstChannelMask == AUDIO_CHANNEL_IN_MONO;
179    mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO
180                   && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO
181                            || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK);
182
183    // do we need to process in float?
184    mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix;
185
186    // do we need a staging buffer to convert for destination (we can still optimize this)?
187    // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity
188    if (mResampler != NULL) {
189        mBufFrameSize = max(mSrcChannelCount, (uint32_t)FCC_2)
190                * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
191    } else if (mIsLegacyUpmix || mIsLegacyDownmix) { // legacy modes always float
192        mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
193    } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) {
194        mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat);
195    } else {
196        mBufFrameSize = 0;
197    }
198    mBufFrames = 0; // force the buffer to be resized.
199
200    // do we need an input converter buffer provider to give us float?
201    delete mInputConverterProvider;
202    mInputConverterProvider = NULL;
203    if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) {
204        mInputConverterProvider = new ReformatBufferProvider(
205                audio_channel_count_from_in_mask(mSrcChannelMask),
206                mSrcFormat,
207                AUDIO_FORMAT_PCM_FLOAT,
208                256 /* provider buffer frame count */);
209    }
210
211    // do we need a remixer to do channel mask conversion
212    if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) {
213        (void) memcpy_by_index_array_initialization_from_channel_mask(
214                mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask);
215    }
216    return NO_ERROR;
217}
218
219void RecordBufferConverter::convertNoResampler(
220        void *dst, const void *src, size_t frames)
221{
222    // src is native type unless there is legacy upmix or downmix, whereupon it is float.
223    if (mBufFrameSize != 0 && mBufFrames < frames) {
224        free(mBuf);
225        mBufFrames = frames;
226        (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
227    }
228    // do we need to do legacy upmix and downmix?
229    if (mIsLegacyUpmix || mIsLegacyDownmix) {
230        void *dstBuf = mBuf != NULL ? mBuf : dst;
231        if (mIsLegacyUpmix) {
232            upmix_to_stereo_float_from_mono_float((float *)dstBuf,
233                    (const float *)src, frames);
234        } else /*mIsLegacyDownmix */ {
235            downmix_to_mono_float_from_stereo_float((float *)dstBuf,
236                    (const float *)src, frames);
237        }
238        if (mBuf != NULL) {
239            memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT,
240                    frames * mDstChannelCount);
241        }
242        return;
243    }
244    // do we need to do channel mask conversion?
245    if (mSrcChannelMask != mDstChannelMask) {
246        void *dstBuf = mBuf != NULL ? mBuf : dst;
247        memcpy_by_index_array(dstBuf, mDstChannelCount,
248                src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames);
249        if (dstBuf == dst) {
250            return; // format is the same
251        }
252    }
253    // convert to destination buffer
254    const void *convertBuf = mBuf != NULL ? mBuf : src;
255    memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat,
256            frames * mDstChannelCount);
257}
258
259void RecordBufferConverter::convertResampler(
260        void *dst, /*not-a-const*/ void *src, size_t frames)
261{
262    // src buffer format is ALWAYS float when entering this routine
263    if (mIsLegacyUpmix) {
264        ; // mono to stereo already handled by resampler
265    } else if (mIsLegacyDownmix
266            || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) {
267        // the resampler outputs stereo for mono input channel (a feature?)
268        // must convert to mono
269        downmix_to_mono_float_from_stereo_float((float *)src,
270                (const float *)src, frames);
271    } else if (mSrcChannelMask != mDstChannelMask) {
272        // convert to mono channel again for channel mask conversion (could be skipped
273        // with further optimization).
274        if (mSrcChannelCount == 1) {
275            downmix_to_mono_float_from_stereo_float((float *)src,
276                (const float *)src, frames);
277        }
278        // convert to destination format (in place, OK as float is larger than other types)
279        if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
280            memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
281                    frames * mSrcChannelCount);
282        }
283        // channel convert and save to dst
284        memcpy_by_index_array(dst, mDstChannelCount,
285                src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames);
286        return;
287    }
288    // convert to destination format and save to dst
289    memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
290            frames * mDstChannelCount);
291}
292
293// ----------------------------------------------------------------------------
294} // namespace android
295