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

Commit c92fd24c authored by Andreas Huber's avatar Andreas Huber
Browse files

Error handling in ACodec and Nuplayer.

Codec errors (and codec not found errors) now trigger a controlled shutdown
of playback and signal errors to the MediaPlayer client.

Change-Id: I2ee23ff2a1422d05a1a21e50ecb87d7c7ab958cc
parent a5cc7cce
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct ACodec : public AHierarchicalStateMachine {
        kWhatShutdownCompleted   = 'scom',
        kWhatFlushCompleted      = 'fcom',
        kWhatOutputFormatChanged = 'outC',
        kWhatError               = 'erro',
    };

    ACodec();
@@ -58,7 +59,6 @@ private:
    struct OutputPortSettingsChangedState;
    struct ExecutingToIdleState;
    struct IdleToLoadedState;
    struct ErrorState;
    struct FlushingState;

    enum {
@@ -102,7 +102,6 @@ private:
    sp<OutputPortSettingsChangedState> mOutputPortSettingsChangedState;
    sp<ExecutingToIdleState> mExecutingToIdleState;
    sp<IdleToLoadedState> mIdleToLoadedState;
    sp<ErrorState> mErrorState;
    sp<FlushingState> mFlushingState;

    AString mComponentName;
+17 −1
Original line number Diff line number Diff line
@@ -340,6 +340,11 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                }

                finishFlushIfPossible();
            } else if (what == ACodec::kWhatError) {
                LOGE("Received error from %s decoder, aborting playback.",
                     audio ? "audio" : "video");

                mRenderer->queueEOS(audio, UNKNOWN_ERROR);
            } else {
                CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer);

@@ -358,13 +363,24 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                int32_t audio;
                CHECK(msg->findInt32("audio", &audio));

                int32_t finalResult;
                CHECK(msg->findInt32("finalResult", &finalResult));

                if (audio) {
                    mAudioEOS = true;
                } else {
                    mVideoEOS = true;
                }

                if (finalResult == ERROR_END_OF_STREAM) {
                    LOGV("reached %s EOS", audio ? "audio" : "video");
                } else {
                    LOGE("%s track encountered an error (0x%08x)",
                         audio ? "audio" : "video", finalResult);

                    notifyListener(
                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult);
                }

                if ((mAudioEOS || mAudioDecoder == NULL)
                        && (mVideoEOS || mVideoDecoder == NULL)) {
+17 −16
Original line number Diff line number Diff line
@@ -200,19 +200,6 @@ 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);

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

        if (numBytesAvailableToWrite == 0) {
            break;
        }

        if (mAudioQueue.empty()) {
            break;
        }
