Converted libaudioutils implementation to C.
Converted libaudioutils implementation and interfaces from C++ to C
and removed dependencies from frameworks/base classes so that it can
be used by any audio HAL implementation.
Change-Id: I3f7ce541be8495d41864661451540971b067359b
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 599de4a..2422a69 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -50,6 +50,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/filterpack_text_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/filterpack_ui_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/filterpack_videosrc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudioutils_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/audio_utils/Android.mk b/audio_utils/Android.mk
index 43ba0d7..8cdde41 100644
--- a/audio_utils/Android.mk
+++ b/audio_utils/Android.mk
@@ -6,8 +6,8 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
- ReSampler.cpp \
- EchoReference.cpp
+ resampler.c \
+ echo_reference.c
LOCAL_C_INCLUDES += $(call include-path-for, speex)
LOCAL_C_INCLUDES += \
@@ -15,7 +15,7 @@
system/media/audio_utils/include
LOCAL_SHARED_LIBRARIES := \
- libutils \
- libspeexresampler
+ libcutils \
+ libspeexresampler
include $(BUILD_SHARED_LIBRARY)
diff --git a/audio_utils/EchoReference.cpp b/audio_utils/EchoReference.cpp
deleted file mode 100644
index a17a17b..0000000
--- a/audio_utils/EchoReference.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
-** 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 "EchoReference"
-
-#include <utils/Log.h>
-#include <audio_utils/EchoReference.h>
-
-namespace android_audio_legacy {
-
-//------------------------------------------------------------------------------
-// Echo reference buffer
-//------------------------------------------------------------------------------
-
-EchoReference::EchoReference(audio_format_t rdFormat,
- uint32_t rdChannelCount,
- uint32_t rdSamplingRate,
- audio_format_t wrFormat,
- uint32_t wrChannelCount,
- uint32_t wrSamplingRate)
-: mStatus (NO_INIT), mState(ECHOREF_IDLE),
- mRdFormat(rdFormat), mRdChannelCount(rdChannelCount), mRdSamplingRate(rdSamplingRate),
- mWrFormat(wrFormat), mWrChannelCount(wrChannelCount), mWrSamplingRate(wrSamplingRate),
- mBuffer(NULL), mBufSize(0), mFramesIn(0), mWrBuf(NULL), mWrBufSize(0), mWrFramesIn(0),
- mDownSampler(NULL)
-{
- LOGV("EchoReference cstor");
- if (rdFormat != AUDIO_FORMAT_PCM_16_BIT ||
- rdFormat != wrFormat) {
- LOGW("EchoReference cstor bad format rd %d, wr %d", rdFormat, wrFormat);
- mStatus = BAD_VALUE;
- return;
- }
- if ((rdChannelCount != 1 && rdChannelCount != 2) ||
- wrChannelCount != 2) {
- LOGW("EchoReference cstor bad channel count rd %d, wr %d", rdChannelCount, wrChannelCount);
- mStatus = BAD_VALUE;
- return;
- }
-
- if (wrSamplingRate < rdSamplingRate) {
- LOGW("EchoReference cstor bad smp rate rd %d, wr %d", rdSamplingRate, wrSamplingRate);
- mStatus = BAD_VALUE;
- return;
- }
-
- mRdFrameSize = audio_bytes_per_sample(rdFormat) * rdChannelCount;
- mWrFrameSize = audio_bytes_per_sample(wrFormat) * wrChannelCount;
- mStatus = NO_ERROR;
-}
-
-
-EchoReference::~EchoReference() {
- LOGV("EchoReference dstor");
- reset_l();
- delete mDownSampler;
-}
-
-status_t EchoReference::write(Buffer *buffer)
-{
- if (mStatus != NO_ERROR) {
- LOGV("EchoReference::write() ERROR, exiting early");
- return mStatus;
- }
-
- AutoMutex _l(mLock);
-
- if (buffer == NULL) {
- LOGV("EchoReference::write() stop write");
- mState &= ~ECHOREF_WRITING;
- reset_l();
- return NO_ERROR;
- }
-
- LOGV("EchoReference::write() START trying to write %d frames", buffer->frameCount);
- LOGV("EchoReference::write() playbackTimestamp:[%lld].[%lld], mPlaybackDelay:[%ld]",
- (int64_t)buffer->timeStamp.tv_sec,
- (int64_t)buffer->timeStamp.tv_nsec, mPlaybackDelay);
-
- //LOGV("EchoReference::write() %d frames", buffer->frameCount);
- // discard writes until a valid time stamp is provided.
-
- if ((buffer->timeStamp.tv_sec == 0) && (buffer->timeStamp.tv_nsec == 0) &&
- (mWrRenderTime.tv_sec == 0) && (mWrRenderTime.tv_nsec == 0)) {
- return NO_ERROR;
- }
-
- if ((mState & ECHOREF_WRITING) == 0) {
- LOGV("EchoReference::write() start write");
- if (mDownSampler != NULL) {
- mDownSampler->reset();
- }
- mState |= ECHOREF_WRITING;
- }
-
- if ((mState & ECHOREF_READING) == 0) {
- return NO_ERROR;
- }
-
- mWrRenderTime.tv_sec = buffer->timeStamp.tv_sec;
- mWrRenderTime.tv_nsec = buffer->timeStamp.tv_nsec;
-
- mPlaybackDelay = buffer->delayNs;
-
- void *srcBuf;
- size_t inFrames;
- // do stereo to mono and down sampling if necessary
- if (mRdChannelCount != mWrChannelCount ||
- mRdSamplingRate != mWrSamplingRate) {
- if (mWrBufSize < buffer->frameCount) {
- mWrBufSize = buffer->frameCount;
- //max buffer size is normally function of read sampling rate but as write sampling rate
- //is always more than read sampling rate this works
- mWrBuf = realloc(mWrBuf, mWrBufSize * mRdFrameSize);
- }
-
- inFrames = buffer->frameCount;
- if (mRdChannelCount != mWrChannelCount) {
- // must be stereo to mono
- int16_t *src16 = (int16_t *)buffer->raw;
- int16_t *dst16 = (int16_t *)mWrBuf;
- size_t frames = buffer->frameCount;
- while (frames--) {
- *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
- src16 += 2;
- }
- }
- if (mWrSamplingRate != mRdSamplingRate) {
- if (mDownSampler == NULL) {
- LOGV("EchoReference::write() new ReSampler(%d, %d)",
- mWrSamplingRate, mRdSamplingRate);
- mDownSampler = new ReSampler(mWrSamplingRate,
- mRdSamplingRate,
- mRdChannelCount,
- this);
-
- }
- // mWrSrcBuf and mWrFramesIn are used by getNexBuffer() called by the resampler
- // to get new frames
- if (mRdChannelCount != mWrChannelCount) {
- mWrSrcBuf = mWrBuf;
- } else {
- mWrSrcBuf = buffer->raw;
- }
- mWrFramesIn = buffer->frameCount;
- // inFrames is always more than we need here to get frames remaining from previous runs
- // inFrames is updated by resample() with the number of frames produced
- LOGV("EchoReference::write() ReSampling(%d, %d)",
- mWrSamplingRate, mRdSamplingRate);
- mDownSampler->resample((int16_t *)mWrBuf, &inFrames);
- LOGV_IF(mWrFramesIn != 0,
- "EchoReference::write() mWrFramesIn not 0 (%d) after resampler",
- mWrFramesIn);
- }
- srcBuf = mWrBuf;
- } else {
- inFrames = buffer->frameCount;
- srcBuf = buffer->raw;
- }
-
- if (mFramesIn + inFrames > mBufSize) {
- LOGV("EchoReference::write() increasing buffer size from %d to %d",
- mBufSize, mFramesIn + inFrames);
- mBufSize = mFramesIn + inFrames;
- mBuffer = realloc(mBuffer, mBufSize * mRdFrameSize);
- }
- memcpy((char *)mBuffer + mFramesIn * mRdFrameSize,
- srcBuf,
- inFrames * mRdFrameSize);
- mFramesIn += inFrames;
-
- LOGV("EchoReference::write_log() inFrames:[%d], mFramesInOld:[%d], "\
- "mFramesInNew:[%d], mBufSize:[%d], mWrRenderTime:[%lld].[%lld], mPlaybackDelay:[%ld]",
- inFrames, mFramesIn - inFrames, mFramesIn, mBufSize, (int64_t)mWrRenderTime.tv_sec,
- (int64_t)mWrRenderTime.tv_nsec, mPlaybackDelay);
-
- mCond.signal();
- LOGV("EchoReference::write() END");
- return NO_ERROR;
-}
-
-status_t EchoReference::read(EchoReference::Buffer *buffer)
-{
- if (mStatus != NO_ERROR) {
- return mStatus;
- }
- AutoMutex _l(mLock);
-
- if (buffer == NULL) {
- LOGV("EchoReference::read() stop read");
- mState &= ~ECHOREF_READING;
- return NO_ERROR;
- }
-
- LOGV("EchoReference::read() START, delayCapture:[%ld],mFramesIn:[%d],buffer->frameCount:[%d]",
- buffer->delayNs, mFramesIn, buffer->frameCount);
-
- if ((mState & ECHOREF_READING) == 0) {
- LOGV("EchoReference::read() start read");
- reset_l();
- mState |= ECHOREF_READING;
- }
-
- if ((mState & ECHOREF_WRITING) == 0) {
- memset(buffer->raw, 0, mRdFrameSize * buffer->frameCount);
- buffer->delayNs = 0;
- return NO_ERROR;
- }
-
-// LOGV("EchoReference::read() %d frames", buffer->frameCount);
-
- // allow some time for new frames to arrive if not enough frames are ready for read
- if (mFramesIn < buffer->frameCount) {
- uint32_t timeoutMs = (uint32_t)((1000 * buffer->frameCount) / mRdSamplingRate / 2);
-
- mCond.waitRelative(mLock, milliseconds(timeoutMs));
- if (mFramesIn < buffer->frameCount) {
- LOGV("EchoReference::read() waited %d ms but still not enough frames"\
- " mFramesIn: %d, buffer->frameCount = %d",
- timeoutMs, mFramesIn, buffer->frameCount);
- buffer->frameCount = mFramesIn;
- }
- }
-
- int64_t timeDiff;
- struct timespec tmp;
-
- if ((mWrRenderTime.tv_sec == 0 && mWrRenderTime.tv_nsec == 0) ||
- (buffer->timeStamp.tv_sec == 0 && buffer->timeStamp.tv_nsec == 0)) {
- LOGV("read: NEW:timestamp is zero---------setting timeDiff = 0, "\
- "not updating delay this time");
- timeDiff = 0;
- } else {
- if (buffer->timeStamp.tv_nsec < mWrRenderTime.tv_nsec) {
- tmp.tv_sec = buffer->timeStamp.tv_sec - mWrRenderTime.tv_sec - 1;
- tmp.tv_nsec = 1000000000 + buffer->timeStamp.tv_nsec - mWrRenderTime.tv_nsec;
- } else {
- tmp.tv_sec = buffer->timeStamp.tv_sec - mWrRenderTime.tv_sec;
- tmp.tv_nsec = buffer->timeStamp.tv_nsec - mWrRenderTime.tv_nsec;
- }
- timeDiff = (((int64_t)tmp.tv_sec * 1000000000 + tmp.tv_nsec));
-
- int64_t expectedDelayNs = mPlaybackDelay + buffer->delayNs - timeDiff;
-
- LOGV("expectedDelayNs[%lld] = mPlaybackDelay[%ld] + delayCapture[%ld] - timeDiff[%lld]",
- expectedDelayNs, mPlaybackDelay, buffer->delayNs, timeDiff);
-
- if (expectedDelayNs > 0) {
- int64_t delayNs = ((int64_t)mFramesIn * 1000000000) / mRdSamplingRate;
-
- delayNs -= expectedDelayNs;
-
- if (abs(delayNs) >= sMinDelayUpdate) {
- if (delayNs < 0) {
- size_t previousFrameIn = mFramesIn;
- mFramesIn = (expectedDelayNs * mRdSamplingRate)/1000000000;
- int offset = mFramesIn - previousFrameIn;
- LOGV("EchoReference::readlog: delayNs = NEGATIVE and ENOUGH : "\
- "setting %d frames to zero mFramesIn: %d, previousFrameIn = %d",
- offset, mFramesIn, previousFrameIn);
-
- if (mFramesIn > mBufSize) {
- mBufSize = mFramesIn;
- mBuffer = realloc(mBuffer, mFramesIn * mRdFrameSize);
- LOGV("EchoReference::read: increasing buffer size to %d", mBufSize);
- }
-
- if (offset > 0)
- memset((char *)mBuffer + previousFrameIn * mRdFrameSize,
- 0, offset * mRdFrameSize);
- } else {
- size_t previousFrameIn = mFramesIn;
- int framesInInt = (int)(((int64_t)expectedDelayNs *
- (int64_t)mRdSamplingRate)/1000000000);
- int offset = previousFrameIn - framesInInt;
-
- LOGV("EchoReference::readlog: delayNs = POSITIVE/ENOUGH :previousFrameIn: %d,"\
- "framesInInt: [%d], offset:[%d], buffer->frameCount:[%d]",
- previousFrameIn, framesInInt, offset, buffer->frameCount);
-
- if (framesInInt < (int)buffer->frameCount) {
- if (framesInInt > 0) {
- memset((char *)mBuffer + framesInInt * mRdFrameSize,
- 0, (buffer->frameCount-framesInInt) * mRdFrameSize);
- LOGV("EchoReference::read: pushing [%d] zeros into ref buffer",
- (buffer->frameCount-framesInInt));
- } else {
- LOGV("framesInInt = %d", framesInInt);
- }
- framesInInt = buffer->frameCount;
- } else {
- if (offset > 0) {
- memcpy(mBuffer, (char *)mBuffer + (offset * mRdFrameSize),
- framesInInt * mRdFrameSize);
- LOGV("EchoReference::read: shifting ref buffer by [%d]",framesInInt);
- }
- }
- mFramesIn = (size_t)framesInInt;
- }
- } else {
- LOGV("EchoReference::read: NOT ENOUGH samples to update %lld", delayNs);
- }
- } else {
- LOGV("NEGATIVE expectedDelayNs[%lld] = "\
- "mPlaybackDelay[%ld] + delayCapture[%ld] - timeDiff[%lld]",
- expectedDelayNs, mPlaybackDelay, buffer->delayNs, timeDiff);
- }
- }
-
- memcpy(buffer->raw,
- (char *)mBuffer,
- buffer->frameCount * mRdFrameSize);
-
- mFramesIn -= buffer->frameCount;
- memcpy(mBuffer,
- (char *)mBuffer + buffer->frameCount * mRdFrameSize,
- mFramesIn * mRdFrameSize);
-
- // As the reference buffer is now time aligned to the microphone signal there is a zero delay
- buffer->delayNs = 0;
-
- LOGV("EchoReference::read() END %d frames, total frames in %d",
- buffer->frameCount, mFramesIn);
-
- mCond.signal();
- return NO_ERROR;
-}
-
-void EchoReference::reset_l() {
- LOGV("EchoReference::reset_l()");
- free(mBuffer);
- mBuffer = NULL;
- mBufSize = 0;
- mFramesIn = 0;
- free(mWrBuf);
- mWrBuf = NULL;
- mWrBufSize = 0;
- mWrRenderTime.tv_sec = 0;
- mWrRenderTime.tv_nsec = 0;
-}
-
-status_t EchoReference::getNextBuffer(ReSampler::BufferProvider::Buffer* buffer)
-{
- if (mWrSrcBuf == NULL || mWrFramesIn == 0) {
- buffer->raw = NULL;
- buffer->frameCount = 0;
- return NOT_ENOUGH_DATA;
- }
-
- buffer->frameCount = (buffer->frameCount > mWrFramesIn) ? mWrFramesIn : buffer->frameCount;
- // this is mRdChannelCount here as we resample after stereo to mono conversion if any
- buffer->i16 = (int16_t *)mWrSrcBuf + (mWrBufSize - mWrFramesIn) * mRdChannelCount;
-
- return 0;
-}
-
-void EchoReference::releaseBuffer(ReSampler::BufferProvider::Buffer* buffer)
-{
- mWrFramesIn -= buffer->frameCount;
-}
-
-}; // namespace android_audio_legacy
diff --git a/audio_utils/ReSampler.cpp b/audio_utils/ReSampler.cpp
deleted file mode 100644
index 854b7dc..0000000
--- a/audio_utils/ReSampler.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
-** 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 <utils/Log.h>
-#include <audio_utils/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
diff --git a/audio_utils/echo_reference.c b/audio_utils/echo_reference.c
new file mode 100644
index 0000000..3dda270
--- /dev/null
+++ b/audio_utils/echo_reference.c
@@ -0,0 +1,498 @@
+/*
+** 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 "echo_reference"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <cutils/log.h>
+#include <system/audio.h>
+#include <audio_utils/resampler.h>
+#include <audio_utils/echo_reference.h>
+
+// echo reference state: bit field indicating if read, write or both are active.
+enum state {
+ ECHOREF_IDLE = 0x00, // idle
+ ECHOREF_READING = 0x01, // reading is active
+ ECHOREF_WRITING = 0x02 // writing is active
+};
+
+struct echo_reference {
+ struct echo_reference_itfe itfe;
+ int status; // init status
+ uint32_t state; // active state: reading, writing or both
+ audio_format_t rd_format; // read sample format
+ uint32_t rd_channel_count; // read number of channels
+ uint32_t rd_sampling_rate; // read sampling rate in Hz
+ size_t rd_frame_size; // read frame size (bytes per sample)
+ audio_format_t wr_format; // write sample format
+ uint32_t wr_channel_count; // write number of channels
+ uint32_t wr_sampling_rate; // write sampling rate in Hz
+ size_t wr_frame_size; // write frame size (bytes per sample)
+ void *buffer; // main buffer
+ size_t buf_size; // main buffer size in frames
+ size_t frames_in; // number of frames in main buffer
+ void *wr_buf; // buffer for input conversions
+ size_t wr_buf_size; // size of conversion buffer in frames
+ size_t wr_frames_in; // number of frames in conversion buffer
+ void *wr_src_buf; // resampler input buf (either wr_buf or buffer used by write())
+ struct timespec wr_render_time; // latest render time indicated by write()
+ // default ALSA gettimeofday() format
+ int32_t playback_delay; // playback buffer delay indicated by last write()
+ pthread_mutex_t lock; // mutex protecting read/write concurrency
+ pthread_cond_t cond; // condition signaled when data is ready to read
+ struct resampler_itfe *down_sampler; // input resampler
+ struct resampler_buffer_provider provider; // resampler buffer provider
+};
+
+
+// container_of is used to retrieve the containing struct echo_reference of
+// a struct buffer_provider passed to echo_reference_get_next_buffer() or
+// echo_reference_release_buffer()
+// - ptr: pointer to the contained member
+// - type: type of the containing struct
+// - member: name of the member in the containing struct
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+int echo_reference_get_next_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer* buffer)
+{
+ struct echo_reference *er;
+
+ if (buffer_provider == NULL) {
+ return -EINVAL;
+ }
+
+ er = container_of(buffer_provider, struct echo_reference, provider);
+
+ if (er->wr_src_buf == NULL || er->wr_frames_in == 0) {
+ buffer->raw = NULL;
+ buffer->frame_count = 0;
+ return -ENODATA;
+ }
+
+ buffer->frame_count = (buffer->frame_count > er->wr_frames_in) ? er->wr_frames_in : buffer->frame_count;
+ // this is er->rd_channel_count here as we resample after stereo to mono conversion if any
+ buffer->i16 = (int16_t *)er->wr_src_buf + (er->wr_buf_size - er->wr_frames_in) * er->rd_channel_count;
+
+ return 0;
+}
+
+void echo_reference_release_buffer(struct resampler_buffer_provider *buffer_provider,
+ struct resampler_buffer* buffer)
+{
+ struct echo_reference *er;
+
+ if (buffer_provider == NULL) {
+ return;
+ }
+
+ er = container_of(buffer_provider, struct echo_reference, provider);
+
+ er->wr_frames_in -= buffer->frame_count;
+}
+
+static void echo_reference_reset_l(struct echo_reference *er)
+{
+ LOGV("echo_reference_reset_l()");
+ free(er->buffer);
+ er->buffer = NULL;
+ er->buf_size = 0;
+ er->frames_in = 0;
+ free(er->wr_buf);
+ er->wr_buf = NULL;
+ er->wr_buf_size = 0;
+ er->wr_render_time.tv_sec = 0;
+ er->wr_render_time.tv_nsec = 0;
+}
+
+static int echo_reference_write(struct echo_reference_itfe *echo_reference,
+ struct echo_reference_buffer *buffer)
+{
+ struct echo_reference *er = (struct echo_reference *)echo_reference;
+ int status = 0;
+
+ if (er == NULL) {
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&er->lock);
+
+ if (buffer == NULL) {
+ LOGV("echo_reference_write() stop write");
+ er->state &= ~ECHOREF_WRITING;
+ echo_reference_reset_l(er);
+ goto exit;
+ }
+
+ LOGV("echo_reference_write() START trying to write %d frames", buffer->frame_count);
+ LOGV("echo_reference_write() playbackTimestamp:[%d].[%d], er->playback_delay:[%d]",
+ (int)buffer->time_stamp.tv_sec,
+ (int)buffer->time_stamp.tv_nsec, er->playback_delay);
+
+ //LOGV("echo_reference_write() %d frames", buffer->frame_count);
+ // discard writes until a valid time stamp is provided.
+
+ if ((buffer->time_stamp.tv_sec == 0) && (buffer->time_stamp.tv_nsec == 0) &&
+ (er->wr_render_time.tv_sec == 0) && (er->wr_render_time.tv_nsec == 0)) {
+ goto exit;
+ }
+
+ if ((er->state & ECHOREF_WRITING) == 0) {
+ LOGV("echo_reference_write() start write");
+ if (er->down_sampler != NULL) {
+ er->down_sampler->reset(er->down_sampler);
+ }
+ er->state |= ECHOREF_WRITING;
+ }
+
+ if ((er->state & ECHOREF_READING) == 0) {
+ goto exit;
+ }
+
+ er->wr_render_time.tv_sec = buffer->time_stamp.tv_sec;
+ er->wr_render_time.tv_nsec = buffer->time_stamp.tv_nsec;
+
+ er->playback_delay = buffer->delay_ns;
+
+ void *srcBuf;
+ size_t inFrames;
+ // do stereo to mono and down sampling if necessary
+ if (er->rd_channel_count != er->wr_channel_count ||
+ er->rd_sampling_rate != er->wr_sampling_rate) {
+ if (er->wr_buf_size < buffer->frame_count) {
+ er->wr_buf_size = buffer->frame_count;
+ //max buffer size is normally function of read sampling rate but as write sampling rate
+ //is always more than read sampling rate this works
+ er->wr_buf = realloc(er->wr_buf, er->wr_buf_size * er->rd_frame_size);
+ }
+
+ inFrames = buffer->frame_count;
+ if (er->rd_channel_count != er->wr_channel_count) {
+ // must be stereo to mono
+ int16_t *src16 = (int16_t *)buffer->raw;
+ int16_t *dst16 = (int16_t *)er->wr_buf;
+ size_t frames = buffer->frame_count;
+ while (frames--) {
+ *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
+ src16 += 2;
+ }
+ }
+ if (er->wr_sampling_rate != er->rd_sampling_rate) {
+ if (er->down_sampler == NULL) {
+ int rc;
+ LOGV("echo_reference_write() new ReSampler(%d, %d)",
+ er->wr_sampling_rate, er->rd_sampling_rate);
+ er->provider.get_next_buffer = echo_reference_get_next_buffer;
+ er->provider.release_buffer = echo_reference_release_buffer;
+ rc = create_resampler(er->wr_sampling_rate,
+ er->rd_sampling_rate,
+ er->rd_channel_count,
+ RESAMPLER_QUALITY_VOIP,
+ &er->provider,
+ &er->down_sampler);
+ if (rc != 0) {
+ er->down_sampler = NULL;
+ LOGV("echo_reference_write() failure to create resampler %d", rc);
+ status = -ENODEV;
+ goto exit;
+ }
+ }
+ // er->wr_src_buf and er->wr_frames_in are used by getNexBuffer() called by the resampler
+ // to get new frames
+ if (er->rd_channel_count != er->wr_channel_count) {
+ er->wr_src_buf = er->wr_buf;
+ } else {
+ er->wr_src_buf = buffer->raw;
+ }
+ er->wr_frames_in = buffer->frame_count;
+ // inFrames is always more than we need here to get frames remaining from previous runs
+ // inFrames is updated by resample() with the number of frames produced
+ LOGV("echo_reference_write() ReSampling(%d, %d)",
+ er->wr_sampling_rate, er->rd_sampling_rate);
+ er->down_sampler->resample_from_provider(er->down_sampler,
+ (int16_t *)er->wr_buf, &inFrames);
+ LOGV_IF(er->wr_frames_in != 0,
+ "echo_reference_write() er->wr_frames_in not 0 (%d) after resampler",
+ er->wr_frames_in);
+ }
+ srcBuf = er->wr_buf;
+ } else {
+ inFrames = buffer->frame_count;
+ srcBuf = buffer->raw;
+ }
+
+ if (er->frames_in + inFrames > er->buf_size) {
+ LOGV("echo_reference_write() increasing buffer size from %d to %d",
+ er->buf_size, er->frames_in + inFrames);
+ er->buf_size = er->frames_in + inFrames;
+ er->buffer = realloc(er->buffer, er->buf_size * er->rd_frame_size);
+ }
+ memcpy((char *)er->buffer + er->frames_in * er->rd_frame_size,
+ srcBuf,
+ inFrames * er->rd_frame_size);
+ er->frames_in += inFrames;
+
+ LOGV("EchoReference::write_log() inFrames:[%d], mFramesInOld:[%d], "\
+ "mFramesInNew:[%d], er->buf_size:[%d], er->wr_render_time:[%d].[%d],"
+ "er->playback_delay:[%d]",
+ inFrames, er->frames_in - inFrames, er->frames_in, er->buf_size,
+ (int)er->wr_render_time.tv_sec,
+ (int)er->wr_render_time.tv_nsec, er->playback_delay);
+
+ pthread_cond_signal(&er->cond);
+exit:
+ pthread_mutex_unlock(&er->lock);
+ LOGV("echo_reference_write() END");
+ return status;
+}
+
+#define MIN_DELAY_UPDATE_NS 62500 // delay jump threshold to update ref buffer
+ // 0.5 samples at 8kHz in nsecs
+
+
+static int echo_reference_read(struct echo_reference_itfe *echo_reference,
+ struct echo_reference_buffer *buffer)
+{
+ struct echo_reference *er = (struct echo_reference *)echo_reference;
+
+ if (er == NULL) {
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&er->lock);
+
+ if (buffer == NULL) {
+ LOGV("EchoReference::read() stop read");
+ er->state &= ~ECHOREF_READING;
+ goto exit;
+ }
+
+ LOGV("EchoReference::read() START, delayCapture:[%d],er->frames_in:[%d],buffer->frame_count:[%d]",
+ buffer->delay_ns, er->frames_in, buffer->frame_count);
+
+ if ((er->state & ECHOREF_READING) == 0) {
+ LOGV("EchoReference::read() start read");
+ echo_reference_reset_l(er);
+ er->state |= ECHOREF_READING;
+ }
+
+ if ((er->state & ECHOREF_WRITING) == 0) {
+ memset(buffer->raw, 0, er->rd_frame_size * buffer->frame_count);
+ buffer->delay_ns = 0;
+ goto exit;
+ }
+
+// LOGV("EchoReference::read() %d frames", buffer->frame_count);
+
+ // allow some time for new frames to arrive if not enough frames are ready for read
+ if (er->frames_in < buffer->frame_count) {
+ uint32_t timeoutMs = (uint32_t)((1000 * buffer->frame_count) / er->rd_sampling_rate / 2);
+ struct timespec ts;
+
+ ts.tv_sec = timeoutMs/1000;
+ ts.tv_nsec = timeoutMs%1000;
+ pthread_cond_timedwait_relative_np(&er->cond, &er->lock, &ts);
+
+ if (er->frames_in < buffer->frame_count) {
+ LOGV("EchoReference::read() waited %d ms but still not enough frames"\
+ " er->frames_in: %d, buffer->frame_count = %d",
+ timeoutMs, er->frames_in, buffer->frame_count);
+ buffer->frame_count = er->frames_in;
+ }
+ }
+
+ int64_t timeDiff;
+ struct timespec tmp;
+
+ if ((er->wr_render_time.tv_sec == 0 && er->wr_render_time.tv_nsec == 0) ||
+ (buffer->time_stamp.tv_sec == 0 && buffer->time_stamp.tv_nsec == 0)) {
+ LOGV("read: NEW:timestamp is zero---------setting timeDiff = 0, "\
+ "not updating delay this time");
+ timeDiff = 0;
+ } else {
+ if (buffer->time_stamp.tv_nsec < er->wr_render_time.tv_nsec) {
+ tmp.tv_sec = buffer->time_stamp.tv_sec - er->wr_render_time.tv_sec - 1;
+ tmp.tv_nsec = 1000000000 + buffer->time_stamp.tv_nsec - er->wr_render_time.tv_nsec;
+ } else {
+ tmp.tv_sec = buffer->time_stamp.tv_sec - er->wr_render_time.tv_sec;
+ tmp.tv_nsec = buffer->time_stamp.tv_nsec - er->wr_render_time.tv_nsec;
+ }
+ timeDiff = (((int64_t)tmp.tv_sec * 1000000000 + tmp.tv_nsec));
+
+ int64_t expectedDelayNs = er->playback_delay + buffer->delay_ns - timeDiff;
+
+ LOGV("expectedDelayNs[%lld] = er->playback_delay[%d] + delayCapture[%d] - timeDiff[%lld]",
+ expectedDelayNs, er->playback_delay, buffer->delay_ns, timeDiff);
+
+ if (expectedDelayNs > 0) {
+ int64_t delayNs = ((int64_t)er->frames_in * 1000000000) / er->rd_sampling_rate;
+
+ delayNs -= expectedDelayNs;
+
+ if (abs(delayNs) >= MIN_DELAY_UPDATE_NS) {
+ if (delayNs < 0) {
+ size_t previousFrameIn = er->frames_in;
+ er->frames_in = (expectedDelayNs * er->rd_sampling_rate)/1000000000;
+ int offset = er->frames_in - previousFrameIn;
+ LOGV("EchoReference::readlog: delayNs = NEGATIVE and ENOUGH : "\
+ "setting %d frames to zero er->frames_in: %d, previousFrameIn = %d",
+ offset, er->frames_in, previousFrameIn);
+
+ if (er->frames_in > er->buf_size) {
+ er->buf_size = er->frames_in;
+ er->buffer = realloc(er->buffer, er->frames_in * er->rd_frame_size);
+ LOGV("EchoReference::read: increasing buffer size to %d", er->buf_size);
+ }
+
+ if (offset > 0)
+ memset((char *)er->buffer + previousFrameIn * er->rd_frame_size,
+ 0, offset * er->rd_frame_size);
+ } else {
+ size_t previousFrameIn = er->frames_in;
+ int framesInInt = (int)(((int64_t)expectedDelayNs *
+ (int64_t)er->rd_sampling_rate)/1000000000);
+ int offset = previousFrameIn - framesInInt;
+
+ LOGV("EchoReference::readlog: delayNs = POSITIVE/ENOUGH :previousFrameIn: %d,"\
+ "framesInInt: [%d], offset:[%d], buffer->frame_count:[%d]",
+ previousFrameIn, framesInInt, offset, buffer->frame_count);
+
+ if (framesInInt < (int)buffer->frame_count) {
+ if (framesInInt > 0) {
+ memset((char *)er->buffer + framesInInt * er->rd_frame_size,
+ 0, (buffer->frame_count-framesInInt) * er->rd_frame_size);
+ LOGV("EchoReference::read: pushing [%d] zeros into ref buffer",
+ (buffer->frame_count-framesInInt));
+ } else {
+ LOGV("framesInInt = %d", framesInInt);
+ }
+ framesInInt = buffer->frame_count;
+ } else {
+ if (offset > 0) {
+ memcpy(er->buffer, (char *)er->buffer + (offset * er->rd_frame_size),
+ framesInInt * er->rd_frame_size);
+ LOGV("EchoReference::read: shifting ref buffer by [%d]",framesInInt);
+ }
+ }
+ er->frames_in = (size_t)framesInInt;
+ }
+ } else {
+ LOGV("EchoReference::read: NOT ENOUGH samples to update %lld", delayNs);
+ }
+ } else {
+ LOGV("NEGATIVE expectedDelayNs[%lld] = "\
+ "er->playback_delay[%d] + delayCapture[%d] - timeDiff[%lld]",
+ expectedDelayNs, er->playback_delay, buffer->delay_ns, timeDiff);
+ }
+ }
+
+ memcpy(buffer->raw,
+ (char *)er->buffer,
+ buffer->frame_count * er->rd_frame_size);
+
+ er->frames_in -= buffer->frame_count;
+ memcpy(er->buffer,
+ (char *)er->buffer + buffer->frame_count * er->rd_frame_size,
+ er->frames_in * er->rd_frame_size);
+
+ // As the reference buffer is now time aligned to the microphone signal there is a zero delay
+ buffer->delay_ns = 0;
+
+ LOGV("EchoReference::read() END %d frames, total frames in %d",
+ buffer->frame_count, er->frames_in);
+
+ pthread_cond_signal(&er->cond);
+
+exit:
+ pthread_mutex_unlock(&er->lock);
+ return 0;
+}
+
+
+int create_echo_reference(audio_format_t rdFormat,
+ uint32_t rdChannelCount,
+ uint32_t rdSamplingRate,
+ audio_format_t wrFormat,
+ uint32_t wrChannelCount,
+ uint32_t wrSamplingRate,
+ struct echo_reference_itfe **echo_reference)
+{
+ struct echo_reference *er;
+
+ LOGV("create_echo_reference()");
+
+ if (echo_reference == NULL) {
+ return -EINVAL;
+ }
+
+ *echo_reference = NULL;
+
+ if (rdFormat != AUDIO_FORMAT_PCM_16_BIT ||
+ rdFormat != wrFormat) {
+ LOGW("create_echo_reference bad format rd %d, wr %d", rdFormat, wrFormat);
+ return -EINVAL;
+ }
+ if ((rdChannelCount != 1 && rdChannelCount != 2) ||
+ wrChannelCount != 2) {
+ LOGW("create_echo_reference bad channel count rd %d, wr %d", rdChannelCount, wrChannelCount);
+ return -EINVAL;
+ }
+
+ if (wrSamplingRate < rdSamplingRate) {
+ LOGW("create_echo_reference bad smp rate rd %d, wr %d", rdSamplingRate, wrSamplingRate);
+ return -EINVAL;
+ }
+
+ er = (struct echo_reference *)calloc(1, sizeof(struct echo_reference));
+
+ er->itfe.read = echo_reference_read;
+ er->itfe.write = echo_reference_write;
+
+ er->state = ECHOREF_IDLE;
+ er->rd_format = rdFormat;
+ er->rd_channel_count = rdChannelCount;
+ er->rd_sampling_rate = rdSamplingRate;
+ er->wr_format = wrFormat;
+ er->wr_channel_count = wrChannelCount;
+ er->wr_sampling_rate = wrSamplingRate;
+ er->rd_frame_size = audio_bytes_per_sample(rdFormat) * rdChannelCount;
+ er->wr_frame_size = audio_bytes_per_sample(wrFormat) * wrChannelCount;
+ *echo_reference = &er->itfe;
+ return 0;
+}
+
+void release_echo_reference(struct echo_reference_itfe *echo_reference) {
+ struct echo_reference *er = (struct echo_reference *)echo_reference;
+
+ if (er == NULL) {
+ return;
+ }
+
+ LOGV("EchoReference dstor");
+ echo_reference_reset_l(er);
+ if (er->down_sampler != NULL) {
+ release_resampler(er->down_sampler);
+ }
+ free(er);
+}
+
diff --git a/audio_utils/include/audio_utils/EchoReference.h b/audio_utils/include/audio_utils/EchoReference.h
deleted file mode 100644
index e20ec69..0000000
--- a/audio_utils/include/audio_utils/EchoReference.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-** 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.
-*/
-
-#ifndef ANDROID_ECHO_REFERENCE_H
-#define ANDROID_ECHO_REFERENCE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <hardware_legacy/AudioSystemLegacy.h>
-#include <audio_utils/ReSampler.h>
-
-namespace android_audio_legacy {
-using android::Mutex;
-using android::AutoMutex;
-
-class EchoReference : public ReSampler::BufferProvider {
-
-public:
-
- EchoReference(audio_format_t rdFormat,
- uint32_t rdChannelCount,
- uint32_t rdSamplingRate,
- audio_format_t wrFormat,
- uint32_t wrChannelCount,
- uint32_t wrSamplingRate);
- virtual ~EchoReference();
-
- // echo reference state: it field indicating if read, write or both are active.
- enum state {
- ECHOREF_IDLE = 0x00, // idle
- ECHOREF_READING = 0x01, // reading is active
- ECHOREF_WRITING = 0x02 // writing is active
- };
-
- // Buffer descriptor used by read() and write() methods, including the time stamp and delay.
- class Buffer {
- public:
- void *raw; // pointer to audio frame
- size_t frameCount; // number of frames in buffer
- int32_t delayNs; // delay for this buffer (see comment below)
- struct timespec timeStamp; // time stamp for this buffer (see comment below)
- };
- // when used for EchoReference::write():
- // + as input:
- // - delayNs is the delay introduced by playback buffers
- // - timeStamp is the time stamp corresponding to the delay calculation
- // + as output:
- // unused
- // when used for EchoReference::read():
- // + as input:
- // - delayNs is the delay introduced by capture buffers
- // - timeStamp is the time stamp corresponding to the delay calculation
- // + as output:
- // - delayNs is the delay between the returned frames and the capture time derived from
- // delay and time stamp indicated as input. This delay is to be communicated to the AEC.
- // - frameCount is updated with the actual number of frames returned
-
-
- // BufferProvider
- status_t getNextBuffer(ReSampler::BufferProvider::Buffer* buffer);
- void releaseBuffer(ReSampler::BufferProvider::Buffer* buffer);
-
- status_t initCheck() { return mStatus; }
-
- status_t read(Buffer *buffer);
- status_t write(Buffer *buffer);
-
-
-private:
-
- void reset_l();
-
- status_t mStatus; // init status
- uint32_t mState; // active state: reading, writing or both
- audio_format_t mRdFormat; // read sample format
- uint32_t mRdChannelCount; // read number of channels
- uint32_t mRdSamplingRate; // read sampling rate
- size_t mRdFrameSize; // read frame size (bytes per sample)
- audio_format_t mWrFormat; // write sample format
- uint32_t mWrChannelCount; // write number of channels
- uint32_t mWrSamplingRate; // write sampling rate
- size_t mWrFrameSize; // write frame size (bytes per sample)
- void *mBuffer; // main buffer
- size_t mBufSize; // main buffer size in frames
- size_t mFramesIn; // number of frames in main buffer
- void *mWrBuf; // buffer for input conversions
- size_t mWrBufSize; // size of conversion buffer in frames
- size_t mWrFramesIn; // number of frames in conversion buffer
- void *mWrSrcBuf; // resampler input buf (either mWrBuf or buffer used by write()
- struct timespec mWrRenderTime; // latest render time indicated by write()
- int32_t mPlaybackDelay;
-
- uint32_t mRdDurationUs; // Duration of last buffer read (used for mCond wait timeout)
- android::Mutex mLock; // Mutex protecting read/write concurrency
- android::Condition mCond; // Condition signaled when data is ready to read
- ReSampler *mDownSampler; // input resampler
-
- static const int sMinDelayUpdate = 62500; // delay jump threshold to update ref buffer
- // 0.5 samples at 8kHz in nsecs
-};
-
-}; // namespace android
-
-#endif // ANDROID_ECHO_REFERENCE_H
diff --git a/audio_utils/include/audio_utils/ReSampler.h b/audio_utils/include/audio_utils/ReSampler.h
deleted file mode 100644
index f531900..0000000
--- a/audio_utils/include/audio_utils/ReSampler.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-** Copyright 2008, 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_RESAMPLER_H
-#define ANDROID_RESAMPLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <hardware_legacy/AudioSystemLegacy.h>
-#include "speex/speex_resampler.h"
-
-namespace android_audio_legacy {
-
-class ReSampler {
-public:
-
- class BufferProvider
- {
- public:
-
- struct Buffer {
- union {
- void* raw;
- short* i16;
- int8_t* i8;
- };
- size_t frameCount;
- };
-
- virtual ~BufferProvider() {}
-
- virtual status_t getNextBuffer(Buffer* buffer) = 0;
- virtual void releaseBuffer(Buffer* buffer) = 0;
- };
-
- ReSampler(uint32_t inSampleRate,
- uint32_t outSampleRate,
- uint32_t channelCount,
- BufferProvider* provider);
-
- virtual ~ReSampler();
-
- status_t initCheck() { return mStatus; }
- void reset();
- int resample(int16_t* out, size_t *outFrameCount);
- int32_t delayNs();
-
-
-private:
- status_t mStatus; // init status
- SpeexResamplerState *mSpeexResampler; // handle on speex resampler
- BufferProvider* mProvider; // buffer provider installed by client
- uint32_t mInSampleRate; // input sampling rate
- uint32_t mOutSampleRate; // output sampling rate
- uint32_t mChannelCount; // number of channels
- int16_t *mInBuf; // input buffer
- size_t mInBufSize; // input buffer size
- size_t mFramesIn; // number of frames in input buffer
- size_t mFramesRq; // cached number of output frames
- size_t mFramesNeeded; // minimum number of input frames to produce mFramesRq
- // output frames
- int32_t mSpeexDelayNs; // delay introduced by speex resampler in ns
-};
-
-}; // namespace android_audio_legacy
-
-#endif // ANDROID_RESAMPLER_H
diff --git a/audio_utils/include/audio_utils/echo_reference.h b/audio_utils/include/audio_utils/echo_reference.h
new file mode 100644
index 0000000..15edda4
--- /dev/null
+++ b/audio_utils/include/audio_utils/echo_reference.h
@@ -0,0 +1,66 @@
+/*
+** 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.
+*/
+
+#ifndef ANDROID_ECHO_REFERENCE_H
+#define ANDROID_ECHO_REFERENCE_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+/* Buffer descriptor used by read() and write() methods, including the time stamp and delay. */
+struct echo_reference_buffer {
+ void *raw; // pointer to audio frame
+ size_t frame_count; // number of frames in buffer
+ int32_t delay_ns; // delay for this buffer (see comment below)
+ struct timespec time_stamp; // time stamp for this buffer (see comment below)
+ // default ALSA gettimeofday() format
+};
+/**
+ * + as input:
+ * - delay_ns is the delay introduced by playback buffers
+ * - time_stamp is the time stamp corresponding to the delay calculation
+ * + as output:
+ * unused
+ * when used for EchoReference::read():
+ * + as input:
+ * - delay_ns is the delay introduced by capture buffers
+ * - time_stamp is the time stamp corresponding to the delay calculation
+ * + as output:
+ * - delay_ns is the delay between the returned frames and the capture time derived from
+ * delay and time stamp indicated as input. This delay is to be communicated to the AEC.
+ * - frame_count is updated with the actual number of frames returned
+ */
+
+struct echo_reference_itfe {
+ int (*read)(struct echo_reference_itfe *echo_reference, struct echo_reference_buffer *buffer);
+ int (*write)(struct echo_reference_itfe *echo_reference, struct echo_reference_buffer *buffer);
+};
+
+int create_echo_reference(audio_format_t rdFormat,
+ uint32_t rdChannelCount,
+ uint32_t rdSamplingRate,
+ audio_format_t wrFormat,
+ uint32_t wrChannelCount,
+ uint32_t wrSamplingRate,
+ struct echo_reference_itfe **);
+
+void release_echo_reference(struct echo_reference_itfe *echo_reference);
+
+__END_DECLS
+
+#endif // ANDROID_ECHO_REFERENCE_H
diff --git a/audio_utils/include/audio_utils/resampler.h b/audio_utils/include/audio_utils/resampler.h
new file mode 100644
index 0000000..0c7046f
--- /dev/null
+++ b/audio_utils/include/audio_utils/resampler.h
@@ -0,0 +1,109 @@
+/*
+** Copyright 2008, 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_RESAMPLER_H
+#define ANDROID_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+
+#define RESAMPLER_QUALITY_MAX 10
+#define RESAMPLER_QUALITY_MIN 0
+#define RESAMPLER_QUALITY_DEFAULT 4
+#define RESAMPLER_QUALITY_VOIP 3
+#define RESAMPLER_QUALITY_DESKTOP 5
+
+struct resampler_buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frame_count;
+};
+
+/* call back interface used by the resampler to get new data */
+struct resampler_buffer_provider
+{
+ /**
+ * get a new buffer of data:
+ * as input: buffer->frame_count is the number of frames requested
+ * as output: buffer->frame_count is the number of frames returned
+ * buffer->raw points to data returned
+ */
+ int (*get_next_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+ /**
+ * release a consumed buffer of data:
+ * as input: buffer->frame_count is the number of frames released
+ * buffer->raw points to data released
+ */
+ void (*release_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+};
+
+/* resampler interface */
+struct resampler_itfe {
+ /**
+ * reset resampler state
+ */
+ void (*reset)(struct resampler_itfe *resampler);
+ /**
+ * resample input from buffer provider and output at most *outFrameCount to out buffer.
+ * *outFrameCount is updated with the actual number of frames produced.
+ */
+ int (*resample_from_provider)(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * resample at most *inFrameCount frames from in buffer and output at most
+ * *outFrameCount to out buffer. *inFrameCount and *outFrameCount are updated respectively
+ * with the number of frames remaining in input and written to output.
+ */
+ int (*resample_from_input)(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * return the latency introduced by the resampler in ns.
+ */
+ int32_t (*delay_ns)(struct resampler_itfe *resampler);
+};
+
+/**
+ * create a resampler according to input parameters passed.
+ * If resampler_buffer_provider is not NULL only resample_from_provider() can be called.
+ * If resampler_buffer_provider is NULL only resample_from_input() can be called.
+ */
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider *provider,
+ struct resampler_itfe **);
+
+/**
+ * release resampler resources.
+ */
+void release_resampler(struct resampler_itfe *);
+
+__END_DECLS
+
+#endif // ANDROID_RESAMPLER_H
diff --git a/audio_utils/resampler.c b/audio_utils/resampler.c
new file mode 100644
index 0000000..d41dd42
--- /dev/null
+++ b/audio_utils/resampler.c
@@ -0,0 +1,263 @@
+/*
+** 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 <errno.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <system/audio.h>
+#include <audio_utils/resampler.h>
+#include <speex/speex_resampler.h>
+
+
+struct resampler {
+ struct resampler_itfe itfe;
+ SpeexResamplerState *speex_resampler; // handle on speex resampler
+ struct resampler_buffer_provider *provider; // buffer provider installed by client
+ uint32_t in_sample_rate; // input sampling rate in Hz
+ uint32_t out_sample_rate; // output sampling rate in Hz
+ uint32_t channel_count; // number of channels (interleaved)
+ int16_t *in_buf; // input buffer
+ size_t in_buf_size; // input buffer size
+ size_t frames_in; // number of frames in input buffer
+ size_t frames_rq; // cached number of output frames
+ size_t frames_needed; // minimum number of input frames to produce
+ // frames_rq output frames
+ int32_t speex_delay_ns; // delay introduced by speex resampler in ns
+};
+
+
+//------------------------------------------------------------------------------
+// speex based resampler
+//------------------------------------------------------------------------------
+
+static void resampler_reset(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ rsmp->frames_in = 0;
+ rsmp->frames_rq = 0;
+
+ if (rsmp != NULL && rsmp->speex_resampler != NULL) {
+ speex_resampler_reset_mem(rsmp->speex_resampler);
+ }
+}
+
+static int32_t resampler_delay_ns(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate);
+ delay += rsmp->speex_delay_ns;
+
+ 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_from_provider(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL || out == NULL || outFrameCount == NULL) {
+ return -EINVAL;
+ }
+ if (rsmp->provider == NULL) {
+ *outFrameCount = 0;
+ return -ENOSYS;
+ }
+
+ 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 != rsmp->frames_rq) {
+ rsmp->frames_needed = (framesRq * rsmp->out_sample_rate) / rsmp->in_sample_rate + 1;
+ rsmp->frames_rq = framesRq;
+ }
+
+ size_t framesWr = 0;
+ size_t inFrames = 0;
+ while (framesWr < framesRq) {
+ if (rsmp->frames_in < rsmp->frames_needed) {
+ // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
+ // least the number of frames needed to produce the number of frames requested at
+ // the output sampling rate
+ if (rsmp->in_buf_size < rsmp->frames_needed) {
+ rsmp->in_buf_size = rsmp->frames_needed;
+ rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
+ rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
+ }
+ struct resampler_buffer buf;
+ buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
+ rsmp->provider->get_next_buffer(rsmp->provider, &buf);
+ if (buf.raw == NULL) {
+ break;
+ }
+ memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
+ buf.raw,
+ buf.frame_count * rsmp->channel_count * sizeof(int16_t));
+ rsmp->frames_in += buf.frame_count;
+ rsmp->provider->release_buffer(rsmp->provider, &buf);
+ }
+
+ size_t outFrames = framesRq - framesWr;
+ inFrames = rsmp->frames_in;
+ if (rsmp->channel_count == 1) {
+ speex_resampler_process_int(rsmp->speex_resampler,
+ 0,
+ rsmp->in_buf,
+ &inFrames,
+ out + framesWr,
+ &outFrames);
+ } else {
+ speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+ rsmp->in_buf,
+ &inFrames,
+ out + framesWr * rsmp->channel_count,
+ &outFrames);
+ }
+ framesWr += outFrames;
+ rsmp->frames_in -= inFrames;
+ LOGW_IF((framesWr != framesRq) && (rsmp->frames_in != 0),
+ "ReSampler::resample() remaining %d frames in and %d frames out",
+ rsmp->frames_in, (framesRq - framesWr));
+ }
+ if (rsmp->frames_in) {
+ memmove(rsmp->in_buf,
+ rsmp->in_buf + inFrames * rsmp->channel_count,
+ rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
+ }
+ *outFrameCount = framesWr;
+
+ return 0;
+}
+
+int resampler_resample_from_input(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL || in == NULL || inFrameCount == NULL ||
+ out == NULL || outFrameCount == NULL) {
+ return -EINVAL;
+ }
+ if (rsmp->provider != NULL) {
+ *outFrameCount = 0;
+ return -ENOSYS;
+ }
+
+ if (rsmp->channel_count == 1) {
+ speex_resampler_process_int(rsmp->speex_resampler,
+ 0,
+ in,
+ inFrameCount,
+ out,
+ outFrameCount);
+ } else {
+ speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+ in,
+ inFrameCount,
+ out,
+ outFrameCount);
+ }
+
+ LOGV("resampler_resample_from_input() DONE in %d out % d", *inFrameCount, *outFrameCount);
+
+ return 0;
+}
+
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider* provider,
+ struct resampler_itfe **resampler)
+{
+ int error;
+ struct resampler *rsmp;
+
+ LOGV("create_resampler() In SR %d Out SR %d channels %d",
+ inSampleRate, outSampleRate, channelCount);
+
+ if (resampler == NULL) {
+ return -EINVAL;
+ }
+
+ *resampler = NULL;
+
+ if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) {
+ return -EINVAL;
+ }
+
+ rsmp = (struct resampler *)calloc(1, sizeof(struct resampler));
+
+ rsmp->speex_resampler = speex_resampler_init(channelCount,
+ inSampleRate,
+ outSampleRate,
+ quality,
+ &error);
+ if (rsmp->speex_resampler == NULL) {
+ LOGW("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error));
+ return -ENODEV;
+ }
+
+ rsmp->itfe.reset = resampler_reset;
+ rsmp->itfe.resample_from_provider = resampler_resample_from_provider;
+ rsmp->itfe.resample_from_input = resampler_resample_from_input;
+ rsmp->itfe.delay_ns = resampler_delay_ns;
+
+ rsmp->provider = provider;
+ rsmp->in_sample_rate = inSampleRate;
+ rsmp->out_sample_rate = outSampleRate;
+ rsmp->channel_count = channelCount;
+ rsmp->in_buf = NULL;
+ rsmp->in_buf_size = 0;
+
+ resampler_reset(&rsmp->itfe);
+
+ int frames = speex_resampler_get_input_latency(rsmp->speex_resampler);
+ rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate);
+ frames = speex_resampler_get_output_latency(rsmp->speex_resampler);
+ rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate);
+
+ *resampler = &rsmp->itfe;
+ LOGV("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p",
+ rsmp, &rsmp->itfe, rsmp->speex_resampler);
+ return 0;
+}
+
+void release_resampler(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL) {
+ return;
+ }
+
+ free(rsmp->in_buf);
+
+ if (rsmp->speex_resampler != NULL) {
+ speex_resampler_destroy(rsmp->speex_resampler);
+ }
+ free(rsmp);
+}