Loading include/media/stagefright/AudioSource.h +2 −3 Original line number Diff line number Diff line Loading @@ -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; Loading media/libstagefright/AudioSource.cpp +92 −45 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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); Loading Loading @@ -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; Loading @@ -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; } 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); ssize_t n = 0; timestampUs += (1000000LL * numLostBytes >> 1) / sampleRate; CHECK(timestampUs > mPrevSampleTimeUs); if (mCollectStats) { n = mRecord->read(buffer->data(), buffer->size()); int64_t endTime = systemTime() / 1000; mTotalReadTimeUs += (endTime - readTime); if (n >= 0) { mTotalReadBytes += n; mNumLostFrames += (numLostBytes >> 1); } } else { n = mRecord->read(buffer->data(), buffer->size()); if ((err = skipFrame(timestampUs, options)) == -1) { buffer->release(); return UNKNOWN_ERROR; } else if (err != 0) { continue; } 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); int64_t recordDurationUs = (1000000LL * n >> 1) / sampleRate; timestampUs += recordDurationUs; if ((err = skipFrame(timestampUs, options)) == -1) { buffer->release(); return UNKNOWN_ERROR; } LOGV("skipFrame: %lld us > timestamp: %lld us, samples %d", skipFrameUs, timestampUs, numFramesRecorded); } else if (err != 0) { continue; } Loading @@ -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); Loading Loading
include/media/stagefright/AudioSource.h +2 −3 Original line number Diff line number Diff line Loading @@ -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; Loading
media/libstagefright/AudioSource.cpp +92 −45 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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); Loading Loading @@ -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; Loading @@ -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; } 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); ssize_t n = 0; timestampUs += (1000000LL * numLostBytes >> 1) / sampleRate; CHECK(timestampUs > mPrevSampleTimeUs); if (mCollectStats) { n = mRecord->read(buffer->data(), buffer->size()); int64_t endTime = systemTime() / 1000; mTotalReadTimeUs += (endTime - readTime); if (n >= 0) { mTotalReadBytes += n; mNumLostFrames += (numLostBytes >> 1); } } else { n = mRecord->read(buffer->data(), buffer->size()); if ((err = skipFrame(timestampUs, options)) == -1) { buffer->release(); return UNKNOWN_ERROR; } else if (err != 0) { continue; } 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); int64_t recordDurationUs = (1000000LL * n >> 1) / sampleRate; timestampUs += recordDurationUs; if ((err = skipFrame(timestampUs, options)) == -1) { buffer->release(); return UNKNOWN_ERROR; } LOGV("skipFrame: %lld us > timestamp: %lld us, samples %d", skipFrameUs, timestampUs, numFramesRecorded); } else if (err != 0) { continue; } Loading @@ -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); Loading