@@ -222,13 +209,26 @@ void NuPlayer::Renderer::onDrainAudioQueue() {
        if (entry->mBuffer == NULL) {
            // EOS

            notifyEOS(true /* audio */);
            notifyEOS(true /* audio */, entry->mFinalResult);

            mAudioQueue.erase(mAudioQueue.begin());
            entry = NULL;
            return;
        }

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

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

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

        if (numBytesAvailableToWrite == 0) {
            break;
        }

        if (entry->mOffset == 0) {
            int64_t mediaTimeUs;
            CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
@@ -330,7 +330,7 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
    if (entry->mBuffer == NULL) {
        // EOS

        notifyEOS(false /* audio */);
        notifyEOS(false /* audio */, entry->mFinalResult);

        mVideoQueue.erase(mVideoQueue.begin());
        entry = NULL;
@@ -352,10 +352,11 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
    notifyPosition();
}

void NuPlayer::Renderer::notifyEOS(bool audio) {
void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
    sp<AMessage> notify = mNotify->dup();
    notify->setInt32("what", kWhatEOS);
    notify->setInt32("audio", static_cast<int32_t>(audio));
    notify->setInt32("finalResult", finalResult);
    notify->post();
}

+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ private:
    void onPause();
    void onResume();

    void notifyEOS(bool audio);
    void notifyEOS(bool audio, status_t finalResult);
    void notifyFlushComplete(bool audio);
    void notifyPosition();

+28 −46
Original line number Diff line number Diff line
@@ -285,21 +285,6 @@ private:

////////////////////////////////////////////////////////////////////////////////

struct ACodec::ErrorState : public ACodec::BaseState {
    ErrorState(ACodec *codec);

protected:
    virtual bool onMessageReceived(const sp<AMessage> &msg);
    virtual void stateEntered();

    virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);

private:
    DISALLOW_EVIL_CONSTRUCTORS(ErrorState);
};

////////////////////////////////////////////////////////////////////////////////

struct ACodec::FlushingState : public ACodec::BaseState {
    FlushingState(ACodec *codec);

@@ -335,7 +320,6 @@ ACodec::ACodec()

    mExecutingToIdleState = new ExecutingToIdleState(this);
    mIdleToLoadedState = new IdleToLoadedState(this);
    mErrorState = new ErrorState(this);
    mFlushingState = new FlushingState(this);

    mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false;
@@ -594,7 +578,10 @@ status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) {

ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
    ANativeWindowBuffer *buf;
    CHECK_EQ(mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf), 0);
    if (mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf) != 0) {
        LOGE("dequeueBuffer failed.");
        return NULL;
    }

    for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
        BufferInfo *info =
@@ -1263,10 +1250,12 @@ bool ACodec::BaseState::onOMXEvent(
        return false;
    }

    LOGE("[%s] ERROR(0x%08lx, 0x%08lx)",
         mCodec->mComponentName.c_str(), data1, data2);
    LOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1);

    mCodec->changeState(mCodec->mErrorState);
    sp<AMessage> notify = mCodec->mNotify->dup();
    notify->setInt32("what", ACodec::kWhatError);
    notify->setInt32("omx-error", data1);
    notify->post();

    return true;
}
@@ -1595,6 +1584,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
                    info = mCodec->dequeueBufferFromNativeWindow();
                }

                if (info != NULL) {
                    LOGV("[%s] calling fillBuffer %p",
                         mCodec->mComponentName.c_str(), info->mBufferID);

@@ -1603,6 +1593,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {

                    info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
                }
            }
            break;
        }

@@ -1642,6 +1633,7 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
            notify->post();

            handled = true;
            break;
        }

        case ACodec::kWhatFlush:
@@ -1651,6 +1643,7 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
            notify->post();

            handled = true;
            break;
        }

        default:
@@ -1696,7 +1689,16 @@ void ACodec::UninitializedState::onSetup(
        node = NULL;
    }

    CHECK(node != NULL);
    if (node == NULL) {
        LOGE("Unable to instantiate a decoder for type '%s'.", mime.c_str());

        sp<AMessage> notify = mCodec->mNotify->dup();
        notify->setInt32("what", ACodec::kWhatError);
        notify->setInt32("omx-error", OMX_ErrorComponentNotFound);
        notify->post();

        return;
    }

    sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id());
    observer->setNotificationMessage(notify);
@@ -2236,26 +2238,6 @@ bool ACodec::IdleToLoadedState::onOMXEvent(

////////////////////////////////////////////////////////////////////////////////

ACodec::ErrorState::ErrorState(ACodec *codec)
    : BaseState(codec) {
}

bool ACodec::ErrorState::onMessageReceived(const sp<AMessage> &msg) {
    return BaseState::onMessageReceived(msg);
}

void ACodec::ErrorState::stateEntered() {
    LOGV("[%s] Now in ErrorState", mCodec->mComponentName.c_str());
}

bool ACodec::ErrorState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    LOGV("EVENT(%d, 0x%08lx, 0x%08lx)", event, data1, data2);
    return true;
}

////////////////////////////////////////////////////////////////////////////////

ACodec::FlushingState::FlushingState(ACodec *codec)
    : BaseState(codec) {
}