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

Commit 6667ac33 authored by Eric Laurent's avatar Eric Laurent
Browse files

Fix issue 3483718: audio streaming and A2DP.

The problem is that when switching from A2DP to device speakers or headset,
The AudioTrack binder interface to AudioFlinger must be destroyed and restored
to accomodate new buffer size requirements. Current AudioTrack implementation
did not restore properly the PCM buffer write index which caused a mismatch between
the written frame count in the mediaplayer renderer and the AudioTrack. The renderer
could then believe the AudioTrack buffer was full and stop writing data preventing the
AudioTrack to reach a bufffer full condition and resume playback.

The rendered was also modified to refresh the AudioTrack frame count (buffer size)
inside the write loop in NuPlayer::Renderer::onDrainAudioQueue() as this count can change
from one write to the next.

Also modified AudioTrack::obtainBuffer() to check for track invalidated status before
querying for available space in the buffer. This avoids writing to the old track's
buffer until full before detecting the invalidated condition and create a new track.

Change-Id: I16a857e464e466880847f52f640820aa271539ad
parent affb58e7
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -546,7 +546,8 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou
    }

    if (loopStart >= loopEnd ||
        loopEnd - loopStart > cblk->frameCount) {
        loopEnd - loopStart > cblk->frameCount ||
        cblk->server > loopStart) {
        LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user);
        return BAD_VALUE;
    }
@@ -825,6 +826,12 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)

    uint32_t framesAvail = cblk->framesAvailable();

    cblk->lock.lock();
    if (cblk->flags & CBLK_INVALID_MSK) {
        goto create_new_track;
    }
    cblk->lock.unlock();

    if (framesAvail == 0) {
        cblk->lock.lock();
        goto start_loop_here;
@@ -1148,6 +1155,7 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
             fromStart ? "start()" : "obtainBuffer()");

        cblk->flags |= CBLK_RESTORING_ON;

        // signal old cblk condition so that other threads waiting for available buffers stop
        // waiting now
        cblk->cv.broadcast();
@@ -1167,10 +1175,20 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
                               false);

        if (result == NO_ERROR) {
            // restore write index and set other indexes to reflect empty buffer status
            mCblk->user = cblk->user;
            mCblk->server = cblk->user;
            mCblk->userBase = cblk->user;
            mCblk->serverBase = cblk->user;
            // restore loop: this is not guaranteed to succeed if new frame count is not
            // compatible with loop length
            setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount);
            if (!fromStart) {
                mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
            }
            if (mActive) {
                result = mAudioTrack->start();
            }
            if (fromStart && result == NO_ERROR) {
                mNewPosition = mCblk->server + mUpdatePeriod;
            }
+12 −9
Original line number Diff line number Diff line
@@ -198,18 +198,21 @@ void NuPlayer::Renderer::signalAudioSinkChanged() {
}

void NuPlayer::Renderer::onDrainAudioQueue() {

    for (;;) {
        uint32_t numFramesPlayed;
        CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);

        ssize_t numFramesAvailableToWrite =
            mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);

    CHECK_GE(numFramesAvailableToWrite, 0);

        size_t numBytesAvailableToWrite =
            numFramesAvailableToWrite * mAudioSink->frameSize();

    while (numBytesAvailableToWrite > 0) {
        if (numBytesAvailableToWrite == 0) {
            break;
        }

        if (mAudioQueue.empty()) {
            break;
        }
@@ -264,10 +267,10 @@ void NuPlayer::Renderer::onDrainAudioQueue() {
        if (entry->mOffset == entry->mBuffer->size()) {
            entry->mNotifyConsumed->post();
            mAudioQueue.erase(mAudioQueue.begin());

            entry = NULL;
        }

        numBytesAvailableToWrite -= copy;
        mNumFramesWritten += copy / mAudioSink->frameSize();
    }