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