diff options
author | James Dong <jdong@google.com> | 2010-07-29 18:06:08 -0700 |
---|---|---|
committer | James Dong <jdong@google.com> | 2010-07-30 14:35:37 -0700 |
commit | 46292fb347d72a314d985e34e5e3743d846cb9b6 (patch) | |
tree | a949b30281f740309113e150132aa4eae6bd10e4 | |
parent | 5caff27f4683d5e444f327a5beec15d9b8c7f252 (diff) | |
download | frameworks_av-46292fb347d72a314d985e34e5e3743d846cb9b6.zip frameworks_av-46292fb347d72a314d985e34e5e3743d846cb9b6.tar.gz frameworks_av-46292fb347d72a314d985e34e5e3743d846cb9b6.tar.bz2 |
Add lost frame handling in AudioSource
- Also collect stats on lost audio frames instead of time spent on reading
Change-Id: I6380b143e4fbdcd894491aaae523331e90d0f04f
-rw-r--r-- | include/media/stagefright/AudioSource.h | 5 | ||||
-rw-r--r-- | media/libstagefright/AudioSource.cpp | 137 |
2 files changed, 94 insertions, 48 deletions
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h index 628200d..f1d45d2 100644 --- a/include/media/stagefright/AudioSource.h +++ b/include/media/stagefright/AudioSource.h @@ -57,11 +57,10 @@ private: bool mCollectStats; bool mTrackMaxAmplitude; - int64_t mTotalReadTimeUs; - int64_t mTotalReadBytes; - int64_t mTotalReads; int64_t mStartTimeUs; int16_t mMaxAmplitude; + int64_t mPrevSampleTimeUs; + int64_t mNumLostFrames; MediaBufferGroup *mGroup; diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index 50c0edc..99978e8 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -26,8 +26,7 @@ #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> #include <cutils/properties.h> -#include <sys/time.h> -#include <time.h> +#include <stdlib.h> namespace android { @@ -35,9 +34,8 @@ AudioSource::AudioSource( int inputSource, uint32_t sampleRate, uint32_t channels) : mStarted(false), mCollectStats(false), - mTotalReadTimeUs(0), - mTotalReadBytes(0), - mTotalReads(0), + mPrevSampleTimeUs(0), + mNumLostFrames(0), mGroup(NULL) { LOGV("sampleRate: %d, channels: %d", sampleRate, channels); @@ -110,10 +108,7 @@ status_t AudioSource::stop() { mStarted = false; if (mCollectStats) { - LOGI("%lld reads: %.2f bps in %lld us", - mTotalReads, - (mTotalReadBytes * 8000000.0) / mTotalReadTimeUs, - mTotalReadTimeUs); + LOGI("Total lost audio frames: %lld", mNumLostFrames); } return OK; @@ -129,67 +124,113 @@ sp<MetaData> AudioSource::getFormat() { return meta; } +/* + * Returns -1 if frame skipping request is too long. + * Returns 0 if there is no need to skip frames. + * Returns 1 if we need to skip frames. + */ +static int skipFrame(int64_t timestampUs, + const MediaSource::ReadOptions *options) { + + int64_t skipFrameUs; + if (!options || !options->getSkipFrame(&skipFrameUs)) { + return 0; + } + + if (skipFrameUs <= timestampUs) { + return 0; + } + + // Safe guard against the abuse of the kSkipFrame_Option. + if (skipFrameUs - timestampUs >= 1E6) { + LOGE("Frame skipping requested is way too long: %lld us", + skipFrameUs - timestampUs); + + return -1; + } + + LOGV("skipFrame: %lld us > timestamp: %lld us", + skipFrameUs, timestampUs); + + return 1; + +} + status_t AudioSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; - ++mTotalReads; MediaBuffer *buffer; CHECK_EQ(mGroup->acquire_buffer(&buffer), OK); + int err = 0; while (mStarted) { + uint32_t numFramesRecorded; mRecord->getPosition(&numFramesRecorded); - int64_t latency = mRecord->latency() * 1000; - int64_t readTime = systemTime() / 1000; - if (numFramesRecorded == 0) { + if (numFramesRecorded == 0 && mPrevSampleTimeUs == 0) { // Initial delay if (mStartTimeUs > 0) { - mStartTimeUs = readTime - mStartTimeUs; + mStartTimeUs = systemTime() / 1000 - mStartTimeUs; } else { - mStartTimeUs += latency; + // Assume latency is constant. + mStartTimeUs += mRecord->latency() * 1000; } + mPrevSampleTimeUs = mStartTimeUs; } - ssize_t n = 0; - if (mCollectStats) { - n = mRecord->read(buffer->data(), buffer->size()); - int64_t endTime = systemTime() / 1000; - mTotalReadTimeUs += (endTime - readTime); - if (n >= 0) { - mTotalReadBytes += n; + uint32_t sampleRate = mRecord->getSampleRate(); + + // Insert null frames when lost frames are detected. + int64_t timestampUs = mPrevSampleTimeUs; + uint32_t numLostBytes = mRecord->getInputFramesLost() << 1; +#if 0 + // Simulate lost frames + numLostBytes = ((rand() * 1.0 / RAND_MAX)) * kMaxBufferSize; + numLostBytes &= 0xFFFFFFFE; // Alignment request + + // Reduce the chance to lose + if (rand() * 1.0 / RAND_MAX >= 0.05) { + numLostBytes = 0; + } +#endif + if (numLostBytes > 0) { + // Not expect too many lost frames! + CHECK(numLostBytes <= kMaxBufferSize); + + timestampUs += (1000000LL * numLostBytes >> 1) / sampleRate; + CHECK(timestampUs > mPrevSampleTimeUs); + if (mCollectStats) { + mNumLostFrames += (numLostBytes >> 1); + } + if ((err = skipFrame(timestampUs, options)) == -1) { + buffer->release(); + return UNKNOWN_ERROR; + } else if (err != 0) { + continue; } - } else { - n = mRecord->read(buffer->data(), buffer->size()); + memset(buffer->data(), 0, numLostBytes); + buffer->set_range(0, numLostBytes); + buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); + mPrevSampleTimeUs = timestampUs; + *out = buffer; + return OK; } + ssize_t n = mRecord->read(buffer->data(), buffer->size()); if (n < 0) { buffer->release(); - buffer = NULL; - return (status_t)n; } - uint32_t sampleRate = mRecord->getSampleRate(); - int64_t timestampUs = (1000000LL * numFramesRecorded) / sampleRate + - mStartTimeUs; - int64_t skipFrameUs; - if (!options || !options->getSkipFrame(&skipFrameUs)) { - skipFrameUs = timestampUs; // Don't skip frame - } - - if (skipFrameUs > timestampUs) { - // Safe guard against the abuse of the kSkipFrame_Option. - if (skipFrameUs - timestampUs >= 1E6) { - LOGE("Frame skipping requested is way too long: %lld us", - skipFrameUs - timestampUs); - buffer->release(); - return UNKNOWN_ERROR; - } - LOGV("skipFrame: %lld us > timestamp: %lld us, samples %d", - skipFrameUs, timestampUs, numFramesRecorded); + int64_t recordDurationUs = (1000000LL * n >> 1) / sampleRate; + timestampUs += recordDurationUs; + if ((err = skipFrame(timestampUs, options)) == -1) { + buffer->release(); + return UNKNOWN_ERROR; + } else if (err != 0) { continue; } @@ -197,7 +238,13 @@ status_t AudioSource::read( trackMaxAmplitude((int16_t *) buffer->data(), n >> 1); } - buffer->meta_data()->setInt64(kKeyTime, timestampUs); + buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); + CHECK(timestampUs > mPrevSampleTimeUs); + if (mNumLostFrames == 0) { + CHECK_EQ(mPrevSampleTimeUs, + mStartTimeUs + (1000000LL * numFramesRecorded) / sampleRate); + } + mPrevSampleTimeUs = timestampUs; LOGV("initial delay: %lld, sample rate: %d, timestamp: %lld", mStartTimeUs, sampleRate, timestampUs); |