Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b556f5df authored by Alexy Joseph's avatar Alexy Joseph Committed by Gerrit - the friendly Code Review server
Browse files

libstagefright: Aggregate buffers in audio source

 -AudioSource currently receives callback whenever
  Audiorecord callback has data. The callbacks are
  with very small buffer sizes. These small buffer
  sizes lead to increase in number of messages that
  have to be passed between components. This leads
  to increase in power especially in camcorder
  use cases.
- To solve this, camcorder use cases configure
  AudioRecord in TRANSFER_SYNC mode so that
  buffers are aggregated inside AudioRecord.
  Soundrecorder, VOIP use cases are left untouched
  and continue to use TRANSFER_CALLBACK
Change-Id: Ie79028357656623e241c11bd017c69753f25d964
parent 908070d0
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ struct AudioSource : public MediaSource, public MediaBufferObserver {
            MediaBuffer **buffer, const ReadOptions *options = NULL);

    status_t dataCallback(const AudioRecord::Buffer& buffer);
    virtual void onEvent(int event, void* info);
    virtual void signalBufferReturned(MediaBuffer *buffer);

protected:
@@ -60,7 +61,9 @@ protected:

private:
    enum {
        kMaxBufferSize = 2048,
        //This max buffer size is derived from aggregation of audio
        //buffers for max duration 80 msec with 48K sampling rate.
        kMaxBufferSize = 30720,

        // After the initial mute, we raise the volume linearly
        // over kAutoRampDurationUs.
@@ -75,6 +78,11 @@ private:
    Condition mFrameAvailableCondition;
    Condition mFrameEncodingCompletionCondition;

    AudioRecord::Buffer mTempBuf;
    uint32_t mPrevPosition;
    uint32_t mAllocBytes;
    int32_t mAudioSessionId;
    AudioRecord::transfer_type mTransferMode;
    sp<AudioRecord> mRecord;
    status_t mInitCheck;
    bool mStarted;
@@ -91,7 +99,6 @@ private:
    int64_t mAutoRampStartUs;

    List<MediaBuffer * > mBuffersReceived;

    void trackMaxAmplitude(int16_t *data, int nSamples);

    // This is used to raise the volume from mute to the
+138 −20
Original line number Diff line number Diff line
@@ -31,23 +31,12 @@
#include <cutils/properties.h>
#include <system/audio.h>

#define AUDIO_RECORD_DEFAULT_BUFFER_DURATION 20
namespace android {

static void AudioRecordCallbackFunction(int event, void *user, void *info) {
    AudioSource *source = (AudioSource *) user;
    switch (event) {
        case AudioRecord::EVENT_MORE_DATA: {
            source->dataCallback(*((AudioRecord::Buffer *) info));
            break;
        }
        case AudioRecord::EVENT_OVERRUN: {
            ALOGW("AudioRecord reported overrun!");
            break;
        }
        default:
            // does nothing
            break;
    }
    source->onEvent(event, info);
}

AudioSource::AudioSource(
@@ -80,6 +69,60 @@ AudioSource::AudioSource(
            bufCount++;
        }

        mTempBuf.size = 0;
        mTempBuf.frameCount = 0;
        mTempBuf.i16 = (short*)NULL;
        mPrevPosition = 0;
        mAudioSessionId = -1;
        mAllocBytes = 0;
        mTransferMode = AudioRecord::TRANSFER_CALLBACK;

        //decide whether to use callback or event pos callback
        //use position marker only for PCM 16 bit and mono or stereo capture
        //and if input source is camera
        if((mFormat == AUDIO_FORMAT_PCM_16_BIT) &&
            ((channelCount == 1) || (channelCount == 2)) &&
            (inputSource == AUDIO_SOURCE_CAMCORDER)) {

            //Need audioSession Id in the extended audio record constructor
            //where the transfer mode can be specified
            mAudioSessionId = AudioSystem::newAudioUniqueId();
            AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);

            mRecord = new AudioRecord(
                        inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                        audio_channel_in_mask_from_count(channelCount),
                        (size_t) (bufCount * frameCount),
                        AudioRecordCallbackFunction,
                        this,
                        frameCount /*notificationFrames*/,
                        mAudioSessionId,
                        AudioRecord::TRANSFER_SYNC,
                        AUDIO_INPUT_FLAG_NONE);

            int buffDuration = AUDIO_RECORD_DEFAULT_BUFFER_DURATION;
            char propValue[PROPERTY_VALUE_MAX];
            if (property_get("audio.record.buffer.duration", propValue, NULL)) {
                if (atoi(propValue) < AUDIO_RECORD_DEFAULT_BUFFER_DURATION)
                    buffDuration = AUDIO_RECORD_DEFAULT_BUFFER_DURATION;
                else
                    buffDuration = atoi(propValue);
            }
            else
                buffDuration = AUDIO_RECORD_DEFAULT_BUFFER_DURATION;

            //set to update position after frames worth of buffduration time for 16 bits
            mAllocBytes = ((sizeof(uint8_t) * frameCount * 2 * channelCount));
            ALOGI("AudioSource in TRANSFER_SYNC with duration %d ms", buffDuration);
            mTempBuf.i16 = (short*) malloc(mAllocBytes);
            if (mTempBuf.i16 == NULL) {
                mAllocBytes = 0;
                mInitCheck = NO_MEMORY;
            }
            mTransferMode = AudioRecord::TRANSFER_SYNC;
            mRecord->setPositionUpdatePeriod((sampleRate * buffDuration)/1000);
        } else {
            //Sound recorder and VOIP use cases does NOT use aggregation
            mRecord = new AudioRecord(
                        inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                        audio_channel_in_mask_from_count(channelCount),
@@ -87,7 +130,12 @@ AudioSource::AudioSource(
                        AudioRecordCallbackFunction,
                        this,
                        frameCount /*notificationFrames*/);
            ALOGI("AudioSource in TRANSFER_CALLBACK");
            mTransferMode = AudioRecord::TRANSFER_CALLBACK;
        }

        mInitCheck = mRecord->initCheck();

        mAutoRampStartUs = kAutoRampStartUs;
        uint32_t playbackLatencyMs = 0;
        if (AudioSystem::getOutputLatency(&playbackLatencyMs,
@@ -100,6 +148,7 @@ AudioSource::AudioSource(
    } else {
        mInitCheck = status;
    }
    ALOGV("mInitCheck %d", mInitCheck);
}

AudioSource::AudioSource( audio_source_t inputSource, const sp<MetaData>& meta )
@@ -137,6 +186,14 @@ AudioSource::AudioSource( audio_source_t inputSource, const sp<MetaData>& meta )
                AudioRecordCallbackFunction,
                this);
    mInitCheck = mRecord->initCheck();
    mTempBuf.size = 0;
    mTempBuf.frameCount = 0;
    mTempBuf.i16 = (short*)NULL;
    mPrevPosition = 0;
    mAudioSessionId = -1;
    mAllocBytes = 0;
    mTransferMode = AudioRecord::TRANSFER_CALLBACK;

}

AudioSource::~AudioSource() {
@@ -223,6 +280,16 @@ status_t AudioSource::reset() {
    waitOutstandingEncodingFrames_l();
    releaseQueuedFrames_l();

    if (mTransferMode == AudioRecord::TRANSFER_SYNC) {
        if(mAudioSessionId != -1)
            AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);

        mAudioSessionId = -1;
        if(mTempBuf.i16) {
            free(mTempBuf.i16);
            mTempBuf.i16 = (short*)NULL;
        }
    }
    return OK;
}

@@ -408,6 +475,57 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) {
    return OK;
}

void AudioSource::onEvent(int event, void* info) {

    switch (event) {
        case AudioRecord::EVENT_MORE_DATA: {
            dataCallback(*((AudioRecord::Buffer *) info));
            break;
        }
        case AudioRecord::EVENT_NEW_POS: {
            uint32_t position = 0;
            mRecord->getPosition(&position);
            size_t framestoRead = position - mPrevPosition;
            size_t bytestoRead = (framestoRead * 2 * mRecord->channelCount());
            if(bytestoRead <=0 || bytestoRead > mAllocBytes) {
                //try to read only max
                ALOGI("greater than allocated size in callback, adjusting size");
                bytestoRead =  mAllocBytes;
                framestoRead = (mAllocBytes / (2 * mRecord->channelCount()));
            }

            if(mTempBuf.i16 && framestoRead > 0) {
                //read only if you have valid data
                size_t bytesRead = mRecord->read(mTempBuf.i16, framestoRead);
                size_t framesRead = 0;
                ALOGV("event_new_pos, new pos %d, frames to read %d\n", \
                        position, framestoRead);
                ALOGV("bytes read = %d \n", bytesRead);
                if(bytesRead > 0){
                    framesRead = (bytesRead / (2 * mRecord->channelCount()));
                    mPrevPosition += framesRead;
                    mTempBuf.size = bytesRead;
                    mTempBuf.frameCount = framesRead;
                    dataCallback(mTempBuf);
                } else {
                    ALOGE("EVENT_NEW_POS did not return any data");
                }
            } else {
                ALOGE("Init error");
            }
            break;
        }
        case AudioRecord::EVENT_OVERRUN: {
            ALOGW("AudioRecord reported overrun!");
            break;
        }
        default:
            // does nothing
            break;
    }
    return;
}

void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) {
    if (mRecPaused) {
        if (!mBuffersReceived.empty()) {