Home | History | Annotate | Download | only in libaudioprocessing
      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>
     33 static inline T max(const T& a, const T& b)
     34 {
     35     return a > b ? a : b;
     36 }
     37 
     38 namespace android {
     39 
     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 
     65 RecordBufferConverter::~RecordBufferConverter() {
     66     free(mBuf);
     67     delete mResampler;
     68     delete mInputConverterProvider;
     69 }
     70 
     71 void RecordBufferConverter::reset() {
     72     if (mResampler != NULL) {
     73         mResampler->reset();
     74     }
     75 }
     76 
     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     return frames;
    121 }
    122 
    123 status_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 
    219 void 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 
    259 void 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