void DecodedStream::Stop() { AssertOwnerThread(); MOZ_ASSERT(mStartTime.isSome(), "playback not started."); mStartTime.reset(); DisconnectListener(); mFinishPromise = nullptr; // Clear mData immediately when this playback session ends so we won't // send data to the wrong stream in SendData() in next playback session. DestroyData(Move(mData)); }
void VideoSink::Stop() { AssertOwnerThread(); MOZ_ASSERT(mAudioSink->IsStarted(), "playback not started."); VSINK_LOG("[%s]", __func__); mAudioSink->Stop(); mUpdateScheduler.Reset(); if (mHasVideo) { DisconnectListener(); mEndPromiseHolder.Resolve(true, __func__); mEndPromise = nullptr; } mVideoFrameEndTime = -1; }
void DecodedAudioDataSink::AudioLoop() { AssertOnAudioThread(); mAudioLoopScheduled = false; switch (mState) { case AUDIOSINK_STATE_INIT: { SINK_LOG("AudioLoop started"); nsresult rv = InitializeAudioStream(); if (NS_FAILED(rv)) { NS_WARNING("Initializing AudioStream failed."); mEndPromise.Reject(rv, __func__); SetState(AUDIOSINK_STATE_ERROR); break; } SetState(AUDIOSINK_STATE_PLAYING); ConnectListener(); break; } case AUDIOSINK_STATE_PLAYING: { if (WaitingForAudioToPlay()) { // OnAudioQueueEvent() will schedule next loop. break; } if (!IsPlaybackContinuing()) { SetState(AUDIOSINK_STATE_COMPLETE); break; } if (!PlayAudio()) { SetState(AUDIOSINK_STATE_COMPLETE); break; } // Schedule next loop to play next sample. ScheduleNextLoop(); break; } case AUDIOSINK_STATE_COMPLETE: { DisconnectListener(); FinishAudioLoop(); SetState(AUDIOSINK_STATE_SHUTDOWN); break; } case AUDIOSINK_STATE_SHUTDOWN: break; case AUDIOSINK_STATE_ERROR: break; } // end of switch // We want mState to stay stable during AudioLoop to keep things simple. // Therefore, we only do state transition at the end of AudioLoop. if (mPendingState.isSome()) { MOZ_ASSERT(mState != mPendingState.ref()); SINK_LOG("change mState, %d -> %d", mState, mPendingState.ref()); mState = mPendingState.ref(); mPendingState.reset(); // Schedule next loop when state changes. ScheduleNextLoop(); } }