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

Commit c1d0d36d authored by lubiny's avatar lubiny Committed by Steve Kondik
Browse files

NuPlayer: add implementations of suspend/resume APIs

- API:suspend() will just pause the player and release all the decoders
  to replace reset() which will release the whole player
- API:resume() will just init the decoders again, then start() will be
  called to start to play the streaming

CRs-Fixed: 587059
Change-Id: Ib57625109ea993dc0ae6f298386d09c807d42455
parent d23e63be
Loading
Loading
Loading
Loading
+56 −2
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ NuPlayer::GenericSource::GenericSource(
      mMetaDataSize(-1ll),
      mBitrate(-1ll),
      mPollBufferingGeneration(0),
      mPendingReadBufferTypes(0) {
      mPendingReadBufferTypes(0),
      mStartAfterSuspended(false) {
    resetDataSource();
    DataSource::RegisterDefaultSniffers();
}
@@ -273,6 +274,47 @@ status_t NuPlayer::GenericSource::setBuffers(
    return INVALID_OPERATION;
}

status_t NuPlayer::GenericSource::suspend() {
    ALOGV("suspend");
    if (mCachedSource == NULL) {
        ALOGE("suspend when mCachedSource doesn't exist");
        return INVALID_OPERATION;
    }

    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
    mStarted = false;
    if (mIsWidevine) {
        // For a widevine source we need to prevent any further reads.
        sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
        sp<AMessage> response;
        (void) msg->postAndAwaitResponse(&response);
    }

    cancelPollBuffering();

    return mCachedSource->disconnectWhileSuspend();
}

status_t NuPlayer::GenericSource::resumeFromSuspended() {
    ALOGV("resumeFromSuspended");
    status_t err = OK;
    if (mCachedSource == NULL) {
        ALOGE("resumeFromSuspended when mCachedSource doesn't exist");
        return INVALID_OPERATION;
    } else {
        err = mCachedSource->connectWhileResume();
    }

    if (err != OK) {
        return err;
    }

    setDrmPlaybackStatusIfNeeded(Playback::PAUSE, getLastReadPosition() / 1000);
    mStartAfterSuspended = true;
    schedulePollBuffering();
    return OK;
}

NuPlayer::GenericSource::~GenericSource() {
    if (mLooper != NULL) {
        mLooper->unregisterHandler(id());
@@ -467,6 +509,13 @@ void NuPlayer::GenericSource::start() {
    ALOGI("start");

    mStopRead = false;

    if (mStartAfterSuspended) {
        setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
        mStarted = true;
        return;
    }

    if (mAudioTrack.mSource != NULL) {
        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);

@@ -1154,6 +1203,7 @@ status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
    if (!mStarted) {
        setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
    }
    mStartAfterSuspended = false;
    return OK;
}

@@ -1294,7 +1344,11 @@ void NuPlayer::GenericSource::readBuffer(
    bool seeking = false;

    if (seekTimeUs >= 0) {
        if (mStartAfterSuspended) {
            options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
        } else {
            options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
        }
        seeking = true;
    }

+5 −0
Original line number Diff line number Diff line
@@ -72,6 +72,9 @@ struct NuPlayer::GenericSource : public NuPlayer::Source {

    virtual status_t setBuffers(bool audio, Vector<MediaBuffer *> &buffers);

    virtual status_t suspend();
    virtual status_t resumeFromSuspended();

protected:
    virtual ~GenericSource();

@@ -144,6 +147,8 @@ private:

    sp<ALooper> mLooper;

    bool mStartAfterSuspended;

    void resetDataSource();

    status_t initFromDataSource();
+130 −1
Original line number Diff line number Diff line
@@ -183,7 +183,9 @@ NuPlayer::NuPlayer()
      mStarted(false),
      mBuffering(false),
      mPlaying(false),
      mImageShowed(false) {
      mImageShowed(false),
      mSkipAudioFlushAfterSuspend(false),
      mSkipVideoFlushAfterSuspend(false) {

    clearFlushComplete();
    mPlayerExtendedStats = (PlayerExtendedStats *)ExtendedStats::Create(
@@ -1094,6 +1096,35 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
            break;
        }

        case kWhatSuspend:
        {
            ALOGV("kWhatSuspend");

            mDeferredActions.push_back(
                    new ShutdownDecoderAction(
                        true /* audio */, true /* video */));

            mDeferredActions.push_back(
                    new SimpleAction(&NuPlayer::performSuspend));

            processDeferredActions();
            break;
        }

        case kWhatResumeFromSuspended:
        {
            ALOGV("kWhatResumeFromSuspended");

            mDeferredActions.push_back(
                    new SimpleAction(&NuPlayer::performResumeFromSuspended));

            mDeferredActions.push_back(
                    new SimpleAction(&NuPlayer::performScanSources));

            processDeferredActions();
            break;
        }

        default:
            TRESPASS();
            break;
@@ -1380,6 +1411,23 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
                ALOGI("%s discontinuity (formatChange=%d, time=%d)",
                     audio ? "audio" : "video", formatChange, timeChange);

                if (!formatChange && timeChange) {
                    if (audio && mSkipAudioFlushAfterSuspend) {
                        ALOGV("Skip audio flush for seek after suspend");
                        mSkipAudioFlushAfterSuspend = false;
                        reply->setInt32("err", OK);
                        reply->post();
                        return OK;
                    }
                    if (!audio && mSkipVideoFlushAfterSuspend) {
                        ALOGV("Skip video flush for seek after suspend");
                        mSkipVideoFlushAfterSuspend = false;
                        reply->setInt32("err", OK);
                        reply->post();
                        return OK;
                    }
                }

                if (audio) {
                    mSkipRenderingAudioUntilMediaTimeUs = -1;
                } else {
@@ -2001,6 +2049,79 @@ void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) {
    }
}

void NuPlayer::performSuspend() {
    ALOGV("performSuspsend");

    CHECK(mAudioDecoder == NULL);
    CHECK(mVideoDecoder == NULL);

    cancelPollDuration();

    ++mScanSourcesGeneration;
    mScanSourcesPending = false;

    if (mRenderer != NULL) {
        mRenderer->pause();
    }
    if (mRendererLooper != NULL) {
        if (mRenderer != NULL) {
            mRendererLooper->unregisterHandler(mRenderer->id());
        }
        mRendererLooper->stop();
        mRendererLooper.clear();
    }

    status_t err;
    if (mSource == NULL) {
        ALOGE("suspend called when source is gone or not set");
        err = UNKNOWN_ERROR;
    } else {
        err = mSource->suspend();
    }

    if (mDriver != NULL) {
        sp<NuPlayerDriver> driver = mDriver.promote();
        if (driver != NULL) {
            driver->notifySuspendCompleted(err);
        }
    }

    mStarted = false;
}

void NuPlayer::performResumeFromSuspended() {
    ALOGV("performResumeFromSuspended");

    CHECK(mAudioDecoder == NULL);
    CHECK(mVideoDecoder == NULL);
    CHECK(mRendererLooper == NULL);

    status_t err;
    if (mSource == NULL) {
        ALOGE("resumeFromSuspended called when source is gone or not set");
        err = UNKNOWN_ERROR;
    } else {
        err = mSource->resumeFromSuspended();
    }

    if (err == OK) {
        mRendererLooper = new ALooper;
        mRendererLooper->setName("NuPlayerRenderer");
        mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
        mRendererLooper->registerHandler(mRenderer);
        mRenderer->resume();
        mSkipAudioFlushAfterSuspend = true;
        mSkipVideoFlushAfterSuspend = true;
    }

    if (mDriver != NULL) {
        sp<NuPlayerDriver> driver = mDriver.promote();
        if (driver != NULL) {
            driver->notifyResumeFromSuspendedCompleted(err);
        }
    }
}

void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
    int32_t what;
    CHECK(msg->findInt32("what", &what));
@@ -2311,4 +2432,12 @@ void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
    TRESPASS();
}

void NuPlayer::suspendAsync() {
    (new AMessage(kWhatSuspend, id()))->post();
}

void NuPlayer::resumeFromSuspendedAsync() {
    (new AMessage(kWhatResumeFromSuspended, id()))->post();
}

}  // namespace android
+11 −0
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ struct NuPlayer : public AHandler {

    int64_t getServerTimeoutUs();

    void suspendAsync();
    void resumeFromSuspendedAsync();

    static const size_t kAggregateBufferSizeBytes;

protected:
@@ -131,6 +134,8 @@ private:
        kWhatGetTrackInfo               = 'gTrI',
        kWhatGetSelectedTrack           = 'gSel',
        kWhatSelectTrack                = 'selT',
        kWhatSuspend                    = 'susp',
        kWhatResumeFromSuspended        = 'refs',
    };
    sp<PlayerExtendedStats> mPlayerExtendedStats;

@@ -203,6 +208,9 @@ private:

    bool mImageShowed;

    bool mSkipAudioFlushAfterSuspend;
    bool mSkipVideoFlushAfterSuspend;

    inline const sp<Decoder> &getDecoder(bool audio) {
        return audio ? mAudioDecoder : mVideoDecoder;
    }
@@ -251,6 +259,9 @@ private:
    void performScanSources();
    void performSetSurface(const sp<NativeWindowWrapper> &wrapper);

    void performSuspend();
    void performResumeFromSuspended();

    void onSourceNotify(const sp<AMessage> &msg);
    void onClosedCaptionNotify(const sp<AMessage> &msg);

+74 −0
Original line number Diff line number Diff line
@@ -361,6 +361,7 @@ status_t NuPlayerDriver::seekTo(int msec) {

    switch (mState) {
        case STATE_PREPARED:
        case STATE_SUSPENDED:
        {
            mStartupSeekTimeUs = seekTimeUs;
            // pretend that the seek completed. It will actually happen when starting playback.
@@ -729,4 +730,77 @@ void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
    mPlayerFlags = flags;
}

void NuPlayerDriver::notifySuspendCompleted(status_t err) {
    ALOGD("notifySuspendCompleted(%p, %d)", this, err);
    Mutex::Autolock autoLock(mLock);

    CHECK_EQ(mState, STATE_SUSPEND_IN_PROGRESS);
    mState = STATE_SUSPENDED;
    mAsyncResult = err;
    mCondition.broadcast();
}

void NuPlayerDriver::notifyResumeFromSuspendedCompleted(status_t err) {
    ALOGD("notifyResumeFromSuspendedCompleted(%p, %d)", this, err);
    Mutex::Autolock autoLock(mLock);

    CHECK_EQ(mState, STATE_RESUME_IN_PROGRESS);
    mState = STATE_PREPARED;
    mAsyncResult = err;
    mCondition.broadcast();
}

status_t NuPlayerDriver::suspend() {
    ALOGV("suspend");
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
        case STATE_SUSPENDED:
            return OK;

        case STATE_PREPARED:
        case STATE_PAUSED:
        case STATE_RUNNING:
        case STATE_STOPPED:
        case STATE_STOPPED_AND_PREPARING:
        case STATE_STOPPED_AND_PREPARED:
            ALOGV("suspend from state %d", mState);
            break;

        default:
            return INVALID_OPERATION;
    }

    mState = STATE_SUSPEND_IN_PROGRESS;
    mPlayer->suspendAsync();

    while (mState == STATE_SUSPEND_IN_PROGRESS) {
        mCondition.wait(mLock);
    }

    return mAsyncResult;
}

status_t NuPlayerDriver::resume() {
    ALOGV("resume");
    Mutex::Autolock autoLock(mLock);

    if (mState == STATE_PREPARED) {
        return OK;
    }

    if (mState != STATE_SUSPENDED) {
        return INVALID_OPERATION;
    }

    mState = STATE_RESUME_IN_PROGRESS;
    mPlayer->resumeFromSuspendedAsync();

    while (mState == STATE_RESUME_IN_PROGRESS) {
        mCondition.wait(mLock);
    }

    return mAsyncResult;
}

}  // namespace android
Loading