Loading include/media/BufferProviders.h +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <sys/types.h> #include <media/AudioBufferProvider.h> #include <media/AudioResamplerPublic.h> #include <system/audio.h> #include <system/audio_effect.h> #include <utils/StrongPointer.h> Loading include/media/RecordBufferConverter.h 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_RECORD_BUFFER_CONVERTER_H #define ANDROID_RECORD_BUFFER_CONVERTER_H #include <stdint.h> #include <sys/types.h> #include <media/AudioBufferProvider.h> #include <system/audio.h> class AudioResampler; class PassthruBufferProvider; namespace android { /* The RecordBufferConverter is used for format, channel, and sample rate * conversion for a RecordTrack. * * RecordBufferConverter uses the convert() method rather than exposing a * buffer provider interface; this is to save a memory copy. * * There are legacy conversion requirements for this converter, specifically * due to mono handling, so be careful about modifying. * * Original source audioflinger/Threads.{h,cpp} */ class RecordBufferConverter { public: 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); ~RecordBufferConverter(); /* Converts input data from an AudioBufferProvider by format, channelMask, * and sampleRate to a destination buffer. * * Parameters * dst: buffer to place the converted data. * provider: buffer provider to obtain source data. * frames: number of frames to convert * * Returns the number of frames converted. */ size_t convert(void *dst, AudioBufferProvider *provider, size_t frames); // returns NO_ERROR if constructor was successful status_t initCheck() const { // mSrcChannelMask set on successful updateParameters return mSrcChannelMask != AUDIO_CHANNEL_INVALID ? NO_ERROR : NO_INIT; } // allows dynamic reconfigure of all parameters status_t 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); // called to reset resampler buffers on record track discontinuity void reset(); private: // format conversion when not using resampler void convertNoResampler(void *dst, const void *src, size_t frames); // format conversion when using resampler; modifies src in-place void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames); // user provided information audio_channel_mask_t mSrcChannelMask; audio_format_t mSrcFormat; uint32_t mSrcSampleRate; audio_channel_mask_t mDstChannelMask; audio_format_t mDstFormat; uint32_t mDstSampleRate; // derived information uint32_t mSrcChannelCount; uint32_t mDstChannelCount; size_t mDstFrameSize; // format conversion buffer void *mBuf; size_t mBufFrames; size_t mBufFrameSize; // resampler info AudioResampler *mResampler; bool mIsLegacyDownmix; // legacy stereo to mono conversion needed bool mIsLegacyUpmix; // legacy mono to stereo conversion needed bool mRequiresFloat; // data processing requires float (e.g. resampler) PassthruBufferProvider *mInputConverterProvider; // converts input to float int8_t mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion }; // ---------------------------------------------------------------------------- } // namespace android #endif // ANDROID_RECORD_BUFFER_CONVERTER_H media/libaudioprocessing/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ LOCAL_SRC_FILES := \ AudioResamplerSinc.cpp.arm \ AudioResamplerDyn.cpp.arm \ BufferProviders.cpp \ RecordBufferConverter.cpp \ LOCAL_C_INCLUDES := \ $(TOP) \ Loading media/libaudioprocessing/RecordBufferConverter.cpp 0 → 100644 +294 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "RecordBufferConverter" //#define LOG_NDEBUG 0 #include <audio_utils/primitives.h> #include <audio_utils/format.h> #include <media/AudioMixer.h> // for UNITY_GAIN_FLOAT #include <media/AudioResampler.h> #include <media/BufferProviders.h> #include <media/RecordBufferConverter.h> #include <utils/Log.h> #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) #endif template <typename T> static inline T max(const T& a, const T& b) { return a > b ? a : b; } namespace android { RecordBufferConverter::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) : mSrcChannelMask(AUDIO_CHANNEL_INVALID), // updateParameters will set following vars // mSrcFormat // mSrcSampleRate // mDstChannelMask // mDstFormat // mDstSampleRate // mSrcChannelCount // mDstChannelCount // mDstFrameSize mBuf(NULL), mBufFrames(0), mBufFrameSize(0), mResampler(NULL), mIsLegacyDownmix(false), mIsLegacyUpmix(false), mRequiresFloat(false), mInputConverterProvider(NULL) { (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate, dstChannelMask, dstFormat, dstSampleRate); } RecordBufferConverter::~RecordBufferConverter() { free(mBuf); delete mResampler; delete mInputConverterProvider; } void RecordBufferConverter::reset() { if (mResampler != NULL) { mResampler->reset(); } } size_t RecordBufferConverter::convert(void *dst, AudioBufferProvider *provider, size_t frames) { if (mInputConverterProvider != NULL) { mInputConverterProvider->setBufferProvider(provider); provider = mInputConverterProvider; } if (mResampler == NULL) { ALOGV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x", mSrcSampleRate, mSrcFormat, mDstFormat); AudioBufferProvider::Buffer buffer; for (size_t i = frames; i > 0; ) { buffer.frameCount = i; status_t status = provider->getNextBuffer(&buffer); if (status != OK || buffer.frameCount == 0) { frames -= i; // cannot fill request. break; } // format convert to destination buffer convertNoResampler(dst, buffer.raw, buffer.frameCount); dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize; i -= buffer.frameCount; provider->releaseBuffer(&buffer); } } else { ALOGV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x", mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat); // reallocate buffer if needed if (mBufFrameSize != 0 && mBufFrames < frames) { free(mBuf); mBufFrames = frames; (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); } // resampler accumulates, but we only have one source track memset(mBuf, 0, frames * mBufFrameSize); frames = mResampler->resample((int32_t*)mBuf, frames, provider); // format convert to destination buffer convertResampler(dst, mBuf, frames); } return frames; } status_t RecordBufferConverter::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) { // quick evaluation if there is any change. if (mSrcFormat == srcFormat && mSrcChannelMask == srcChannelMask && mSrcSampleRate == srcSampleRate && mDstFormat == dstFormat && mDstChannelMask == dstChannelMask && mDstSampleRate == dstSampleRate) { return NO_ERROR; } ALOGV("RecordBufferConverter updateParameters srcMask:%#x dstMask:%#x" " srcFormat:%#x dstFormat:%#x srcRate:%u dstRate:%u", srcChannelMask, dstChannelMask, srcFormat, dstFormat, srcSampleRate, dstSampleRate); const bool valid = audio_is_input_channel(srcChannelMask) && audio_is_input_channel(dstChannelMask) && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat) && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat) && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) ; // no upsampling checks for now if (!valid) { return BAD_VALUE; } mSrcFormat = srcFormat; mSrcChannelMask = srcChannelMask; mSrcSampleRate = srcSampleRate; mDstFormat = dstFormat; mDstChannelMask = dstChannelMask; mDstSampleRate = dstSampleRate; // compute derived parameters mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask); mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask); mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat); // do we need to resample? delete mResampler; mResampler = NULL; if (mSrcSampleRate != mDstSampleRate) { mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT, mSrcChannelCount, mDstSampleRate); mResampler->setSampleRate(mSrcSampleRate); mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT); } // are we running legacy channel conversion modes? mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK) && mDstChannelMask == AUDIO_CHANNEL_IN_MONO; mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK); // do we need to process in float? mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix; // do we need a staging buffer to convert for destination (we can still optimize this)? // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity if (mResampler != NULL) { mBufFrameSize = max(mSrcChannelCount, (uint32_t)FCC_2) * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT); } else if (mIsLegacyUpmix || mIsLegacyDownmix) { // legacy modes always float mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT); } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) { mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat); } else { mBufFrameSize = 0; } mBufFrames = 0; // force the buffer to be resized. // do we need an input converter buffer provider to give us float? delete mInputConverterProvider; mInputConverterProvider = NULL; if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) { mInputConverterProvider = new ReformatBufferProvider( audio_channel_count_from_in_mask(mSrcChannelMask), mSrcFormat, AUDIO_FORMAT_PCM_FLOAT, 256 /* provider buffer frame count */); } // do we need a remixer to do channel mask conversion if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) { (void) memcpy_by_index_array_initialization_from_channel_mask( mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask); } return NO_ERROR; } void RecordBufferConverter::convertNoResampler( void *dst, const void *src, size_t frames) { // src is native type unless there is legacy upmix or downmix, whereupon it is float. if (mBufFrameSize != 0 && mBufFrames < frames) { free(mBuf); mBufFrames = frames; (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); } // do we need to do legacy upmix and downmix? if (mIsLegacyUpmix || mIsLegacyDownmix) { void *dstBuf = mBuf != NULL ? mBuf : dst; if (mIsLegacyUpmix) { upmix_to_stereo_float_from_mono_float((float *)dstBuf, (const float *)src, frames); } else /*mIsLegacyDownmix */ { downmix_to_mono_float_from_stereo_float((float *)dstBuf, (const float *)src, frames); } if (mBuf != NULL) { memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT, frames * mDstChannelCount); } return; } // do we need to do channel mask conversion? if (mSrcChannelMask != mDstChannelMask) { void *dstBuf = mBuf != NULL ? mBuf : dst; memcpy_by_index_array(dstBuf, mDstChannelCount, src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames); if (dstBuf == dst) { return; // format is the same } } // convert to destination buffer const void *convertBuf = mBuf != NULL ? mBuf : src; memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat, frames * mDstChannelCount); } void RecordBufferConverter::convertResampler( void *dst, /*not-a-const*/ void *src, size_t frames) { // src buffer format is ALWAYS float when entering this routine if (mIsLegacyUpmix) { ; // mono to stereo already handled by resampler } else if (mIsLegacyDownmix || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) { // the resampler outputs stereo for mono input channel (a feature?) // must convert to mono downmix_to_mono_float_from_stereo_float((float *)src, (const float *)src, frames); } else if (mSrcChannelMask != mDstChannelMask) { // convert to mono channel again for channel mask conversion (could be skipped // with further optimization). if (mSrcChannelCount == 1) { downmix_to_mono_float_from_stereo_float((float *)src, (const float *)src, frames); } // convert to destination format (in place, OK as float is larger than other types) if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) { memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT, frames * mSrcChannelCount); } // channel convert and save to dst memcpy_by_index_array(dst, mDstChannelCount, src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames); return; } // convert to destination format and save to dst memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT, frames * mDstChannelCount); } // ---------------------------------------------------------------------------- } // namespace android services/audioflinger/AudioFlinger.h +1 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ class DevicesFactoryHalInterface; class EffectsFactoryHalInterface; class FastMixer; class PassthruBufferProvider; class RecordBufferConverter; class ServerProxy; // ---------------------------------------------------------------------------- Loading Loading
include/media/BufferProviders.h +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <sys/types.h> #include <media/AudioBufferProvider.h> #include <media/AudioResamplerPublic.h> #include <system/audio.h> #include <system/audio_effect.h> #include <utils/StrongPointer.h> Loading
include/media/RecordBufferConverter.h 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_RECORD_BUFFER_CONVERTER_H #define ANDROID_RECORD_BUFFER_CONVERTER_H #include <stdint.h> #include <sys/types.h> #include <media/AudioBufferProvider.h> #include <system/audio.h> class AudioResampler; class PassthruBufferProvider; namespace android { /* The RecordBufferConverter is used for format, channel, and sample rate * conversion for a RecordTrack. * * RecordBufferConverter uses the convert() method rather than exposing a * buffer provider interface; this is to save a memory copy. * * There are legacy conversion requirements for this converter, specifically * due to mono handling, so be careful about modifying. * * Original source audioflinger/Threads.{h,cpp} */ class RecordBufferConverter { public: 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); ~RecordBufferConverter(); /* Converts input data from an AudioBufferProvider by format, channelMask, * and sampleRate to a destination buffer. * * Parameters * dst: buffer to place the converted data. * provider: buffer provider to obtain source data. * frames: number of frames to convert * * Returns the number of frames converted. */ size_t convert(void *dst, AudioBufferProvider *provider, size_t frames); // returns NO_ERROR if constructor was successful status_t initCheck() const { // mSrcChannelMask set on successful updateParameters return mSrcChannelMask != AUDIO_CHANNEL_INVALID ? NO_ERROR : NO_INIT; } // allows dynamic reconfigure of all parameters status_t 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); // called to reset resampler buffers on record track discontinuity void reset(); private: // format conversion when not using resampler void convertNoResampler(void *dst, const void *src, size_t frames); // format conversion when using resampler; modifies src in-place void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames); // user provided information audio_channel_mask_t mSrcChannelMask; audio_format_t mSrcFormat; uint32_t mSrcSampleRate; audio_channel_mask_t mDstChannelMask; audio_format_t mDstFormat; uint32_t mDstSampleRate; // derived information uint32_t mSrcChannelCount; uint32_t mDstChannelCount; size_t mDstFrameSize; // format conversion buffer void *mBuf; size_t mBufFrames; size_t mBufFrameSize; // resampler info AudioResampler *mResampler; bool mIsLegacyDownmix; // legacy stereo to mono conversion needed bool mIsLegacyUpmix; // legacy mono to stereo conversion needed bool mRequiresFloat; // data processing requires float (e.g. resampler) PassthruBufferProvider *mInputConverterProvider; // converts input to float int8_t mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion }; // ---------------------------------------------------------------------------- } // namespace android #endif // ANDROID_RECORD_BUFFER_CONVERTER_H
media/libaudioprocessing/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ LOCAL_SRC_FILES := \ AudioResamplerSinc.cpp.arm \ AudioResamplerDyn.cpp.arm \ BufferProviders.cpp \ RecordBufferConverter.cpp \ LOCAL_C_INCLUDES := \ $(TOP) \ Loading
media/libaudioprocessing/RecordBufferConverter.cpp 0 → 100644 +294 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "RecordBufferConverter" //#define LOG_NDEBUG 0 #include <audio_utils/primitives.h> #include <audio_utils/format.h> #include <media/AudioMixer.h> // for UNITY_GAIN_FLOAT #include <media/AudioResampler.h> #include <media/BufferProviders.h> #include <media/RecordBufferConverter.h> #include <utils/Log.h> #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) #endif template <typename T> static inline T max(const T& a, const T& b) { return a > b ? a : b; } namespace android { RecordBufferConverter::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) : mSrcChannelMask(AUDIO_CHANNEL_INVALID), // updateParameters will set following vars // mSrcFormat // mSrcSampleRate // mDstChannelMask // mDstFormat // mDstSampleRate // mSrcChannelCount // mDstChannelCount // mDstFrameSize mBuf(NULL), mBufFrames(0), mBufFrameSize(0), mResampler(NULL), mIsLegacyDownmix(false), mIsLegacyUpmix(false), mRequiresFloat(false), mInputConverterProvider(NULL) { (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate, dstChannelMask, dstFormat, dstSampleRate); } RecordBufferConverter::~RecordBufferConverter() { free(mBuf); delete mResampler; delete mInputConverterProvider; } void RecordBufferConverter::reset() { if (mResampler != NULL) { mResampler->reset(); } } size_t RecordBufferConverter::convert(void *dst, AudioBufferProvider *provider, size_t frames) { if (mInputConverterProvider != NULL) { mInputConverterProvider->setBufferProvider(provider); provider = mInputConverterProvider; } if (mResampler == NULL) { ALOGV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x", mSrcSampleRate, mSrcFormat, mDstFormat); AudioBufferProvider::Buffer buffer; for (size_t i = frames; i > 0; ) { buffer.frameCount = i; status_t status = provider->getNextBuffer(&buffer); if (status != OK || buffer.frameCount == 0) { frames -= i; // cannot fill request. break; } // format convert to destination buffer convertNoResampler(dst, buffer.raw, buffer.frameCount); dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize; i -= buffer.frameCount; provider->releaseBuffer(&buffer); } } else { ALOGV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x", mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat); // reallocate buffer if needed if (mBufFrameSize != 0 && mBufFrames < frames) { free(mBuf); mBufFrames = frames; (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); } // resampler accumulates, but we only have one source track memset(mBuf, 0, frames * mBufFrameSize); frames = mResampler->resample((int32_t*)mBuf, frames, provider); // format convert to destination buffer convertResampler(dst, mBuf, frames); } return frames; } status_t RecordBufferConverter::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) { // quick evaluation if there is any change. if (mSrcFormat == srcFormat && mSrcChannelMask == srcChannelMask && mSrcSampleRate == srcSampleRate && mDstFormat == dstFormat && mDstChannelMask == dstChannelMask && mDstSampleRate == dstSampleRate) { return NO_ERROR; } ALOGV("RecordBufferConverter updateParameters srcMask:%#x dstMask:%#x" " srcFormat:%#x dstFormat:%#x srcRate:%u dstRate:%u", srcChannelMask, dstChannelMask, srcFormat, dstFormat, srcSampleRate, dstSampleRate); const bool valid = audio_is_input_channel(srcChannelMask) && audio_is_input_channel(dstChannelMask) && audio_is_valid_format(srcFormat) && audio_is_linear_pcm(srcFormat) && audio_is_valid_format(dstFormat) && audio_is_linear_pcm(dstFormat) && (srcSampleRate <= dstSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) ; // no upsampling checks for now if (!valid) { return BAD_VALUE; } mSrcFormat = srcFormat; mSrcChannelMask = srcChannelMask; mSrcSampleRate = srcSampleRate; mDstFormat = dstFormat; mDstChannelMask = dstChannelMask; mDstSampleRate = dstSampleRate; // compute derived parameters mSrcChannelCount = audio_channel_count_from_in_mask(srcChannelMask); mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask); mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat); // do we need to resample? delete mResampler; mResampler = NULL; if (mSrcSampleRate != mDstSampleRate) { mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT, mSrcChannelCount, mDstSampleRate); mResampler->setSampleRate(mSrcSampleRate); mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT); } // are we running legacy channel conversion modes? mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK) && mDstChannelMask == AUDIO_CHANNEL_IN_MONO; mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK); // do we need to process in float? mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix; // do we need a staging buffer to convert for destination (we can still optimize this)? // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity if (mResampler != NULL) { mBufFrameSize = max(mSrcChannelCount, (uint32_t)FCC_2) * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT); } else if (mIsLegacyUpmix || mIsLegacyDownmix) { // legacy modes always float mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT); } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) { mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat); } else { mBufFrameSize = 0; } mBufFrames = 0; // force the buffer to be resized. // do we need an input converter buffer provider to give us float? delete mInputConverterProvider; mInputConverterProvider = NULL; if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) { mInputConverterProvider = new ReformatBufferProvider( audio_channel_count_from_in_mask(mSrcChannelMask), mSrcFormat, AUDIO_FORMAT_PCM_FLOAT, 256 /* provider buffer frame count */); } // do we need a remixer to do channel mask conversion if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) { (void) memcpy_by_index_array_initialization_from_channel_mask( mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask); } return NO_ERROR; } void RecordBufferConverter::convertNoResampler( void *dst, const void *src, size_t frames) { // src is native type unless there is legacy upmix or downmix, whereupon it is float. if (mBufFrameSize != 0 && mBufFrames < frames) { free(mBuf); mBufFrames = frames; (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize); } // do we need to do legacy upmix and downmix? if (mIsLegacyUpmix || mIsLegacyDownmix) { void *dstBuf = mBuf != NULL ? mBuf : dst; if (mIsLegacyUpmix) { upmix_to_stereo_float_from_mono_float((float *)dstBuf, (const float *)src, frames); } else /*mIsLegacyDownmix */ { downmix_to_mono_float_from_stereo_float((float *)dstBuf, (const float *)src, frames); } if (mBuf != NULL) { memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT, frames * mDstChannelCount); } return; } // do we need to do channel mask conversion? if (mSrcChannelMask != mDstChannelMask) { void *dstBuf = mBuf != NULL ? mBuf : dst; memcpy_by_index_array(dstBuf, mDstChannelCount, src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames); if (dstBuf == dst) { return; // format is the same } } // convert to destination buffer const void *convertBuf = mBuf != NULL ? mBuf : src; memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat, frames * mDstChannelCount); } void RecordBufferConverter::convertResampler( void *dst, /*not-a-const*/ void *src, size_t frames) { // src buffer format is ALWAYS float when entering this routine if (mIsLegacyUpmix) { ; // mono to stereo already handled by resampler } else if (mIsLegacyDownmix || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) { // the resampler outputs stereo for mono input channel (a feature?) // must convert to mono downmix_to_mono_float_from_stereo_float((float *)src, (const float *)src, frames); } else if (mSrcChannelMask != mDstChannelMask) { // convert to mono channel again for channel mask conversion (could be skipped // with further optimization). if (mSrcChannelCount == 1) { downmix_to_mono_float_from_stereo_float((float *)src, (const float *)src, frames); } // convert to destination format (in place, OK as float is larger than other types) if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) { memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT, frames * mSrcChannelCount); } // channel convert and save to dst memcpy_by_index_array(dst, mDstChannelCount, src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames); return; } // convert to destination format and save to dst memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT, frames * mDstChannelCount); } // ---------------------------------------------------------------------------- } // namespace android
services/audioflinger/AudioFlinger.h +1 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ class DevicesFactoryHalInterface; class EffectsFactoryHalInterface; class FastMixer; class PassthruBufferProvider; class RecordBufferConverter; class ServerProxy; // ---------------------------------------------------------------------------- Loading