diff options
Diffstat (limited to 'media/libstagefright/AudioSource.cpp')
-rw-r--r-- | media/libstagefright/AudioSource.cpp | 195 |
1 files changed, 176 insertions, 19 deletions
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index bb2d415..2bb721c 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,8 +29,17 @@ #include <cutils/properties.h> #include <stdlib.h> -namespace android { +#ifdef QCOM_ENHANCED_AUDIO +#define AMR_FRAMESIZE 32 +#define QCELP_FRAMESIZE 35 +#define EVRC_FRAMESIZE 23 +#define AMR_WB_FRAMESIZE 61 +#endif +namespace android { +// Treat time out as an error if we have not received any output +// buffers after 1 seconds +const static int64_t WaitLockEventTimeOutNs = 1000000000LL; static void AudioRecordCallbackFunction(int event, void *user, void *info) { AudioSource *source = (AudioSource *) user; switch (event) { @@ -55,7 +64,13 @@ AudioSource::AudioSource( mSampleRate(sampleRate), mPrevSampleTimeUs(0), mNumFramesReceived(0), - mNumClientOwnedBuffers(0) { + mNumClientOwnedBuffers(0) +#ifdef QCOM_ENHANCED_AUDIO + ,mFormat(AUDIO_FORMAT_PCM_16_BIT), + mMime(MEDIA_MIMETYPE_AUDIO_RAW) +#endif +{ + ALOGV("sampleRate: %d, channelCount: %d", sampleRate, channelCount); CHECK(channelCount == 1 || channelCount == 2 || channelCount == 6); @@ -64,10 +79,23 @@ AudioSource::AudioSource( sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_in_mask_from_count(channelCount)); + +#ifdef QCOM_ENHANCED_AUDIO + if ( NO_ERROR != AudioSystem::getInputBufferSize( + sampleRate, mFormat, channelCount, (size_t*)&mMaxBufferSize) ) { + mMaxBufferSize = kMaxBufferSize; + ALOGV("mMaxBufferSize = %d", mMaxBufferSize); + } +#endif + if (status == OK) { // make sure that the AudioRecord callback never returns more than the maximum // buffer size +#ifdef QCOM_ENHANCED_AUDIO + int frameCount = mMaxBufferSize / sizeof(int16_t) / channelCount; +#else int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount; +#endif // make sure that the AudioRecord total buffer size is large enough int bufCount = 2; @@ -78,7 +106,11 @@ AudioSource::AudioSource( mRecord = new AudioRecord( inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_in_mask_from_count(channelCount), +#ifdef QCOM_ENHANCED_AUDIO + 4 * mMaxBufferSize / sizeof(int16_t), /* Enable ping-pong buffers */ +#else bufCount * frameCount, +#endif AudioRecordCallbackFunction, this, frameCount); @@ -99,6 +131,62 @@ AudioSource::AudioSource( } } +#ifdef QCOM_ENHANCED_AUDIO +AudioSource::AudioSource( audio_source_t inputSource, const sp<MetaData>& meta ) + : mStarted(false), + mPrevSampleTimeUs(0), + mNumFramesReceived(0), + mNumClientOwnedBuffers(0), + mFormat(AUDIO_FORMAT_PCM_16_BIT), + mMime(MEDIA_MIMETYPE_AUDIO_RAW) { + + const char * mime; + ALOGE("SK: in AudioSource : inputSource: %d", inputSource); + CHECK( meta->findCString( kKeyMIMEType, &mime ) ); + mMime = mime; + int32_t sampleRate = 0; //these are the only supported values + int32_t channels = 0; //for the below tunnel formats + CHECK( meta->findInt32( kKeyChannelCount, &channels ) ); + CHECK( meta->findInt32( kKeySampleRate, &sampleRate ) ); + int32_t frameSize = -1; + mSampleRate = sampleRate; + if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_NB ) ) { + mFormat = AUDIO_FORMAT_AMR_NB; + frameSize = AMR_FRAMESIZE; + mMaxBufferSize = AMR_FRAMESIZE*10; + } + else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_QCELP ) ) { + mFormat = AUDIO_FORMAT_QCELP; + frameSize = QCELP_FRAMESIZE; + mMaxBufferSize = QCELP_FRAMESIZE*10; + } + else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_EVRC ) ) { + mFormat = AUDIO_FORMAT_EVRC; + frameSize = EVRC_FRAMESIZE; + mMaxBufferSize = EVRC_FRAMESIZE*10; + } + else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_WB ) ) { + mFormat = AUDIO_FORMAT_AMR_WB; + frameSize = AMR_WB_FRAMESIZE; + mMaxBufferSize = AMR_WB_FRAMESIZE*10; + } + else { + CHECK(0); + } + mAutoRampStartUs = 0; + CHECK(channels == 1 || channels == 2); + + mRecord = new AudioRecord( + inputSource, sampleRate, mFormat, + channels > 1? AUDIO_CHANNEL_IN_STEREO: + AUDIO_CHANNEL_IN_MONO, + 4*mMaxBufferSize/channels/frameSize, + AudioRecordCallbackFunction, + this); + mInitCheck = mRecord->initCheck(); +} +#endif + AudioSource::~AudioSource() { if (mStarted) { reset(); @@ -184,10 +272,17 @@ sp<MetaData> AudioSource::getFormat() { } sp<MetaData> meta = new MetaData; +#ifdef QCOM_ENHANCED_AUDIO + meta->setCString(kKeyMIMEType, mMime); + meta->setInt32(kKeySampleRate, mRecord->getSampleRate()); + meta->setInt32(kKeyChannelCount, mRecord->channelCount()); + meta->setInt32(kKeyMaxInputSize, mMaxBufferSize); +#else meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); meta->setInt32(kKeySampleRate, mSampleRate); meta->setInt32(kKeyChannelCount, mRecord->channelCount()); meta->setInt32(kKeyMaxInputSize, kMaxBufferSize); +#endif return meta; } @@ -234,7 +329,9 @@ status_t AudioSource::read( } while (mStarted && mBuffersReceived.empty()) { - mFrameAvailableCondition.wait(mLock); + status_t err = mFrameAvailableCondition.waitRelative(mLock,WaitLockEventTimeOutNs); + if(err == -ETIMEDOUT) + return (status_t)err; } if (!mStarted) { return OK; @@ -249,24 +346,33 @@ status_t AudioSource::read( int64_t timeUs; CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); int64_t elapsedTimeUs = timeUs - mStartTimeUs; - if (elapsedTimeUs < mAutoRampStartUs) { - memset((uint8_t *) buffer->data(), 0, buffer->range_length()); - } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) { - int32_t autoRampDurationFrames = - (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; - - int32_t autoRampStartFrames = - (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; - - int32_t nFrames = mNumFramesReceived - autoRampStartFrames; - rampVolume(nFrames, autoRampDurationFrames, - (uint8_t *) buffer->data(), buffer->range_length()); +#ifdef QCOM_ENHANCED_AUDIO + if ( mFormat == AUDIO_FORMAT_PCM_16_BIT ) { +#endif + if (elapsedTimeUs < mAutoRampStartUs) { + memset((uint8_t *) buffer->data(), 0, buffer->range_length()); + } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) { + int32_t autoRampDurationFrames = + (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; + + int32_t autoRampStartFrames = + (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; + + int32_t nFrames = mNumFramesReceived - autoRampStartFrames; + rampVolume(nFrames, autoRampDurationFrames, + (uint8_t *) buffer->data(), buffer->range_length()); + } +#ifdef QCOM_ENHANCED_AUDIO } +#endif // Track the max recording signal amplitude. if (mTrackMaxAmplitude) { - trackMaxAmplitude( - (int16_t *) buffer->data(), buffer->range_length() >> 1); +#ifdef QCOM_ENHANCED_AUDIO + if (mFormat == AUDIO_FORMAT_PCM_16_BIT) +#endif + trackMaxAmplitude( + (int16_t *) buffer->data(), buffer->range_length() >> 1); } *out = buffer; @@ -321,7 +427,9 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { } CHECK_EQ(numLostBytes & 1, 0u); +#ifndef QCOM_ENHANCED_AUDIO CHECK_EQ(audioBuffer.size & 1, 0u); +#endif if (numLostBytes > 0) { // Loss of audio frames should happen rarely; thus the LOGW should // not cause a logging spam @@ -359,19 +467,45 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) { const size_t bufferSize = buffer->range_length(); const size_t frameSize = mRecord->frameSize(); +#ifdef QCOM_ENHANCED_AUDIO + int64_t timestampUs = mPrevSampleTimeUs; + int64_t recordDurationUs = 0; + if ( mFormat == AUDIO_FORMAT_PCM_16_BIT ){ + recordDurationUs = ((1000000LL * (bufferSize / (2 * mRecord->channelCount()))) + + (mSampleRate >> 1)) / mSampleRate; + } else { + recordDurationUs = bufferDurationUs(bufferSize); + } + timestampUs += recordDurationUs; +#else const int64_t timestampUs = mPrevSampleTimeUs + ((1000000LL * (bufferSize / frameSize)) + (mSampleRate >> 1)) / mSampleRate; +#endif if (mNumFramesReceived == 0) { buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs); } buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); - buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs); +#ifdef QCOM_ENHANCED_AUDIO + if (mFormat == AUDIO_FORMAT_PCM_16_BIT) { +#endif + buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs); +#ifdef QCOM_ENHANCED_AUDIO + } else { + int64_t wallClockTimeUs = timeUs - mInitialReadTimeUs; + int64_t mediaTimeUs = mStartTimeUs + mPrevSampleTimeUs; + buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs); + } +#endif mPrevSampleTimeUs = timestampUs; +#ifdef QCOM_ENHANCED_AUDIO + mNumFramesReceived += buffer->range_length() / sizeof(int16_t); +#else mNumFramesReceived += bufferSize / frameSize; +#endif mBuffersReceived.push_back(buffer); mFrameAvailableCondition.signal(); } @@ -399,4 +533,27 @@ int16_t AudioSource::getMaxAmplitude() { return value; } +#ifdef QCOM_ENHANCED_AUDIO +int64_t AudioSource::bufferDurationUs( ssize_t n ) { + + int64_t dataDurationMs = 0; + if (mFormat == AUDIO_FORMAT_AMR_NB) { + dataDurationMs = (n/AMR_FRAMESIZE) * 20; //ms + } + else if (mFormat == AUDIO_FORMAT_EVRC) { + dataDurationMs = (n/EVRC_FRAMESIZE) * 20; //ms + } + else if (mFormat == AUDIO_FORMAT_QCELP) { + dataDurationMs = (n/QCELP_FRAMESIZE) * 20; //ms + } + else if (mFormat == AUDIO_FORMAT_AMR_WB) { + dataDurationMs = (n/AMR_WB_FRAMESIZE) * 20; //ms + } + + else + CHECK(0); + + return dataDurationMs*1000LL; +} +#endif } // namespace android |