/* ** Copyright 2011, 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_NDEBUG 0 #define LOG_TAG "ReSampler" #include #include "ReSampler.h" namespace android_audio_legacy { //------------------------------------------------------------------------------ // speex based resampler //------------------------------------------------------------------------------ #define RESAMPLER_QUALITY 2 ReSampler::ReSampler(uint32_t inSampleRate, uint32_t outSampleRate, uint32_t channelCount, BufferProvider* provider) : mStatus(NO_INIT), mSpeexResampler(NULL), mProvider(provider), mInSampleRate(inSampleRate), mOutSampleRate(outSampleRate), mChannelCount(channelCount), mInBuf(NULL), mInBufSize(0) { LOGV("ReSampler() cstor %p In SR %d Out SR %d channels %d", this, mInSampleRate, mOutSampleRate, mChannelCount); if (mProvider == NULL) { return; } int error; mSpeexResampler = speex_resampler_init(channelCount, inSampleRate, outSampleRate, RESAMPLER_QUALITY, &error); if (mSpeexResampler == NULL) { LOGW("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error)); return; } reset(); int frames = speex_resampler_get_input_latency(mSpeexResampler); mSpeexDelayNs = (int32_t)((1000000000 * (int64_t)frames) / mInSampleRate); frames = speex_resampler_get_output_latency(mSpeexResampler); mSpeexDelayNs += (int32_t)((1000000000 * (int64_t)frames) / mOutSampleRate); mStatus = NO_ERROR; } ReSampler::~ReSampler() { free(mInBuf); if (mSpeexResampler != NULL) { speex_resampler_destroy(mSpeexResampler); } } void ReSampler::reset() { mFramesIn = 0; mFramesRq = 0; if (mSpeexResampler != NULL) { speex_resampler_reset_mem(mSpeexResampler); } } int32_t ReSampler::delayNs() { int32_t delay = (int32_t)((1000000000 * (int64_t)mFramesIn) / mInSampleRate); delay += mSpeexDelayNs; return delay; } // outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount // with the actual number of frames produced. int ReSampler::resample(int16_t *out, size_t *outFrameCount) { if (mStatus != NO_ERROR) { return mStatus; } if (out == NULL || outFrameCount == NULL) { return BAD_VALUE; } size_t framesRq = *outFrameCount; // update and cache the number of frames needed at the input sampling rate to produce // the number of frames requested at the output sampling rate if (framesRq != mFramesRq) { mFramesNeeded = (framesRq * mOutSampleRate) / mInSampleRate + 1; mFramesRq = framesRq; } size_t framesWr = 0; size_t inFrames = 0; while (framesWr < framesRq) { if (mFramesIn < mFramesNeeded) { // make sure that the number of frames present in mInBuf (mFramesIn) is at least // the number of frames needed to produce the number of frames requested at // the output sampling rate if (mInBufSize < mFramesNeeded) { mInBufSize = mFramesNeeded; mInBuf = (int16_t *)realloc(mInBuf, mInBufSize * mChannelCount * sizeof(int16_t)); } BufferProvider::Buffer buf; buf.frameCount = mFramesNeeded - mFramesIn; mProvider->getNextBuffer(&buf); if (buf.raw == NULL) { break; } memcpy(mInBuf + mFramesIn * mChannelCount, buf.raw, buf.frameCount * mChannelCount * sizeof(int16_t)); mFramesIn += buf.frameCount; mProvider->releaseBuffer(&buf); } size_t outFrames = framesRq - framesWr; inFrames = mFramesIn; if (mChannelCount == 1) { speex_resampler_process_int(mSpeexResampler, 0, mInBuf, &inFrames, out + framesWr * mChannelCount, &outFrames); } else { speex_resampler_process_interleaved_int(mSpeexResampler, mInBuf, &inFrames, out + framesWr * mChannelCount, &outFrames); } framesWr += outFrames; mFramesIn -= inFrames; LOGW_IF((framesWr != framesRq) && (mFramesIn != 0), "ReSampler::resample() remaining %d frames in and %d frames out", mFramesIn, (framesRq - framesWr)); } if (mFramesIn) { memmove(mInBuf, mInBuf + inFrames * mChannelCount, mFramesIn * mChannelCount * sizeof(int16_t)); } *outFrameCount = framesWr; return NO_ERROR; } }; // namespace android_audio_legacy