summaryrefslogtreecommitdiffstats
path: root/libaudio
diff options
context:
space:
mode:
authorAndy Gough <andygough@google.com>2011-08-04 11:59:44 -0700
committerEric Laurent <elaurent@google.com>2011-08-12 19:04:47 -0700
commit86a47e3912531066f6b81ee078e78eccc853ad2f (patch)
tree23f569ea1e49a1a36101bef50c4af37638be9729 /libaudio
parent19b413d3c87b2f5c8b610192979ff26efe736d27 (diff)
downloaddevice_samsung_crespo-86a47e3912531066f6b81ee078e78eccc853ad2f.zip
device_samsung_crespo-86a47e3912531066f6b81ee078e78eccc853ad2f.tar.gz
device_samsung_crespo-86a47e3912531066f6b81ee078e78eccc853ad2f.tar.bz2
audio HAL: new echo reference design
The echo reference discards or inserts (silent) frames according to underruns or overruns. It always returns an echo buffer which delay from current capture buffer is 0. Change-Id: Ifea06a47fe87f2b75d4d04737c495a9867d1c4bd
Diffstat (limited to 'libaudio')
-rw-r--r--libaudio/AudioHardware.cpp146
-rw-r--r--libaudio/AudioHardware.h5
-rw-r--r--libaudio/EchoReference.cpp180
-rw-r--r--libaudio/EchoReference.h33
4 files changed, 225 insertions, 139 deletions
diff --git a/libaudio/AudioHardware.cpp b/libaudio/AudioHardware.cpp
index faa8a14..d1160ba 100644
--- a/libaudio/AudioHardware.cpp
+++ b/libaudio/AudioHardware.cpp
@@ -1085,16 +1085,17 @@ AudioHardware::AudioStreamOutALSA::~AudioStreamOutALSA()
standby();
}
-int AudioHardware::AudioStreamOutALSA::computeEchoReferenceDelay(size_t frames,
- struct timespec *echoRefRenderTime)
+int AudioHardware::AudioStreamOutALSA::getPlaybackDelay(size_t frames,
+ EchoReference::Buffer *buffer)
{
size_t kernelFr;
- int rc = pcm_get_htimestamp(mPcm, &kernelFr, echoRefRenderTime);
+ int rc = pcm_get_htimestamp(mPcm, &kernelFr, &buffer->timeStamp);
if (rc < 0) {
- LOGV("computeEchoReferenceDelay(): pcm_get_htimestamp error");
- echoRefRenderTime->tv_sec = 0;
- echoRefRenderTime->tv_nsec = 0;
+ buffer->timeStamp.tv_sec = 0;
+ buffer->timeStamp.tv_nsec = 0;
+ buffer->delayNs = 0;
+ LOGV("getPlaybackDelay(): pcm_get_htimestamp error, setting playbackTimestamp to 0");
return rc;
}
@@ -1103,19 +1104,23 @@ int AudioHardware::AudioStreamOutALSA::computeEchoReferenceDelay(size_t frames,
// adjust render time stamp with delay added by current driver buffer.
// Add the duration of current frame as we want the render time of the last
// sample being written.
- long delayNs = (long)(((int64_t)(kernelFr + frames)* 1000000000) /
- AUDIO_HW_OUT_SAMPLERATE);
- delayNs += echoRefRenderTime->tv_nsec;
+ long delayNs = (long)(((int64_t)(kernelFr + frames)* 1000000000) /AUDIO_HW_OUT_SAMPLERATE);
- echoRefRenderTime->tv_nsec = delayNs % 1000000000;
- echoRefRenderTime->tv_sec += delayNs / 1000000000;
+ LOGV("AudioStreamOutALSA::getPlaybackDelay2 delayNs: [%ld], "\
+ "kernelFr:[%d], frames:[%d], buffSize:[%d], timeStamp:[%ld].[%ld]",
+ delayNs, (int)kernelFr, (int)frames, pcm_get_buffer_size(mPcm),
+ (long)buffer->timeStamp.tv_sec, buffer->timeStamp.tv_nsec);
+
+ buffer->delayNs = delayNs;
+ LOGV("NXPWritehTimestamps: FrameAvailable = [%d], hTimestamps = [%d]s.[%d]ns",
+ (int)kernelFr, (int)buffer->timeStamp.tv_sec, (int)(buffer->timeStamp.tv_nsec/1000));
return 0;
}
ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes)
{
- // LOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes);
+ LOGV("-----AudioStreamInALSA::write(%p, %d) START", buffer, (int)bytes);
status_t status = NO_INIT;
const uint8_t* p = static_cast<const uint8_t*>(buffer);
int ret;
@@ -1176,7 +1181,8 @@ ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t byte
EchoReference::Buffer b;
b.raw = (void *)buffer;
b.frameCount = bytes / frameSize();
- computeEchoReferenceDelay(bytes / frameSize(), &b.tstamp);
+
+ getPlaybackDelay(bytes / frameSize(), &b);
mEchoReference->write(&b);
}
@@ -1185,18 +1191,18 @@ ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t byte
TRACE_DRIVER_OUT
if (ret == 0) {
+ LOGV("-----AudioStreamInALSA::write(%p, %d) END", buffer, (int)bytes);
return bytes;
}
LOGW("write error: %d", errno);
status = -errno;
}
Error:
-
standby();
// Simulate audio output timing in case of error
usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
-
+ LOGE("AudioStreamOutALSA::write END WITH ERROR !!!!!!!!!(%p, %u)", buffer, bytes);
return status;
}
@@ -1549,8 +1555,8 @@ ssize_t AudioHardware::AudioStreamInALSA::processFrames(void* buffer, ssize_t fr
pushEchoReference(mProcFramesIn);
}
- // inBuf.frameCount and outBuf.frameCount indicate respectively the maximum number of frames
- // to be consumed and produced by process()
+ //inBuf.frameCount and outBuf.frameCount indicate respectively the maximum number of frames
+ //to be consumed and produced by process()
audio_buffer_t inBuf = {
mProcFramesIn,
{mProcBuf}
@@ -1585,8 +1591,13 @@ ssize_t AudioHardware::AudioStreamInALSA::processFrames(void* buffer, ssize_t fr
return framesWr;
}
-void AudioHardware::AudioStreamInALSA::updateEchoReference(size_t frames)
+int32_t AudioHardware::AudioStreamInALSA::updateEchoReference(size_t frames)
{
+ EchoReference::Buffer b;
+ b.delayNs = 0;
+
+ LOGV("updateEchoReference1 START, frames = [%d], mRefFramesIn = [%d], b.frameCount = [%d]",
+ frames, mRefFramesIn, frames - mRefFramesIn);
if (mRefFramesIn < frames) {
if (mRefBufSize < frames) {
mRefBufSize = frames;
@@ -1594,24 +1605,29 @@ void AudioHardware::AudioStreamInALSA::updateEchoReference(size_t frames)
mRefBufSize * mChannelCount * sizeof(int16_t));
}
- EchoReference::Buffer b;
b.frameCount = frames - mRefFramesIn;
b.raw = (void *)(mRefBuf + mRefFramesIn * mChannelCount);
- if (mEchoReference->read(&b) == NO_ERROR) {
+
+ getCaptureDelay(frames, &b);
+
+ if (mEchoReference->read(&b) == NO_ERROR)
+ {
mRefFramesIn += b.frameCount;
- // Echo delay calculation: updates mEchoDelayUs
- updateEchoDelay(frames, &b.tstamp);
- } else {
- mEchoDelayUs = 0;
+ LOGV("updateEchoReference2: mRefFramesIn:[%d], mRefBufSize:[%d], "\
+ "frames:[%d], b.frameCount:[%d]", mRefFramesIn, mRefBufSize,frames,b.frameCount);
}
+
+ }else{
+ LOGV("updateEchoReference3: NOT enough frames to read ref buffer");
}
+ return b.delayNs;
}
void AudioHardware::AudioStreamInALSA::pushEchoReference(size_t frames)
{
// read frames from echo reference buffer and update echo delay
// mRefFramesIn is updated with frames available in mRefBuf
- updateEchoReference(frames);
+ int32_t delayUs = (int32_t)(updateEchoReference(frames)/1000);
if (mRefFramesIn < frames) {
frames = mRefFramesIn;
@@ -1629,11 +1645,12 @@ void AudioHardware::AudioStreamInALSA::pushEchoReference(size_t frames)
(*mPreprocessors[i])->process_reverse(mPreprocessors[i],
&refBuf,
NULL);
- setPreProcessorEchoDelay(mPreprocessors[i], mEchoDelayUs);
+ setPreProcessorEchoDelay(mPreprocessors[i], delayUs);
}
mRefFramesIn -= refBuf.frameCount;
if (mRefFramesIn) {
+ LOGV("pushEchoReference5: shifting mRefBuf down by = %d frames", mRefFramesIn);
memcpy(mRefBuf,
mRefBuf + refBuf.frameCount * mChannelCount,
mRefFramesIn * mChannelCount * sizeof(int16_t));
@@ -1674,81 +1691,54 @@ status_t AudioHardware::AudioStreamInALSA::setPreprocessorParam(effect_handle_t
return status;
}
-void AudioHardware::AudioStreamInALSA::updateEchoDelay(size_t frames,
- struct timespec *echoRefRenderTime)
+void AudioHardware::AudioStreamInALSA::getCaptureDelay(size_t frames,
+ EchoReference::Buffer *buffer)
{
+
// read frames available in kernel driver buffer
size_t kernelFr;
struct timespec tstamp;
- if (pcm_get_htimestamp(mPcm, &kernelFr, &tstamp) < 0) {
- mEchoDelayUs = 0;
- LOGW("read updateEchoDelay(): pcm_get_htimestamp error");
- return;
- }
- if (echoRefRenderTime->tv_sec == 0 && echoRefRenderTime->tv_nsec == 0) {
- mEchoDelayUs = 0;
- LOGV("read updateEchoDelay(): echo ref render time is 0");
+ if (pcm_get_htimestamp(mPcm, &kernelFr, &tstamp) < 0) {
+ buffer->timeStamp.tv_sec = 0;
+ buffer->timeStamp.tv_nsec = 0;
+ buffer->delayNs = 0;
+ LOGW("read getCaptureDelay(): pcm_htimestamp error");
return;
}
- long kernelDelay = (long)(((int64_t)kernelFr * 1000000000) / AUDIO_HW_IN_SAMPLERATE);
-
// read frames available in audio HAL input buffer
// add number of frames being read as we want the capture time of first sample in current
// buffer
- long bufDelay = (long)(((int64_t)(mInputFramesIn + mProcFramesIn + frames) * 1000000000)
+ long bufDelay = (long)(((int64_t)(mInputFramesIn + mProcFramesIn) * 1000000000)
/ AUDIO_HW_IN_SAMPLERATE);
-
// add delay introduced by resampler
long rsmpDelay = 0;
if (mDownSampler) {
rsmpDelay = mDownSampler->delayNs();
}
- // correct capture time stamp
- long delay = kernelDelay + bufDelay + rsmpDelay;
- struct timespec tmp;
- tmp.tv_sec = delay / 1000000000;
- tmp.tv_nsec = delay % 1000000000;
-
- if (tstamp.tv_nsec < tmp.tv_nsec)
- {
- tmp.tv_sec = tstamp.tv_sec - tmp.tv_sec - 1;
- tmp.tv_nsec = 1000000000 + tstamp.tv_nsec - tmp.tv_nsec;
- } else {
- tmp.tv_sec = tstamp.tv_sec - tmp.tv_sec;
- tmp.tv_nsec = tstamp.tv_nsec - tmp.tv_nsec;
- }
+ long kernelDelay = (long)(((int64_t)kernelFr * 1000000000) / AUDIO_HW_IN_SAMPLERATE);
- // caculate echo delay = echo reference render time - capture time
- if (echoRefRenderTime->tv_nsec < tmp.tv_nsec)
- {
- tmp.tv_sec = echoRefRenderTime->tv_sec - tmp.tv_sec - 1;
- tmp.tv_nsec = 1000000000 + echoRefRenderTime->tv_nsec - tmp.tv_nsec;
- } else {
- tmp.tv_sec = echoRefRenderTime->tv_sec - tmp.tv_sec;
- tmp.tv_nsec = echoRefRenderTime->tv_nsec - tmp.tv_nsec;
- }
+ // correct capture time stamp
+ long delayNs = kernelDelay + bufDelay + rsmpDelay;
- mEchoDelayUs = (int32_t)(((int64_t)tmp.tv_sec * 1000000000 + tmp.tv_nsec) / 1000);
+ buffer->timeStamp = tstamp;
+ buffer->delayNs = delayNs;
+ LOGV("AudioStreamInALSA::getCaptureDelay2 TimeStamp = [%lld].[%lld], delayCaptureNs: [%ld],"\
+ " kernelDelay:[%ld], bufDelay:[%ld], rsmpDelay:[%ld], kernelFr:[%d], "\
+ "mInputFramesIn:[%d], mProcFramesIn:[%d], frames:[%d]",
+ (int64_t)buffer->timeStamp.tv_sec , (int64_t)buffer->timeStamp.tv_nsec, buffer->delayNs,
+ kernelDelay, bufDelay, rsmpDelay, kernelFr, mInputFramesIn,mProcFramesIn,frames);
- if (mEchoDelayUs < 0) {
- LOGW("negative echo delay !!! %d", mEchoDelayUs);
- mEchoDelayUs = 0;
- }
+ LOGV("NXPReadhTimestamps: FrameAvailable = [%d], hTimestamps = [%d]s.[%d]ns",
+ (int)kernelFr, (int)buffer->timeStamp.tv_sec, (int)(buffer->timeStamp.tv_nsec/1000));
-// LOGV("updateEchoDelay() ref render TS %d.%d capture TS %d.%d delta TS %d.%d"
-// " mEchoDelayUs %d kernelDelay %d bufDelay %d rsmpDelay %d",
-// (int)echoRefRenderTime->tv_sec, (int)echoRefRenderTime->tv_nsec,
-// (int)tstamp.tv_sec, (int)tstamp.tv_nsec,
-// (int)tmp.tv_sec, (int)tmp.tv_nsec,
-// mEchoDelayUs, (int)kernelDelay, (int)bufDelay, (int)rsmpDelay);
}
ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
{
- // LOGV("AudioStreamInALSA::read(%p, %d)", buffer, (int)bytes);
+ LOGV("-----AudioStreamInALSA::read(%p, %d) START", buffer, (int)bytes);
status_t status = NO_INIT;
if (mHardware == NULL) return NO_INIT;
@@ -1820,6 +1810,7 @@ ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
}
if (framesRd >= 0) {
+ LOGV("-----AudioStreamInALSA::read(%p, %d) END", buffer, (int)bytes);
return framesRd * mChannelCount * sizeof(int16_t);
}
@@ -1833,7 +1824,7 @@ Error:
// Simulate audio output timing in case of error
usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
-
+ LOGE("-----AudioStreamInALSA::read(%p, %d) END ERROR", buffer, (int)bytes);
return status;
}
@@ -1944,7 +1935,6 @@ status_t AudioHardware::AudioStreamInALSA::open_l()
mProcFramesIn = 0;
mRefBufSize = 0;
mRefFramesIn = 0;
- mEchoDelayUs = 0;
mMixer = mHardware->openMixer_l();
if (mMixer) {
@@ -2143,7 +2133,7 @@ status_t AudioHardware::AudioStreamInALSA::getNextBuffer(ReSampler::BufferProvid
mInputFramesIn = AUDIO_HW_IN_PERIOD_SZ;
}
- buffer->frameCount = (buffer->frameCount > mInputFramesIn) ? mInputFramesIn : buffer->frameCount;
+ buffer->frameCount = (buffer->frameCount > mInputFramesIn) ? mInputFramesIn:buffer->frameCount;
buffer->i16 = mInputBuf + (AUDIO_HW_IN_PERIOD_SZ - mInputFramesIn) * mChannelCount;
return mReadStatus;
diff --git a/libaudio/AudioHardware.h b/libaudio/AudioHardware.h
index 8824ca5..1fb848e 100644
--- a/libaudio/AudioHardware.h
+++ b/libaudio/AudioHardware.h
@@ -254,6 +254,7 @@ private:
private:
int computeEchoReferenceDelay(size_t frames, struct timespec *echoRefRenderTime);
+ int getPlaybackDelay(size_t frames, EchoReference::Buffer *buffer);
Mutex mLock;
AudioHardware* mHardware;
@@ -320,9 +321,10 @@ private:
ssize_t readFrames(void* buffer, ssize_t frames);
ssize_t processFrames(void* buffer, ssize_t frames);
- void updateEchoReference(size_t frames);
+ int32_t updateEchoReference(size_t frames);
void pushEchoReference(size_t frames);
void updateEchoDelay(size_t frames, struct timespec *echoRefRenderTime);
+ void getCaptureDelay(size_t frames, EchoReference::Buffer *buffer);
status_t setPreProcessorEchoDelay(effect_handle_t handle, int32_t delayUs);
status_t setPreprocessorParam(effect_handle_t handle, effect_param_t *param);
@@ -355,7 +357,6 @@ private:
size_t mRefFramesIn;
EchoReference *mEchoReference;
bool mNeedEchoReference;
- int32_t mEchoDelayUs;
};
};
diff --git a/libaudio/EchoReference.cpp b/libaudio/EchoReference.cpp
index cfd07de..2c10062 100644
--- a/libaudio/EchoReference.cpp
+++ b/libaudio/EchoReference.cpp
@@ -60,7 +60,6 @@ EchoReference::EchoReference(audio_format_t rdFormat,
mRdFrameSize = audio_bytes_per_sample(rdFormat) * rdChannelCount;
mWrFrameSize = audio_bytes_per_sample(wrFormat) * wrChannelCount;
-
mStatus = NO_ERROR;
}
@@ -71,9 +70,10 @@ EchoReference::~EchoReference() {
delete mDownSampler;
}
-status_t EchoReference::write(EchoReference::Buffer *buffer)
+status_t EchoReference::write(Buffer *buffer)
{
if (mStatus != NO_ERROR) {
+ LOGV("EchoReference::write() ERROR, exiting early");
return mStatus;
}
@@ -86,7 +86,18 @@ status_t EchoReference::write(EchoReference::Buffer *buffer)
return NO_ERROR;
}
-// LOGV("EchoReference::write() %d frames", buffer->frameCount);
+ 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");
@@ -100,17 +111,10 @@ status_t EchoReference::write(EchoReference::Buffer *buffer)
return NO_ERROR;
}
+ mWrRenderTime.tv_sec = buffer->timeStamp.tv_sec;
+ mWrRenderTime.tv_nsec = buffer->timeStamp.tv_nsec;
- // discard writes until a valid time stamp is provided. Once a valid TS has been received
- // reuse last good TS if none is provided.
- if (buffer->tstamp.tv_sec == 0 && buffer->tstamp.tv_nsec == 0 ) {
- if (mWrRenderTime.tv_sec == 0 && mWrRenderTime.tv_nsec == 0) {
- return NO_ERROR;
- }
- } else {
- mWrRenderTime.tv_sec = buffer->tstamp.tv_sec;
- mWrRenderTime.tv_nsec = buffer->tstamp.tv_nsec;
- }
+ mPlaybackDelay = buffer->delayNs;
void *srcBuf;
size_t inFrames;
@@ -119,8 +123,8 @@ status_t EchoReference::write(EchoReference::Buffer *buffer)
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
+ //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);
}
@@ -137,7 +141,8 @@ status_t EchoReference::write(EchoReference::Buffer *buffer)
}
if (mWrSamplingRate != mRdSamplingRate) {
if (mDownSampler == NULL) {
- LOGV("EchoReference::write() new ReSampler(%d, %d)", mWrSamplingRate, mRdSamplingRate);
+ LOGV("EchoReference::write() new ReSampler(%d, %d)",
+ mWrSamplingRate, mRdSamplingRate);
mDownSampler = new ReSampler(mWrSamplingRate,
mRdSamplingRate,
mRdChannelCount,
@@ -154,9 +159,12 @@ status_t EchoReference::write(EchoReference::Buffer *buffer)
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);
+ "EchoReference::write() mWrFramesIn not 0 (%d) after resampler",
+ mWrFramesIn);
}
srcBuf = mWrBuf;
} else {
@@ -164,20 +172,24 @@ status_t EchoReference::write(EchoReference::Buffer *buffer)
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);
- LOGV("EchoReference::write() increasing buffer size to %d", mBufSize);
}
memcpy((char *)mBuffer + mFramesIn * mRdFrameSize,
srcBuf,
inFrames * mRdFrameSize);
mFramesIn += inFrames;
- LOGV("EchoReference::write() frames %d, total frames in %d", inFrames, mFramesIn);
+ 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;
}
@@ -194,6 +206,9 @@ status_t EchoReference::read(EchoReference::Buffer *buffer)
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();
@@ -202,8 +217,7 @@ status_t EchoReference::read(EchoReference::Buffer *buffer)
if ((mState & ECHOREF_WRITING) == 0) {
memset(buffer->raw, 0, mRdFrameSize * buffer->frameCount);
- buffer->tstamp.tv_sec = 0;
- buffer->tstamp.tv_nsec = 0;
+ buffer->delayNs = 0;
return NO_ERROR;
}
@@ -215,17 +229,97 @@ status_t EchoReference::read(EchoReference::Buffer *buffer)
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;
- LOGV("EchoReference::read() waited %d ms but still not enough frames", timeoutMs);
}
}
- // computeRenderTime() must be called before subtracting frames read from mFramesIn because
- // we subtract the duration of the whole echo reference buffer including the buffer being read.
- // This is because the time stamp stored in mWrRenderTime corresponds to the last sample written
- // to the echo reference buffer and we want to return the render time of the first sample of
- // the buffer being read.
- computeRenderTime(&buffer->tstamp);
+ 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,
@@ -236,34 +330,16 @@ status_t EchoReference::read(EchoReference::Buffer *buffer)
(char *)mBuffer + buffer->frameCount * mRdFrameSize,
mFramesIn * mRdFrameSize);
- LOGV("EchoReference::read() %d frames, total frames in %d", buffer->frameCount, mFramesIn);
+ // 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::computeRenderTime(struct timespec *renderTime)
-{
- int64_t delayNs = ((int64_t)mFramesIn * 1000000000) / mRdSamplingRate;
-
- if (mDownSampler != NULL) {
- delayNs += mDownSampler->delayNs();
- }
-
- struct timespec tmp;
- tmp.tv_nsec = delayNs % 1000000000;
- tmp.tv_sec = delayNs / 1000000000;
-
- if (mWrRenderTime.tv_nsec < tmp.tv_nsec)
- {
- renderTime->tv_sec = mWrRenderTime.tv_sec - tmp.tv_sec - 1;
- renderTime->tv_nsec = 1000000000 + mWrRenderTime.tv_nsec - tmp.tv_nsec;
- } else {
- renderTime->tv_sec = mWrRenderTime.tv_sec - tmp.tv_sec;
- renderTime->tv_nsec = mWrRenderTime.tv_nsec - tmp.tv_nsec;
- }
-}
-
void EchoReference::reset_l() {
LOGV("EchoReference::reset_l()");
free(mBuffer);
diff --git a/libaudio/EchoReference.h b/libaudio/EchoReference.h
index 5d54fac..b82cd11 100644
--- a/libaudio/EchoReference.h
+++ b/libaudio/EchoReference.h
@@ -46,15 +46,29 @@ public:
ECHOREF_WRITING = 0x02 // writing is active
};
- // Buffer descriptor used by read() and write() methods, including the render time stamp.
- // for write(), The time stamp is the render time for the last sample in the buffer written
- // for read(), the time stamp is the render time for the first sample in the buffer read
+ // Buffer descriptor used by read() and write() methods, including the time stamp and delay.
class Buffer {
public:
- void *raw;
- size_t frameCount;
- struct timespec tstamp; // render time stamp of buffer. 0.0 means if unknown
+ 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);
@@ -65,10 +79,10 @@ public:
status_t read(Buffer *buffer);
status_t write(Buffer *buffer);
+
private:
void reset_l();
- void computeRenderTime(struct timespec *renderTime);
status_t mStatus; // init status
uint32_t mState; // active state: reading, writing or both
@@ -88,10 +102,15 @@ private:
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