summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/AudioSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/AudioSource.cpp')
-rw-r--r--media/libstagefright/AudioSource.cpp195
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