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

Commit 7d3f4df0 authored by Wei Jia's avatar Wei Jia
Browse files

mediaplayer: use non-blocking mode for AudioSink::write().

This cherry picks https://googleplex-android-review.git.corp.google.com/#/c/643541/ to master.

Bug: 19448263
Change-Id: I43dea830212de79c2b080185b6c6b36078f517d2
parent 1ba39920
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -113,7 +113,19 @@ public:
                const audio_offload_info_t *offloadInfo = NULL) = 0;

        virtual status_t    start() = 0;
        virtual ssize_t     write(const void* buffer, size_t size) = 0;

        /* Input parameter |size| is in byte units stored in |buffer|.
         * Data is copied over and actual number of bytes written (>= 0)
         * is returned, or no data is copied and a negative status code
         * is returned (even when |blocking| is true).
         * When |blocking| is false, AudioSink will immediately return after
         * part of or full |buffer| is copied over.
         * When |blocking| is true, AudioSink will wait to copy the entire
         * buffer, unless an error occurs or the copy operation is
         * prematurely stopped.
         */
        virtual ssize_t     write(const void* buffer, size_t size, bool blocking = true) = 0;

        virtual void        stop() = 0;
        virtual void        flush() = 0;
        virtual void        pause() = 0;
+2 −2
Original line number Diff line number Diff line
@@ -1672,13 +1672,13 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() {
    }
}

ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size, bool blocking)
{
    LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");

    //ALOGV("write(%p, %u)", buffer, size);
    if (mTrack != 0) {
        ssize_t ret = mTrack->write(buffer, size);
        ssize_t ret = mTrack->write(buffer, size, blocking);
        if (ret >= 0) {
            mBytesWritten += ret;
        }
+1 −1
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ class MediaPlayerService : public BnMediaPlayerService
                const audio_offload_info_t *offloadInfo = NULL);

        virtual status_t        start();
        virtual ssize_t         write(const void* buffer, size_t size);
        virtual ssize_t         write(const void* buffer, size_t size, bool blocking = true);
        virtual void            stop();
        virtual void            flush();
        virtual void            pause();
+16 −16
Original line number Diff line number Diff line
@@ -567,6 +567,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
}

bool NuPlayer::Renderer::onDrainAudioQueue() {
#if 0
    uint32_t numFramesPlayed;
    if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
        return false;
@@ -575,7 +576,6 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
    ssize_t numFramesAvailableToWrite =
        mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);

#if 0
    if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
        ALOGI("audio sink underrun");
    } else {
@@ -584,10 +584,7 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
    }
#endif

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

    while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
    while (!mAudioQueue.empty()) {
        QueueEntry *entry = &*mAudioQueue.begin();

        mLastAudioBufferDrained = entry->mBufferOrdinal;
@@ -620,14 +617,16 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
        }

        size_t copy = entry->mBuffer->size() - entry->mOffset;
        if (copy > numBytesAvailableToWrite) {
            copy = numBytesAvailableToWrite;
        }

        ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);
        ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset,
                                            copy, false /* blocking */);
        if (written < 0) {
            // An error in AudioSink write. Perhaps the AudioSink was not properly opened.
            if (written == WOULD_BLOCK) {
                ALOGW("AudioSink write would block when writing %zu bytes", copy);
            } else {
                ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
            }
            break;
        }

@@ -639,7 +638,6 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
            entry = NULL;
        }

        numBytesAvailableToWrite -= written;
        size_t copiedFrames = written / mAudioSink->frameSize();
        mNumFramesWritten += copiedFrames;

@@ -651,21 +649,23 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
        if (written != (ssize_t)copy) {
            // A short count was received from AudioSink::write()
            //
            // AudioSink write should block until exactly the number of bytes are delivered.
            // But it may return with a short count (without an error) when:
            // AudioSink write is called in non-blocking mode.
            // It may return with a short count when:
            //
            // 1) Size to be copied is not a multiple of the frame size. We consider this fatal.
            // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
            // 2) The data to be copied exceeds the available buffer in AudioSink.
            // 3) An error occurs and data has been partially copied to the buffer in AudioSink.
            // 4) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.

            // (Case 1)
            // Must be a multiple of the frame size.  If it is not a multiple of a frame size, it
            // needs to fail, as we should not carry over fractional frames between calls.
            CHECK_EQ(copy % mAudioSink->frameSize(), 0);

            // (Case 2)
            // (Case 2, 3, 4)
            // Return early to the caller.
            // Beware of calling immediately again as this may busy-loop if you are not careful.
            ALOGW("AudioSink write short frame count %zd < %zu", written, copy);
            ALOGV("AudioSink write short frame count %zd < %zu", written, copy);
            break;
        }
    }