diff options
author | Eric Laurent <elaurent@google.com> | 2011-08-12 19:07:19 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-08-12 19:07:19 -0700 |
commit | 5a3b88bce08e8ac1b2a7dd01daa5149ff781584a (patch) | |
tree | e439c5add8c937c88dc0862875a658c382617dd1 | |
parent | df5918b0b4eefc387c9cfc4e8d34a021ec8dad38 (diff) | |
parent | 86a47e3912531066f6b81ee078e78eccc853ad2f (diff) | |
download | device_samsung_crespo-5a3b88bce08e8ac1b2a7dd01daa5149ff781584a.zip device_samsung_crespo-5a3b88bce08e8ac1b2a7dd01daa5149ff781584a.tar.gz device_samsung_crespo-5a3b88bce08e8ac1b2a7dd01daa5149ff781584a.tar.bz2 |
Merge "audio HAL: new echo reference design"
-rw-r--r-- | libaudio/AudioHardware.cpp | 146 | ||||
-rw-r--r-- | libaudio/AudioHardware.h | 5 | ||||
-rw-r--r-- | libaudio/EchoReference.cpp | 180 | ||||
-rw-r--r-- | libaudio/EchoReference.h | 33 |
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 |