LCOV - code coverage report
Current view: top level - dom/media - MediaDecoderStateMachine.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1853 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 409 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifdef XP_WIN
       8             : // Include Windows headers required for enabling high precision timers.
       9             : #include "windows.h"
      10             : #include "mmsystem.h"
      11             : #endif
      12             : 
      13             : #include <algorithm>
      14             : #include <stdint.h>
      15             : 
      16             : #include "gfx2DGlue.h"
      17             : 
      18             : #include "mediasink/AudioSink.h"
      19             : #include "mediasink/AudioSinkWrapper.h"
      20             : #include "mediasink/DecodedStream.h"
      21             : #include "mediasink/OutputStreamManager.h"
      22             : #include "mediasink/VideoSink.h"
      23             : #include "mozilla/DebugOnly.h"
      24             : #include "mozilla/IndexSequence.h"
      25             : #include "mozilla/Logging.h"
      26             : #include "mozilla/mozalloc.h"
      27             : #include "mozilla/MathAlgorithms.h"
      28             : #include "mozilla/Preferences.h"
      29             : #include "mozilla/SharedThreadPool.h"
      30             : #include "mozilla/SizePrintfMacros.h"
      31             : #include "mozilla/Sprintf.h"
      32             : #include "mozilla/TaskQueue.h"
      33             : #include "mozilla/Tuple.h"
      34             : 
      35             : #include "nsComponentManagerUtils.h"
      36             : #include "nsContentUtils.h"
      37             : #include "nsIEventTarget.h"
      38             : #include "nsITimer.h"
      39             : #include "nsPrintfCString.h"
      40             : #include "nsTArray.h"
      41             : #include "nsDeque.h"
      42             : #include "prenv.h"
      43             : 
      44             : #include "AudioSegment.h"
      45             : #include "DOMMediaStream.h"
      46             : #include "ImageContainer.h"
      47             : #include "MediaDecoder.h"
      48             : #include "MediaDecoderReader.h"
      49             : #include "MediaDecoderReaderWrapper.h"
      50             : #include "MediaDecoderStateMachine.h"
      51             : #include "MediaShutdownManager.h"
      52             : #include "MediaPrefs.h"
      53             : #include "MediaTimer.h"
      54             : #include "TimeUnits.h"
      55             : #include "VideoSegment.h"
      56             : #include "VideoUtils.h"
      57             : #include "gfxPrefs.h"
      58             : 
      59             : namespace mozilla {
      60             : 
      61             : using namespace mozilla::dom;
      62             : using namespace mozilla::layers;
      63             : using namespace mozilla::media;
      64             : 
      65             : #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
      66             : 
      67             : // avoid redefined macro in unified build
      68             : #undef FMT
      69             : #undef LOG
      70             : #undef LOGV
      71             : #undef LOGW
      72             : #undef SFMT
      73             : #undef SLOG
      74             : #undef SLOGW
      75             : 
      76             : #define FMT(x, ...) "Decoder=%p " x, mDecoderID, ##__VA_ARGS__
      77             : #define LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,   (FMT(x, ##__VA_ARGS__)))
      78             : #define LOGV(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, (FMT(x, ##__VA_ARGS__)))
      79             : #define LOGW(x, ...) NS_WARNING(nsPrintfCString(FMT(x, ##__VA_ARGS__)).get())
      80             : 
      81             : // Used by StateObject and its sub-classes
      82             : #define SFMT(x, ...) "Decoder=%p state=%s " x, mMaster->mDecoderID, ToStateStr(GetState()), ##__VA_ARGS__
      83             : #define SLOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (SFMT(x, ##__VA_ARGS__)))
      84             : #define SLOGW(x, ...) NS_WARNING(nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get())
      85             : 
      86             : // Certain constants get stored as member variables and then adjusted by various
      87             : // scale factors on a per-decoder basis. We want to make sure to avoid using these
      88             : // constants directly, so we put them in a namespace.
      89             : namespace detail {
      90             : 
      91             : // Resume a suspended video decoder to the current playback position plus this
      92             : // time premium for compensating the seeking delay.
      93             : static constexpr auto RESUME_VIDEO_PREMIUM = TimeUnit::FromMicroseconds(125000);
      94             : 
      95             : // If audio queue has less than this much decoded audio, we won't risk
      96             : // trying to decode the video, we'll skip decoding video up to the next
      97             : // keyframe. We may increase this value for an individual decoder if we
      98             : // encounter video frames which take a long time to decode.
      99             : static constexpr auto LOW_AUDIO_THRESHOLD = TimeUnit::FromMicroseconds(300000);
     100             : 
     101             : static const int64_t AMPLE_AUDIO_USECS = 2000000;
     102             : 
     103             : // If more than this much decoded audio is queued, we'll hold off
     104             : // decoding more audio. If we increase the low audio threshold (see
     105             : // LOW_AUDIO_THRESHOLD above) we'll also increase this value to ensure it's not
     106             : // less than the low audio threshold.
     107             : static constexpr auto AMPLE_AUDIO_THRESHOLD = TimeUnit::FromMicroseconds(AMPLE_AUDIO_USECS);
     108             : 
     109             : } // namespace detail
     110             : 
     111             : // If we have fewer than LOW_VIDEO_FRAMES decoded frames, and
     112             : // we're not "prerolling video", we'll skip the video up to the next keyframe
     113             : // which is at or after the current playback position.
     114             : static const uint32_t LOW_VIDEO_FRAMES = 2;
     115             : 
     116             : // Threshold that used to check if we are low on decoded video.
     117             : // If the last video frame's end time |mDecodedVideoEndTime| is more than
     118             : // |LOW_VIDEO_THRESHOLD*mPlaybackRate| after the current clock in
     119             : // Advanceframe(), the video decode is lagging, and we skip to next keyframe.
     120             : static constexpr auto LOW_VIDEO_THRESHOLD = TimeUnit::FromMicroseconds(60000);
     121             : 
     122             : // Arbitrary "frame duration" when playing only audio.
     123             : static const int AUDIO_DURATION_USECS = 40000;
     124             : 
     125             : // If we increase our "low audio threshold" (see LOW_AUDIO_THRESHOLD above), we
     126             : // use this as a factor in all our calculations. Increasing this will cause
     127             : // us to be more likely to increase our low audio threshold, and to
     128             : // increase it by more.
     129             : static const int THRESHOLD_FACTOR = 2;
     130             : 
     131             : namespace detail {
     132             : 
     133             : // If we have less than this much buffered data available, we'll consider
     134             : // ourselves to be running low on buffered data. We determine how much
     135             : // buffered data we have remaining using the reader's GetBuffered()
     136             : // implementation.
     137             : static const int64_t LOW_BUFFER_THRESHOLD_USECS = 5000000;
     138             : 
     139             : static constexpr auto LOW_BUFFER_THRESHOLD = TimeUnit::FromMicroseconds(LOW_BUFFER_THRESHOLD_USECS);
     140             : 
     141             : // LOW_BUFFER_THRESHOLD_USECS needs to be greater than AMPLE_AUDIO_USECS, otherwise
     142             : // the skip-to-keyframe logic can activate when we're running low on data.
     143             : static_assert(LOW_BUFFER_THRESHOLD_USECS > AMPLE_AUDIO_USECS,
     144             :               "LOW_BUFFER_THRESHOLD_USECS is too small");
     145             : 
     146             : } // namespace detail
     147             : 
     148             : // Amount of excess data to add in to the "should we buffer" calculation.
     149             : static constexpr auto EXHAUSTED_DATA_MARGIN = TimeUnit::FromMicroseconds(100000);
     150             : 
     151             : static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
     152             : static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
     153             : #ifdef MOZ_APPLEMEDIA
     154             : static const uint32_t HW_VIDEO_QUEUE_SIZE = 10;
     155             : #else
     156             : static const uint32_t HW_VIDEO_QUEUE_SIZE = 3;
     157             : #endif
     158             : static const uint32_t VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE = 9999;
     159             : 
     160             : static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
     161             : static uint32_t sVideoQueueHWAccelSize = HW_VIDEO_QUEUE_SIZE;
     162             : static uint32_t sVideoQueueSendToCompositorSize =
     163             :   VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE;
     164             : 
     165           0 : static void InitVideoQueuePrefs()
     166             : {
     167           0 :   MOZ_ASSERT(NS_IsMainThread());
     168             :   static bool sPrefInit = false;
     169           0 :   if (!sPrefInit) {
     170           0 :     sPrefInit = true;
     171           0 :     sVideoQueueDefaultSize = Preferences::GetUint(
     172             :       "media.video-queue.default-size", MAX_VIDEO_QUEUE_SIZE);
     173           0 :     sVideoQueueHWAccelSize = Preferences::GetUint(
     174             :       "media.video-queue.hw-accel-size", HW_VIDEO_QUEUE_SIZE);
     175           0 :     sVideoQueueSendToCompositorSize = Preferences::GetUint(
     176             :       "media.video-queue.send-to-compositor-size", VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE);
     177             :   }
     178           0 : }
     179             : 
     180             : // Delay, in milliseconds, that tabs needs to be in background before video
     181             : // decoding is suspended.
     182             : static TimeDuration
     183           0 : SuspendBackgroundVideoDelay()
     184             : {
     185             :   return TimeDuration::FromMilliseconds(
     186           0 :     MediaPrefs::MDSMSuspendBackgroundVideoDelay());
     187             : }
     188             : 
     189             : class MediaDecoderStateMachine::StateObject
     190             : {
     191             : public:
     192           0 :   virtual ~StateObject() { }
     193           0 :   virtual void Exit() { }   // Exit action.
     194           0 :   virtual void Step() { }   // Perform a 'cycle' of this state object.
     195             :   virtual State GetState() const = 0;
     196             : 
     197             :   // Event handlers for various events.
     198           0 :   virtual void HandleCDMProxyReady() { }
     199           0 :   virtual void HandleAudioCaptured() { }
     200           0 :   virtual void HandleAudioDecoded(AudioData* aAudio)
     201             :   {
     202           0 :     Crash("Unexpected event!", __func__);
     203           0 :   }
     204           0 :   virtual void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart)
     205             :   {
     206           0 :     Crash("Unexpected event!", __func__);
     207           0 :   }
     208           0 :   virtual void HandleAudioWaited(MediaData::Type aType)
     209             :   {
     210           0 :     Crash("Unexpected event!", __func__);
     211           0 :   }
     212           0 :   virtual void HandleVideoWaited(MediaData::Type aType)
     213             :   {
     214           0 :     Crash("Unexpected event!", __func__);
     215           0 :   }
     216           0 :   virtual void HandleWaitingForAudio()
     217             :   {
     218           0 :     Crash("Unexpected event!", __func__);
     219           0 :   }
     220           0 :   virtual void HandleAudioCanceled()
     221             :   {
     222           0 :     Crash("Unexpected event!", __func__);
     223           0 :   }
     224           0 :   virtual void HandleEndOfAudio()
     225             :   {
     226           0 :     Crash("Unexpected event!", __func__);
     227           0 :   }
     228           0 :   virtual void HandleWaitingForVideo()
     229             :   {
     230           0 :     Crash("Unexpected event!", __func__);
     231           0 :   }
     232           0 :   virtual void HandleVideoCanceled()
     233             :   {
     234           0 :     Crash("Unexpected event!", __func__);
     235           0 :   }
     236           0 :   virtual void HandleEndOfVideo()
     237             :   {
     238           0 :     Crash("Unexpected event!", __func__);
     239           0 :   }
     240             : 
     241             :   virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget);
     242             : 
     243             :   virtual RefPtr<ShutdownPromise> HandleShutdown();
     244             : 
     245             :   virtual void HandleVideoSuspendTimeout() = 0;
     246             : 
     247             :   virtual void HandleResumeVideoDecoding(const TimeUnit& aTarget);
     248             : 
     249           0 :   virtual void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) { }
     250             : 
     251           0 :   virtual nsCString GetDebugInfo() { return nsCString(); }
     252             : 
     253             : private:
     254             :   template <class S, typename R, typename... As>
     255             :   auto ReturnTypeHelper(R(S::*)(As...)) -> R;
     256             : 
     257           0 :   void Crash(const char* aReason, const char* aSite)
     258             :   {
     259             :     char buf[1024];
     260           0 :     SprintfLiteral(buf, "%s state=%s callsite=%s", aReason,
     261           0 :                    ToStateStr(GetState()), aSite);
     262           0 :     MOZ_ReportAssertionFailure(buf, __FILE__, __LINE__);
     263           0 :     MOZ_CRASH();
     264             :   }
     265             : 
     266             : protected:
     267             :   enum class EventVisibility : int8_t
     268             :   {
     269             :     Observable,
     270             :     Suppressed
     271             :   };
     272             : 
     273             :   using Master = MediaDecoderStateMachine;
     274           0 :   explicit StateObject(Master* aPtr) : mMaster(aPtr) { }
     275           0 :   TaskQueue* OwnerThread() const { return mMaster->mTaskQueue; }
     276           0 :   MediaResource* Resource() const { return mMaster->mResource; }
     277           0 :   MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
     278           0 :   const MediaInfo& Info() const { return mMaster->Info(); }
     279           0 :   bool IsExpectingMoreData() const
     280             :   {
     281             :     // We are expecting more data if either the resource states so, or if we
     282             :     // have a waiting promise pending (such as with non-MSE EME).
     283           0 :     return Resource()->IsExpectingMoreData()
     284           0 :            || mMaster->IsWaitingAudioData()
     285           0 :            || mMaster->IsWaitingVideoData();
     286             :   }
     287           0 :   MediaQueue<AudioData>& AudioQueue() const { return mMaster->mAudioQueue; }
     288           0 :   MediaQueue<VideoData>& VideoQueue() const { return mMaster->mVideoQueue; }
     289             : 
     290             :   template <class S, typename... Args, size_t... Indexes>
     291             :   auto
     292           0 :   CallEnterMemberFunction(S* aS,
     293             :                           Tuple<Args...>& aTuple,
     294             :                           IndexSequence<Indexes...>)
     295             :     -> decltype(ReturnTypeHelper(&S::Enter))
     296             :   {
     297           0 :     return aS->Enter(Move(Get<Indexes>(aTuple))...);
     298             :   }
     299             : 
     300             :   // Note this function will delete the current state object.
     301             :   // Don't access members to avoid UAF after this call.
     302             :   template <class S, typename... Ts>
     303           0 :   auto SetState(Ts&&... aArgs)
     304             :     -> decltype(ReturnTypeHelper(&S::Enter))
     305             :   {
     306             :     // |aArgs| must be passed by reference to avoid passing MOZ_NON_PARAM class
     307             :     // SeekJob by value.  See bug 1287006 and bug 1338374.  But we still *must*
     308             :     // copy the parameters, because |Exit()| can modify them.  See bug 1312321.
     309             :     // So we 1) pass the parameters by reference, but then 2) immediately copy
     310             :     // them into a Tuple to be safe against modification, and finally 3) move
     311             :     // the elements of the Tuple into the final function call.
     312           0 :     auto copiedArgs = MakeTuple(Forward<Ts>(aArgs)...);
     313             : 
     314             :     // keep mMaster in a local object because mMaster will become invalid after
     315             :     // the current state object is deleted.
     316           0 :     auto master = mMaster;
     317             : 
     318           0 :     auto* s = new S(master);
     319             : 
     320           0 :     MOZ_ASSERT(GetState() != s->GetState()
     321             :                || GetState() == DECODER_STATE_SEEKING);
     322             : 
     323           0 :     SLOG("change state to: %s", ToStateStr(s->GetState()));
     324             : 
     325           0 :     Exit();
     326             : 
     327           0 :     master->mStateObj.reset(s);
     328             :     return CallEnterMemberFunction(s, copiedArgs,
     329           0 :                                    typename IndexSequenceFor<Ts...>::Type());
     330             :   }
     331             : 
     332             :   RefPtr<MediaDecoder::SeekPromise>
     333             :   SetSeekingState(SeekJob&& aSeekJob, EventVisibility aVisibility);
     334             : 
     335             :   // Take a raw pointer in order not to change the life cycle of MDSM.
     336             :   // It is guaranteed to be valid by MDSM.
     337             :   Master* mMaster;
     338             : };
     339             : 
     340             : /**
     341             :  * Purpose: decode metadata like duration and dimensions of the media resource.
     342             :  *
     343             :  * Transition to other states when decoding metadata is done:
     344             :  *   SHUTDOWN if failing to decode metadata.
     345             :  *   WAIT_FOR_CDM if the media is encrypted and CDM is not available.
     346             :  *   DECODING_FIRSTFRAME otherwise.
     347             :  */
     348           0 : class MediaDecoderStateMachine::DecodeMetadataState
     349             :   : public MediaDecoderStateMachine::StateObject
     350             : {
     351             : public:
     352           0 :   explicit DecodeMetadataState(Master* aPtr) : StateObject(aPtr) { }
     353             : 
     354           0 :   void Enter()
     355             :   {
     356           0 :     MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
     357           0 :     MOZ_ASSERT(!mMetadataRequest.Exists());
     358           0 :     SLOG("Dispatching AsyncReadMetadata");
     359             : 
     360             :     // Set mode to METADATA since we are about to read metadata.
     361           0 :     Resource()->SetReadMode(MediaCacheStream::MODE_METADATA);
     362             : 
     363             :     // We disconnect mMetadataRequest in Exit() so it is fine to capture
     364             :     // a raw pointer here.
     365           0 :     Reader()->ReadMetadata()
     366           0 :       ->Then(OwnerThread(), __func__,
     367           0 :         [this] (MetadataHolder&& aMetadata) {
     368           0 :           OnMetadataRead(Move(aMetadata));
     369           0 :         },
     370           0 :         [this] (const MediaResult& aError) {
     371           0 :           OnMetadataNotRead(aError);
     372           0 :         })
     373           0 :       ->Track(mMetadataRequest);
     374           0 :   }
     375             : 
     376           0 :   void Exit() override { mMetadataRequest.DisconnectIfExists(); }
     377             : 
     378           0 :   State GetState() const override { return DECODER_STATE_DECODING_METADATA; }
     379             : 
     380           0 :   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
     381             :   {
     382           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek while decoding metadata.");
     383             :     return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
     384             :   }
     385             : 
     386           0 :   void HandleVideoSuspendTimeout() override
     387             :   {
     388             :     // Do nothing since no decoders are created yet.
     389           0 :   }
     390             : 
     391           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
     392             :   {
     393             :     // We never suspend video decoding in this state.
     394           0 :     MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
     395             :   }
     396             : 
     397             : private:
     398             :   void OnMetadataRead(MetadataHolder&& aMetadata);
     399             : 
     400           0 :   void OnMetadataNotRead(const MediaResult& aError)
     401             :   {
     402           0 :     mMetadataRequest.Complete();
     403           0 :     SLOGW("Decode metadata failed, shutting down decoder");
     404           0 :     mMaster->DecodeError(aError);
     405           0 :   }
     406             : 
     407             :   MozPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
     408             : };
     409             : 
     410             : /**
     411             :  * Purpose: wait for the CDM to start decoding.
     412             :  *
     413             :  * Transition to other states when CDM is ready:
     414             :  *   SEEKING if any pending seek request.
     415             :  *   DECODING_FIRSTFRAME otherwise.
     416             :  */
     417           0 : class MediaDecoderStateMachine::WaitForCDMState
     418             :   : public MediaDecoderStateMachine::StateObject
     419             : {
     420             : public:
     421           0 :   explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) { }
     422             : 
     423           0 :   void Enter() { MOZ_ASSERT(!mMaster->mVideoDecodeSuspended); }
     424             : 
     425           0 :   void Exit() override
     426             :   {
     427             :     // mPendingSeek is either moved in HandleCDMProxyReady() or should be
     428             :     // rejected here before transition to SHUTDOWN.
     429           0 :     mPendingSeek.RejectIfExists(__func__);
     430           0 :   }
     431             : 
     432           0 :   State GetState() const override
     433             :   {
     434           0 :     return DECODER_STATE_WAIT_FOR_CDM;
     435             :   }
     436             : 
     437             :   void HandleCDMProxyReady() override;
     438             : 
     439           0 :   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
     440             :   {
     441           0 :     SLOG("Not Enough Data to seek at this stage, queuing seek");
     442           0 :     mPendingSeek.RejectIfExists(__func__);
     443           0 :     mPendingSeek.mTarget.emplace(aTarget);
     444           0 :     return mPendingSeek.mPromise.Ensure(__func__);
     445             :   }
     446             : 
     447           0 :   void HandleVideoSuspendTimeout() override
     448             :   {
     449             :     // Do nothing since no decoders are created yet.
     450           0 :   }
     451             : 
     452           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
     453             :   {
     454             :     // We never suspend video decoding in this state.
     455           0 :     MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
     456             :   }
     457             : 
     458             : private:
     459             :   SeekJob mPendingSeek;
     460             : };
     461             : 
     462             : /**
     463             :  * Purpose: release decoder resources to save memory and hardware resources.
     464             :  *
     465             :  * Transition to:
     466             :  *   SEEKING if any seek request or play state changes to PLAYING.
     467             :  */
     468           0 : class MediaDecoderStateMachine::DormantState
     469             :   : public MediaDecoderStateMachine::StateObject
     470             : {
     471             : public:
     472           0 :   explicit DormantState(Master* aPtr) : StateObject(aPtr) { }
     473             : 
     474           0 :   void Enter()
     475             :   {
     476           0 :     if (mMaster->IsPlaying()) {
     477           0 :       mMaster->StopPlayback();
     478             :     }
     479             : 
     480             :     // Calculate the position to seek to when exiting dormant.
     481           0 :     auto t = mMaster->mMediaSink->IsStarted()
     482           0 :       ? mMaster->GetClock() : mMaster->GetMediaTime();
     483           0 :     mPendingSeek.mTarget.emplace(t, SeekTarget::Accurate);
     484             :     // SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
     485             :     // need to create the promise even it is not used at all.
     486             :     // The promise may be used when coming out of DormantState into
     487             :     // SeekingState.
     488             :     RefPtr<MediaDecoder::SeekPromise> x =
     489           0 :       mPendingSeek.mPromise.Ensure(__func__);
     490             : 
     491             :     // No need to call ResetDecode() and StopMediaSink() here.
     492             :     // We will do them during seeking when exiting dormant.
     493             : 
     494             :     // Ignore WAIT_FOR_DATA since we won't decode in dormant.
     495           0 :     mMaster->mAudioWaitRequest.DisconnectIfExists();
     496           0 :     mMaster->mVideoWaitRequest.DisconnectIfExists();
     497             : 
     498           0 :     MaybeReleaseResources();
     499           0 :   }
     500             : 
     501           0 :   void Exit() override
     502             :   {
     503             :     // mPendingSeek is either moved when exiting dormant or
     504             :     // should be rejected here before transition to SHUTDOWN.
     505           0 :     mPendingSeek.RejectIfExists(__func__);
     506           0 :   }
     507             : 
     508           0 :   State GetState() const override { return DECODER_STATE_DORMANT; }
     509             : 
     510             :   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
     511             : 
     512           0 :   void HandleVideoSuspendTimeout() override
     513             :   {
     514             :     // Do nothing since we've released decoders in Enter().
     515           0 :   }
     516             : 
     517           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
     518             :   {
     519             :     // Do nothing since we won't resume decoding until exiting dormant.
     520           0 :   }
     521             : 
     522             :   void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override;
     523             : 
     524           0 :   void HandleAudioDecoded(AudioData*) override { MaybeReleaseResources(); }
     525           0 :   void HandleVideoDecoded(VideoData*, TimeStamp) override
     526             :   {
     527           0 :     MaybeReleaseResources();
     528           0 :   }
     529           0 :   void HandleWaitingForAudio() override { MaybeReleaseResources(); }
     530           0 :   void HandleWaitingForVideo() override { MaybeReleaseResources(); }
     531           0 :   void HandleAudioCanceled() override { MaybeReleaseResources(); }
     532           0 :   void HandleVideoCanceled() override { MaybeReleaseResources(); }
     533           0 :   void HandleEndOfAudio() override { MaybeReleaseResources(); }
     534           0 :   void HandleEndOfVideo() override { MaybeReleaseResources(); }
     535             : 
     536             : private:
     537           0 :   void MaybeReleaseResources()
     538             :   {
     539           0 :     if (!mMaster->mAudioDataRequest.Exists() &&
     540           0 :         !mMaster->mVideoDataRequest.Exists()) {
     541             :       // Release decoders only when they are idle. Otherwise it might cause
     542             :       // decode error later when resetting decoders during seeking.
     543           0 :       mMaster->mReader->ReleaseResources();
     544             :     }
     545           0 :   }
     546             : 
     547             :   SeekJob mPendingSeek;
     548             : };
     549             : 
     550             : /**
     551             :  * Purpose: decode the 1st audio and video frames to fire the 'loadeddata' event.
     552             :  *
     553             :  * Transition to:
     554             :  *   SHUTDOWN if any decode error.
     555             :  *   SEEKING if any seek request.
     556             :  *   DECODING when the 'loadeddata' event is fired.
     557             :  */
     558           0 : class MediaDecoderStateMachine::DecodingFirstFrameState
     559             :   : public MediaDecoderStateMachine::StateObject
     560             : {
     561             : public:
     562           0 :   explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr) { }
     563             : 
     564             :   void Enter();
     565             : 
     566           0 :   void Exit() override
     567             :   {
     568             :     // mPendingSeek is either moved in MaybeFinishDecodeFirstFrame()
     569             :     // or should be rejected here before transition to SHUTDOWN.
     570           0 :     mPendingSeek.RejectIfExists(__func__);
     571           0 :   }
     572             : 
     573           0 :   State GetState() const override { return DECODER_STATE_DECODING_FIRSTFRAME; }
     574             : 
     575           0 :   void HandleAudioDecoded(AudioData* aAudio) override
     576             :   {
     577           0 :     mMaster->PushAudio(aAudio);
     578           0 :     MaybeFinishDecodeFirstFrame();
     579           0 :   }
     580             : 
     581           0 :   void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart) override
     582             :   {
     583           0 :     mMaster->PushVideo(aVideo);
     584           0 :     MaybeFinishDecodeFirstFrame();
     585           0 :   }
     586             : 
     587           0 :   void HandleWaitingForAudio() override
     588             :   {
     589           0 :     mMaster->WaitForData(MediaData::AUDIO_DATA);
     590           0 :   }
     591             : 
     592           0 :   void HandleAudioCanceled() override
     593             :   {
     594           0 :     mMaster->RequestAudioData();
     595           0 :   }
     596             : 
     597           0 :   void HandleEndOfAudio() override
     598             :   {
     599           0 :     AudioQueue().Finish();
     600           0 :     MaybeFinishDecodeFirstFrame();
     601           0 :   }
     602             : 
     603           0 :   void HandleWaitingForVideo() override
     604             :   {
     605           0 :     mMaster->WaitForData(MediaData::VIDEO_DATA);
     606           0 :   }
     607             : 
     608           0 :   void HandleVideoCanceled() override
     609             :   {
     610           0 :     mMaster->RequestVideoData(media::TimeUnit());
     611           0 :   }
     612             : 
     613           0 :   void HandleEndOfVideo() override
     614             :   {
     615           0 :     VideoQueue().Finish();
     616           0 :     MaybeFinishDecodeFirstFrame();
     617           0 :   }
     618             : 
     619           0 :   void HandleAudioWaited(MediaData::Type aType) override
     620             :   {
     621           0 :     mMaster->RequestAudioData();
     622           0 :   }
     623             : 
     624           0 :   void HandleVideoWaited(MediaData::Type aType) override
     625             :   {
     626           0 :     mMaster->RequestVideoData(media::TimeUnit());
     627           0 :   }
     628             : 
     629           0 :   void HandleVideoSuspendTimeout() override
     630             :   {
     631             :     // Do nothing for we need to decode the 1st video frame to get the
     632             :     // dimensions.
     633           0 :   }
     634             : 
     635           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
     636             :   {
     637             :     // We never suspend video decoding in this state.
     638           0 :     MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
     639             :   }
     640             : 
     641           0 :   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
     642             :   {
     643           0 :     if (mMaster->mIsMSE) {
     644           0 :       return StateObject::HandleSeek(aTarget);
     645             :     }
     646             :     // Delay seek request until decoding first frames for non-MSE media.
     647           0 :     SLOG("Not Enough Data to seek at this stage, queuing seek");
     648           0 :     mPendingSeek.RejectIfExists(__func__);
     649           0 :     mPendingSeek.mTarget.emplace(aTarget);
     650           0 :     return mPendingSeek.mPromise.Ensure(__func__);
     651             :   }
     652             : 
     653             : private:
     654             :   // Notify FirstFrameLoaded if having decoded first frames and
     655             :   // transition to SEEKING if there is any pending seek, or DECODING otherwise.
     656             :   void MaybeFinishDecodeFirstFrame();
     657             : 
     658             :   SeekJob mPendingSeek;
     659             : };
     660             : 
     661             : /**
     662             :  * Purpose: decode audio/video data for playback.
     663             :  *
     664             :  * Transition to:
     665             :  *   DORMANT if playback is paused for a while.
     666             :  *   SEEKING if any seek request.
     667             :  *   SHUTDOWN if any decode error.
     668             :  *   BUFFERING if playback can't continue due to lack of decoded data.
     669             :  *   COMPLETED when having decoded all audio/video data.
     670             :  */
     671           0 : class MediaDecoderStateMachine::DecodingState
     672             :   : public MediaDecoderStateMachine::StateObject
     673             : {
     674             : public:
     675           0 :   explicit DecodingState(Master* aPtr)
     676           0 :     : StateObject(aPtr)
     677           0 :     , mDormantTimer(OwnerThread())
     678             :   {
     679           0 :   }
     680             : 
     681             :   void Enter();
     682             : 
     683           0 :   void Exit() override
     684             :   {
     685           0 :     if (!mDecodeStartTime.IsNull()) {
     686           0 :       TimeDuration decodeDuration = TimeStamp::Now() - mDecodeStartTime;
     687           0 :       SLOG("Exiting DECODING, decoded for %.3lfs", decodeDuration.ToSeconds());
     688             :     }
     689           0 :     mDormantTimer.Reset();
     690           0 :     mOnAudioPopped.DisconnectIfExists();
     691           0 :     mOnVideoPopped.DisconnectIfExists();
     692           0 :   }
     693             : 
     694           0 :   void Step() override
     695             :   {
     696           0 :     if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING
     697           0 :         && mMaster->IsPlaying()) {
     698             :       // We're playing, but the element/decoder is in paused state. Stop
     699             :       // playing!
     700           0 :       mMaster->StopPlayback();
     701             :     }
     702             : 
     703             :     // Start playback if necessary so that the clock can be properly queried.
     704           0 :     if (!mIsPrerolling) {
     705           0 :       mMaster->MaybeStartPlayback();
     706             :     }
     707             : 
     708           0 :     mMaster->UpdatePlaybackPositionPeriodically();
     709             : 
     710           0 :     MOZ_ASSERT(!mMaster->IsPlaying()
     711             :                || mMaster->IsStateMachineScheduled(),
     712             :                "Must have timer scheduled");
     713             : 
     714           0 :     MaybeStartBuffering();
     715           0 :   }
     716             : 
     717           0 :   State GetState() const override
     718             :   {
     719           0 :     return DECODER_STATE_DECODING;
     720             :   }
     721             : 
     722           0 :   void HandleAudioDecoded(AudioData* aAudio) override
     723             :   {
     724           0 :     mMaster->PushAudio(aAudio);
     725           0 :     DispatchDecodeTasksIfNeeded();
     726           0 :     MaybeStopPrerolling();
     727           0 :   }
     728             : 
     729           0 :   void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart) override
     730             :   {
     731           0 :     mMaster->PushVideo(aVideo);
     732           0 :     DispatchDecodeTasksIfNeeded();
     733           0 :     MaybeStopPrerolling();
     734           0 :     CheckSlowDecoding(aDecodeStart);
     735           0 :   }
     736             : 
     737           0 :   void HandleAudioCanceled() override
     738             :   {
     739           0 :     mMaster->RequestAudioData();
     740           0 :   }
     741             : 
     742           0 :   void HandleVideoCanceled() override
     743             :   {
     744           0 :     mMaster->RequestVideoData(mMaster->GetMediaTime());
     745           0 :   }
     746             : 
     747             :   void HandleEndOfAudio() override;
     748             :   void HandleEndOfVideo() override;
     749             : 
     750           0 :   void HandleWaitingForAudio() override
     751             :   {
     752           0 :     mMaster->WaitForData(MediaData::AUDIO_DATA);
     753           0 :     MaybeStopPrerolling();
     754           0 :   }
     755             : 
     756           0 :   void HandleWaitingForVideo() override
     757             :   {
     758           0 :     mMaster->WaitForData(MediaData::VIDEO_DATA);
     759           0 :     MaybeStopPrerolling();
     760           0 :   }
     761             : 
     762           0 :   void HandleAudioWaited(MediaData::Type aType) override
     763             :   {
     764           0 :     mMaster->RequestAudioData();
     765           0 :   }
     766             : 
     767           0 :   void HandleVideoWaited(MediaData::Type aType) override
     768             :   {
     769           0 :     mMaster->RequestVideoData(mMaster->GetMediaTime());
     770           0 :   }
     771             : 
     772           0 :   void HandleAudioCaptured() override
     773             :   {
     774           0 :     MaybeStopPrerolling();
     775             :     // MediaSink is changed. Schedule Step() to check if we can start playback.
     776           0 :     mMaster->ScheduleStateMachine();
     777           0 :   }
     778             : 
     779           0 :   void HandleVideoSuspendTimeout() override
     780             :   {
     781             :     // No video, so nothing to suspend.
     782           0 :     if (!mMaster->HasVideo()) {
     783           0 :       return;
     784             :     }
     785             : 
     786           0 :     mMaster->mVideoDecodeSuspended = true;
     787           0 :     mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
     788           0 :     Reader()->SetVideoBlankDecode(true);
     789             :   }
     790             : 
     791           0 :   void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override
     792             :   {
     793           0 :     if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
     794             :       // Schedule Step() to check if we can start playback.
     795           0 :       mMaster->ScheduleStateMachine();
     796             :       // Try to dispatch decoding tasks for mMinimizePreroll might be reset.
     797           0 :       DispatchDecodeTasksIfNeeded();
     798             :     }
     799             : 
     800           0 :     if (aPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
     801           0 :       StartDormantTimer();
     802             :     } else {
     803           0 :       mDormantTimer.Reset();
     804             :     }
     805           0 :   }
     806             : 
     807           0 :   nsCString GetDebugInfo() override
     808             :   {
     809           0 :     return nsPrintfCString("mIsPrerolling=%d", mIsPrerolling);
     810             :   }
     811             : 
     812             : private:
     813             :   void DispatchDecodeTasksIfNeeded();
     814             :   void EnsureAudioDecodeTaskQueued();
     815             :   void EnsureVideoDecodeTaskQueued();
     816             :   void MaybeStartBuffering();
     817             : 
     818           0 :   void CheckSlowDecoding(TimeStamp aDecodeStart)
     819             :   {
     820             :     // For non async readers, if the requested video sample was slow to
     821             :     // arrive, increase the amount of audio we buffer to ensure that we
     822             :     // don't run out of audio. This is unnecessary for async readers,
     823             :     // since they decode audio and video on different threads so they
     824             :     // are unlikely to run out of decoded audio.
     825           0 :     if (Reader()->IsAsync()) {
     826           0 :       return;
     827             :     }
     828             : 
     829           0 :     TimeDuration decodeTime = TimeStamp::Now() - aDecodeStart;
     830           0 :     auto adjusted = TimeUnit::FromTimeDuration(decodeTime * THRESHOLD_FACTOR);
     831           0 :     if (adjusted > mMaster->mLowAudioThreshold
     832           0 :         && !mMaster->HasLowBufferedData())
     833             :     {
     834           0 :       mMaster->mLowAudioThreshold = std::min(
     835           0 :         adjusted, mMaster->mAmpleAudioThreshold);
     836             : 
     837           0 :       mMaster->mAmpleAudioThreshold = std::max(
     838           0 :         mMaster->mLowAudioThreshold * THRESHOLD_FACTOR,
     839           0 :         mMaster->mAmpleAudioThreshold);
     840             : 
     841           0 :       SLOG("Slow video decode, set "
     842             :            "mLowAudioThreshold=%" PRId64
     843             :            " mAmpleAudioThreshold=%" PRId64,
     844             :            mMaster->mLowAudioThreshold.ToMicroseconds(),
     845             :            mMaster->mAmpleAudioThreshold.ToMicroseconds());
     846             :     }
     847             :   }
     848             : 
     849             :   // At the start of decoding we want to "preroll" the decode until we've
     850             :   // got a few frames decoded before we consider whether decode is falling
     851             :   // behind. Otherwise our "we're falling behind" logic will trigger
     852             :   // unnecessarily if we start playing as soon as the first sample is
     853             :   // decoded. These two fields store how many video frames and audio
     854             :   // samples we must consume before are considered to be finished prerolling.
     855           0 :   TimeUnit AudioPrerollThreshold() const
     856             :   {
     857           0 :     return mMaster->mAmpleAudioThreshold / 2;
     858             :   }
     859             : 
     860           0 :   uint32_t VideoPrerollFrames() const
     861             :   {
     862           0 :     return mMaster->GetAmpleVideoFrames() / 2;
     863             :   }
     864             : 
     865           0 :   bool DonePrerollingAudio()
     866             :   {
     867           0 :     return !mMaster->IsAudioDecoding()
     868           0 :            || mMaster->GetDecodedAudioDuration()
     869           0 :               >= AudioPrerollThreshold().MultDouble(mMaster->mPlaybackRate);
     870             :   }
     871             : 
     872           0 :   bool DonePrerollingVideo()
     873             :   {
     874           0 :     return !mMaster->IsVideoDecoding()
     875           0 :            || static_cast<uint32_t>(mMaster->VideoQueue().GetSize())
     876           0 :               >= VideoPrerollFrames() * mMaster->mPlaybackRate + 1;
     877             :   }
     878             : 
     879           0 :   void MaybeStopPrerolling()
     880             :   {
     881           0 :     if (mIsPrerolling
     882           0 :         && (DonePrerollingAudio() || mMaster->IsWaitingAudioData())
     883           0 :         && (DonePrerollingVideo() || mMaster->IsWaitingVideoData())) {
     884           0 :       mIsPrerolling = false;
     885             :       // Check if we can start playback.
     886           0 :       mMaster->ScheduleStateMachine();
     887             :     }
     888           0 :   }
     889             : 
     890           0 :   void StartDormantTimer()
     891             :   {
     892           0 :     if (!mMaster->mMediaSeekable) {
     893             :       // Don't enter dormant if the media is not seekable because we need to
     894             :       // seek when exiting dormant.
     895           0 :       return;
     896             :     }
     897             : 
     898           0 :     auto timeout = MediaPrefs::DormantOnPauseTimeout();
     899           0 :     if (timeout < 0) {
     900             :       // Disabled when timeout is negative.
     901           0 :       return;
     902           0 :     } else if (timeout == 0) {
     903             :       // Enter dormant immediately without scheduling a timer.
     904           0 :       SetState<DormantState>();
     905           0 :       return;
     906             :     }
     907             : 
     908           0 :     if (mMaster->mMinimizePreroll) {
     909           0 :       SetState<DormantState>();
     910           0 :       return;
     911             :     }
     912             : 
     913           0 :     TimeStamp target = TimeStamp::Now() +
     914           0 :       TimeDuration::FromMilliseconds(timeout);
     915             : 
     916           0 :     mDormantTimer.Ensure(target,
     917           0 :       [this] () {
     918           0 :         mDormantTimer.CompleteRequest();
     919           0 :         SetState<DormantState>();
     920           0 :       }, [this] () {
     921           0 :         mDormantTimer.CompleteRequest();
     922           0 :       });
     923             :   }
     924             : 
     925             :   // Time at which we started decoding.
     926             :   TimeStamp mDecodeStartTime;
     927             : 
     928             :   // When we start decoding (either for the first time, or after a pause)
     929             :   // we may be low on decoded data. We don't want our "low data" logic to
     930             :   // kick in and decide that we're low on decoded data because the download
     931             :   // can't keep up with the decode, and cause us to pause playback. So we
     932             :   // have a "preroll" stage, where we ignore the results of our "low data"
     933             :   // logic during the first few frames of our decode. This occurs during
     934             :   // playback.
     935             :   bool mIsPrerolling = true;
     936             : 
     937             :   // Fired when playback is paused for a while to enter dormant.
     938             :   DelayedScheduler mDormantTimer;
     939             : 
     940             :   MediaEventListener mOnAudioPopped;
     941             :   MediaEventListener mOnVideoPopped;
     942             : };
     943             : 
     944             : /**
     945             :  * Purpose: seek to a particular new playback position.
     946             :  *
     947             :  * Transition to:
     948             :  *   SEEKING if any new seek request.
     949             :  *   SHUTDOWN if seek failed.
     950             :  *   COMPLETED if the new playback position is the end of the media resource.
     951             :  *   NextFrameSeekingState if completing a NextFrameSeekingFromDormantState.
     952             :  *   DECODING otherwise.
     953             :  */
     954           0 : class MediaDecoderStateMachine::SeekingState
     955             :   : public MediaDecoderStateMachine::StateObject
     956             : {
     957             : public:
     958           0 :   explicit SeekingState(Master* aPtr) : StateObject(aPtr) { }
     959             : 
     960           0 :   RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
     961             :                                           EventVisibility aVisibility)
     962             :   {
     963           0 :     mSeekJob = Move(aSeekJob);
     964           0 :     mVisibility = aVisibility;
     965             : 
     966             :     // Always switch off the blank decoder otherwise we might become visible
     967             :     // in the middle of seeking and won't have a valid video frame to show
     968             :     // when seek is done.
     969           0 :     if (mMaster->mVideoDecodeSuspended) {
     970           0 :       mMaster->mVideoDecodeSuspended = false;
     971           0 :       mMaster->mOnPlaybackEvent.Notify(MediaEventType::ExitVideoSuspend);
     972           0 :       Reader()->SetVideoBlankDecode(false);
     973             :     }
     974             : 
     975             :     // Suppressed visibility comes from two cases: (1) leaving dormant state,
     976             :     // and (2) resuming suspended video decoder. We want both cases to be
     977             :     // transparent to the user. So we only notify the change when the seek
     978             :     // request is from the user.
     979           0 :     if (mVisibility == EventVisibility::Observable) {
     980             :       // Don't stop playback for a video-only seek since we want to keep playing
     981             :       // audio and we don't need to stop playback while leaving dormant for the
     982             :       // playback should has been stopped.
     983           0 :       mMaster->StopPlayback();
     984           0 :       mMaster->UpdatePlaybackPositionInternal(mSeekJob.mTarget->GetTime());
     985           0 :       mMaster->mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
     986           0 :       mMaster->UpdateNextFrameStatus(
     987           0 :         MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
     988             :     }
     989             : 
     990           0 :     RefPtr<MediaDecoder::SeekPromise> p = mSeekJob.mPromise.Ensure(__func__);
     991             : 
     992           0 :     DoSeek();
     993             : 
     994           0 :     return p;
     995             :   }
     996             : 
     997             :   virtual void Exit() override = 0;
     998             : 
     999           0 :   State GetState() const override
    1000             :   {
    1001           0 :     return DECODER_STATE_SEEKING;
    1002             :   }
    1003             : 
    1004             :   void HandleAudioDecoded(AudioData* aAudio) override = 0;
    1005             :   void HandleVideoDecoded(VideoData* aVideo,
    1006             :                           TimeStamp aDecodeStart) override = 0;
    1007             :   void HandleAudioWaited(MediaData::Type aType) override = 0;
    1008             :   void HandleVideoWaited(MediaData::Type aType) override = 0;
    1009             : 
    1010           0 :   void HandleVideoSuspendTimeout() override
    1011             :   {
    1012             :     // Do nothing since we want a valid video frame to show when seek is done.
    1013           0 :   }
    1014             : 
    1015           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
    1016             :   {
    1017             :     // We set mVideoDecodeSuspended to false in Enter().
    1018           0 :     MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
    1019             :   }
    1020             : 
    1021             : protected:
    1022             :   SeekJob mSeekJob;
    1023             :   EventVisibility mVisibility;
    1024             : 
    1025             :   virtual void DoSeek() = 0;
    1026             :   // Transition to the next state (defined by the subclass) when seek is completed.
    1027           0 :   virtual void GoToNextState() { SetState<DecodingState>(); }
    1028             :   void SeekCompleted();
    1029             :   virtual TimeUnit CalculateNewCurrentTime() const = 0;
    1030             : };
    1031             : 
    1032           0 : class MediaDecoderStateMachine::AccurateSeekingState
    1033             :   : public MediaDecoderStateMachine::SeekingState
    1034             : {
    1035             : public:
    1036           0 :   explicit AccurateSeekingState(Master* aPtr) : SeekingState(aPtr) { }
    1037             : 
    1038           0 :   RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
    1039             :                                           EventVisibility aVisibility)
    1040             :   {
    1041           0 :     MOZ_ASSERT(aSeekJob.mTarget->IsAccurate() || aSeekJob.mTarget->IsFast());
    1042           0 :     mCurrentTimeBeforeSeek = mMaster->GetMediaTime();
    1043           0 :     return SeekingState::Enter(Move(aSeekJob), aVisibility);
    1044             :   }
    1045             : 
    1046           0 :   void Exit() override
    1047             :   {
    1048             :     // Disconnect MediaDecoder.
    1049           0 :     mSeekJob.RejectIfExists(__func__);
    1050             : 
    1051             :     // Disconnect MediaDecoderReaderWrapper.
    1052           0 :     mSeekRequest.DisconnectIfExists();
    1053             : 
    1054           0 :     mWaitRequest.DisconnectIfExists();
    1055           0 :   }
    1056             : 
    1057           0 :   void HandleAudioDecoded(AudioData* aAudio) override
    1058             :   {
    1059           0 :     MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking,
    1060             :                "Seek shouldn't be finished");
    1061           0 :     MOZ_ASSERT(aAudio);
    1062             : 
    1063           0 :     AdjustFastSeekIfNeeded(aAudio);
    1064             : 
    1065           0 :     if (mSeekJob.mTarget->IsFast()) {
    1066             :       // Non-precise seek; we can stop the seek at the first sample.
    1067           0 :       mMaster->PushAudio(aAudio);
    1068           0 :       mDoneAudioSeeking = true;
    1069             :     } else {
    1070           0 :       nsresult rv = DropAudioUpToSeekTarget(aAudio);
    1071           0 :       if (NS_FAILED(rv)) {
    1072           0 :         mMaster->DecodeError(rv);
    1073           0 :         return;
    1074             :       }
    1075             :     }
    1076             : 
    1077           0 :     if (!mDoneAudioSeeking) {
    1078           0 :       RequestAudioData();
    1079           0 :       return;
    1080             :     }
    1081           0 :     MaybeFinishSeek();
    1082             :   }
    1083             : 
    1084           0 :   void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart) override
    1085             :   {
    1086           0 :     MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking,
    1087             :                "Seek shouldn't be finished");
    1088           0 :     MOZ_ASSERT(aVideo);
    1089             : 
    1090           0 :     AdjustFastSeekIfNeeded(aVideo);
    1091             : 
    1092           0 :     if (mSeekJob.mTarget->IsFast()) {
    1093             :       // Non-precise seek. We can stop the seek at the first sample.
    1094           0 :       mMaster->PushVideo(aVideo);
    1095           0 :       mDoneVideoSeeking = true;
    1096             :     } else {
    1097           0 :       nsresult rv = DropVideoUpToSeekTarget(aVideo);
    1098           0 :       if (NS_FAILED(rv)) {
    1099           0 :         mMaster->DecodeError(rv);
    1100           0 :         return;
    1101             :       }
    1102             :     }
    1103             : 
    1104           0 :     if (!mDoneVideoSeeking) {
    1105           0 :       RequestVideoData();
    1106           0 :       return;
    1107             :     }
    1108           0 :     MaybeFinishSeek();
    1109             :   }
    1110             : 
    1111           0 :   void HandleWaitingForAudio() override
    1112             :   {
    1113           0 :     MOZ_ASSERT(!mDoneAudioSeeking);
    1114           0 :     mMaster->WaitForData(MediaData::AUDIO_DATA);
    1115           0 :   }
    1116             : 
    1117           0 :   void HandleAudioCanceled() override
    1118             :   {
    1119           0 :     MOZ_ASSERT(!mDoneAudioSeeking);
    1120           0 :     RequestAudioData();
    1121           0 :   }
    1122             : 
    1123           0 :   void HandleEndOfAudio() override
    1124             :   {
    1125           0 :     MOZ_ASSERT(!mDoneAudioSeeking);
    1126           0 :     AudioQueue().Finish();
    1127           0 :     mDoneAudioSeeking = true;
    1128           0 :     MaybeFinishSeek();
    1129           0 :   }
    1130             : 
    1131           0 :   void HandleWaitingForVideo() override
    1132             :   {
    1133           0 :     MOZ_ASSERT(!mDoneVideoSeeking);
    1134           0 :     mMaster->WaitForData(MediaData::VIDEO_DATA);
    1135           0 :   }
    1136             : 
    1137           0 :   void HandleVideoCanceled() override
    1138             :   {
    1139           0 :     MOZ_ASSERT(!mDoneVideoSeeking);
    1140           0 :     RequestVideoData();
    1141           0 :   }
    1142             : 
    1143           0 :   void HandleEndOfVideo() override
    1144             :   {
    1145           0 :     MOZ_ASSERT(!mDoneVideoSeeking);
    1146           0 :     if (mFirstVideoFrameAfterSeek) {
    1147             :       // Hit the end of stream. Move mFirstVideoFrameAfterSeek into
    1148             :       // mSeekedVideoData so we have something to display after seeking.
    1149           0 :       mMaster->PushVideo(mFirstVideoFrameAfterSeek);
    1150             :     }
    1151           0 :     VideoQueue().Finish();
    1152           0 :     mDoneVideoSeeking = true;
    1153           0 :     MaybeFinishSeek();
    1154           0 :   }
    1155             : 
    1156           0 :   void HandleAudioWaited(MediaData::Type aType) override
    1157             :   {
    1158           0 :     MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking,
    1159             :                "Seek shouldn't be finished");
    1160             : 
    1161           0 :     RequestAudioData();
    1162           0 :   }
    1163             : 
    1164           0 :   void HandleVideoWaited(MediaData::Type aType) override
    1165             :   {
    1166           0 :     MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking,
    1167             :                "Seek shouldn't be finished");
    1168             : 
    1169           0 :     RequestVideoData();
    1170           0 :   }
    1171             : 
    1172           0 :   void DoSeek() override
    1173             :   {
    1174           0 :     mDoneAudioSeeking = !Info().HasAudio();
    1175           0 :     mDoneVideoSeeking = !Info().HasVideo();
    1176             : 
    1177           0 :     mMaster->ResetDecode();
    1178           0 :     mMaster->StopMediaSink();
    1179             : 
    1180           0 :     DemuxerSeek();
    1181           0 :   }
    1182             : 
    1183           0 :   TimeUnit CalculateNewCurrentTime() const override
    1184             :   {
    1185           0 :     const auto seekTime = mSeekJob.mTarget->GetTime();
    1186             : 
    1187             :     // For the accurate seek, we always set the newCurrentTime = seekTime so
    1188             :     // that the updated HTMLMediaElement.currentTime will always be the seek
    1189             :     // target; we rely on the MediaSink to handles the gap between the
    1190             :     // newCurrentTime and the real decoded samples' start time.
    1191           0 :     if (mSeekJob.mTarget->IsAccurate()) {
    1192           0 :       return seekTime;
    1193             :     }
    1194             : 
    1195             :     // For the fast seek, we update the newCurrentTime with the decoded audio
    1196             :     // and video samples, set it to be the one which is closet to the seekTime.
    1197           0 :     if (mSeekJob.mTarget->IsFast()) {
    1198           0 :       RefPtr<AudioData> audio = AudioQueue().PeekFront();
    1199           0 :       RefPtr<VideoData> video = VideoQueue().PeekFront();
    1200             : 
    1201             :       // A situation that both audio and video approaches the end.
    1202           0 :       if (!audio && !video) {
    1203           0 :         return seekTime;
    1204             :       }
    1205             : 
    1206             :       const int64_t audioStart =
    1207           0 :         audio ? audio->mTime.ToMicroseconds() : INT64_MAX;
    1208             :       const int64_t videoStart =
    1209           0 :         video ? video->mTime.ToMicroseconds() : INT64_MAX;
    1210           0 :       const int64_t audioGap = std::abs(audioStart - seekTime.ToMicroseconds());
    1211           0 :       const int64_t videoGap = std::abs(videoStart - seekTime.ToMicroseconds());
    1212             :       return TimeUnit::FromMicroseconds(
    1213           0 :         audioGap <= videoGap ? audioStart : videoStart);
    1214             :     }
    1215             : 
    1216           0 :     MOZ_ASSERT(false, "AccurateSeekTask doesn't handle other seek types.");
    1217             :     return TimeUnit::Zero();
    1218             :   }
    1219             : 
    1220             : protected:
    1221           0 :   void DemuxerSeek()
    1222             :   {
    1223             :     // Request the demuxer to perform seek.
    1224           0 :     Reader()->Seek(mSeekJob.mTarget.ref())
    1225           0 :       ->Then(OwnerThread(), __func__,
    1226           0 :              [this] (const media::TimeUnit& aUnit) {
    1227           0 :                OnSeekResolved(aUnit);
    1228           0 :              },
    1229           0 :              [this] (const SeekRejectValue& aReject) {
    1230           0 :                OnSeekRejected(aReject);
    1231           0 :              })
    1232           0 :       ->Track(mSeekRequest);
    1233           0 :   }
    1234             : 
    1235           0 :   void OnSeekResolved(media::TimeUnit)
    1236             :   {
    1237           0 :     mSeekRequest.Complete();
    1238             : 
    1239             :     // We must decode the first samples of active streams, so we can determine
    1240             :     // the new stream time. So dispatch tasks to do that.
    1241           0 :     if (!mDoneVideoSeeking) {
    1242           0 :       RequestVideoData();
    1243             :     }
    1244           0 :     if (!mDoneAudioSeeking) {
    1245           0 :       RequestAudioData();
    1246             :     }
    1247           0 :   }
    1248             : 
    1249           0 :   void OnSeekRejected(const SeekRejectValue& aReject)
    1250             :   {
    1251           0 :     mSeekRequest.Complete();
    1252             : 
    1253           0 :     if (aReject.mError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
    1254           0 :       SLOG("OnSeekRejected reason=WAITING_FOR_DATA type=%d", aReject.mType);
    1255           0 :       MOZ_ASSERT_IF(aReject.mType == MediaData::AUDIO_DATA, !mMaster->IsRequestingAudioData());
    1256           0 :       MOZ_ASSERT_IF(aReject.mType == MediaData::VIDEO_DATA, !mMaster->IsRequestingVideoData());
    1257           0 :       MOZ_ASSERT_IF(aReject.mType == MediaData::AUDIO_DATA, !mMaster->IsWaitingAudioData());
    1258           0 :       MOZ_ASSERT_IF(aReject.mType == MediaData::VIDEO_DATA, !mMaster->IsWaitingVideoData());
    1259             : 
    1260             :       // Fire 'waiting' to notify the player that we are waiting for data.
    1261           0 :       mMaster->UpdateNextFrameStatus(
    1262           0 :         MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
    1263             :       Reader()
    1264           0 :         ->WaitForData(aReject.mType)
    1265           0 :         ->Then(OwnerThread(), __func__,
    1266           0 :                [this](MediaData::Type aType) {
    1267           0 :                  SLOG("OnSeekRejected wait promise resolved");
    1268           0 :                  mWaitRequest.Complete();
    1269           0 :                  DemuxerSeek();
    1270           0 :                },
    1271           0 :                [this](const WaitForDataRejectValue& aRejection) {
    1272           0 :                  SLOG("OnSeekRejected wait promise rejected");
    1273           0 :                  mWaitRequest.Complete();
    1274           0 :                  mMaster->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
    1275           0 :                })
    1276           0 :         ->Track(mWaitRequest);
    1277           0 :       return;
    1278             :     }
    1279             : 
    1280           0 :     if (aReject.mError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
    1281           0 :       HandleEndOfAudio();
    1282           0 :       HandleEndOfVideo();
    1283           0 :       return;
    1284             :     }
    1285             : 
    1286           0 :     MOZ_ASSERT(NS_FAILED(aReject.mError),
    1287             :                "Cancels should also disconnect mSeekRequest");
    1288           0 :     mMaster->DecodeError(aReject.mError);
    1289             :   }
    1290             : 
    1291           0 :   void RequestAudioData()
    1292             :   {
    1293           0 :     MOZ_ASSERT(!mDoneAudioSeeking);
    1294           0 :     mMaster->RequestAudioData();
    1295           0 :   }
    1296             : 
    1297           0 :   void RequestVideoData()
    1298             :   {
    1299           0 :     MOZ_ASSERT(!mDoneVideoSeeking);
    1300           0 :     mMaster->RequestVideoData(media::TimeUnit());
    1301           0 :   }
    1302             : 
    1303           0 :   void AdjustFastSeekIfNeeded(MediaData* aSample)
    1304             :   {
    1305           0 :     if (mSeekJob.mTarget->IsFast()
    1306           0 :         && mSeekJob.mTarget->GetTime() > mCurrentTimeBeforeSeek
    1307           0 :         && aSample->mTime < mCurrentTimeBeforeSeek) {
    1308             :       // We are doing a fastSeek, but we ended up *before* the previous
    1309             :       // playback position. This is surprising UX, so switch to an accurate
    1310             :       // seek and decode to the seek target. This is not conformant to the
    1311             :       // spec, fastSeek should always be fast, but until we get the time to
    1312             :       // change all Readers to seek to the keyframe after the currentTime
    1313             :       // in this case, we'll just decode forward. Bug 1026330.
    1314           0 :       mSeekJob.mTarget->SetType(SeekTarget::Accurate);
    1315             :     }
    1316           0 :   }
    1317             : 
    1318           0 :   nsresult DropAudioUpToSeekTarget(AudioData* aAudio)
    1319             :   {
    1320           0 :     MOZ_ASSERT(aAudio && mSeekJob.mTarget->IsAccurate());
    1321             : 
    1322             :     auto sampleDuration = FramesToTimeUnit(
    1323           0 :       aAudio->mFrames, Info().mAudio.mRate);
    1324           0 :     if (!sampleDuration.IsValid()) {
    1325           0 :       return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
    1326             :     }
    1327             : 
    1328           0 :     auto audioTime = aAudio->mTime;
    1329           0 :     if (audioTime + sampleDuration <= mSeekJob.mTarget->GetTime()) {
    1330             :       // Our seek target lies after the frames in this AudioData. Don't
    1331             :       // push it onto the audio queue, and keep decoding forwards.
    1332           0 :       return NS_OK;
    1333             :     }
    1334             : 
    1335           0 :     if (audioTime > mSeekJob.mTarget->GetTime()) {
    1336             :       // The seek target doesn't lie in the audio block just after the last
    1337             :       // audio frames we've seen which were before the seek target. This
    1338             :       // could have been the first audio data we've seen after seek, i.e. the
    1339             :       // seek terminated after the seek target in the audio stream. Just
    1340             :       // abort the audio decode-to-target, the state machine will play
    1341             :       // silence to cover the gap. Typically this happens in poorly muxed
    1342             :       // files.
    1343           0 :       SLOGW("Audio not synced after seek, maybe a poorly muxed file?");
    1344           0 :       mMaster->PushAudio(aAudio);
    1345           0 :       mDoneAudioSeeking = true;
    1346           0 :       return NS_OK;
    1347             :     }
    1348             : 
    1349             :     // The seek target lies somewhere in this AudioData's frames, strip off
    1350             :     // any frames which lie before the seek target, so we'll begin playback
    1351             :     // exactly at the seek target.
    1352           0 :     NS_ASSERTION(mSeekJob.mTarget->GetTime() >= audioTime,
    1353             :                  "Target must at or be after data start.");
    1354           0 :     NS_ASSERTION(mSeekJob.mTarget->GetTime() < audioTime + sampleDuration,
    1355             :                  "Data must end after target.");
    1356             : 
    1357             :     CheckedInt64 framesToPrune = TimeUnitToFrames(
    1358           0 :       mSeekJob.mTarget->GetTime() - audioTime, Info().mAudio.mRate);
    1359           0 :     if (!framesToPrune.isValid()) {
    1360           0 :       return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
    1361             :     }
    1362           0 :     if (framesToPrune.value() > aAudio->mFrames) {
    1363             :       // We've messed up somehow. Don't try to trim frames, the |frames|
    1364             :       // variable below will overflow.
    1365           0 :       SLOGW("Can't prune more frames that we have!");
    1366           0 :       return NS_ERROR_FAILURE;
    1367             :     }
    1368           0 :     uint32_t frames = aAudio->mFrames - uint32_t(framesToPrune.value());
    1369           0 :     uint32_t channels = aAudio->mChannels;
    1370           0 :     AlignedAudioBuffer audioData(frames * channels);
    1371           0 :     if (!audioData) {
    1372           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1373             :     }
    1374             : 
    1375           0 :     memcpy(audioData.get(),
    1376           0 :            aAudio->mAudioData.get() + (framesToPrune.value() * channels),
    1377           0 :            frames * channels * sizeof(AudioDataValue));
    1378           0 :     auto duration = FramesToTimeUnit(frames, Info().mAudio.mRate);
    1379           0 :     if (!duration.IsValid()) {
    1380           0 :       return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
    1381             :     }
    1382             :     RefPtr<AudioData> data(new AudioData(
    1383           0 :       aAudio->mOffset, mSeekJob.mTarget->GetTime(),
    1384             :       duration, frames, Move(audioData), channels,
    1385           0 :       aAudio->mRate));
    1386           0 :     MOZ_ASSERT(AudioQueue().GetSize() == 0,
    1387             :                "Should be the 1st sample after seeking");
    1388           0 :     mMaster->PushAudio(data);
    1389           0 :     mDoneAudioSeeking = true;
    1390             : 
    1391           0 :     return NS_OK;
    1392             :   }
    1393             : 
    1394           0 :   nsresult DropVideoUpToSeekTarget(VideoData* aVideo)
    1395             :   {
    1396           0 :     MOZ_ASSERT(aVideo);
    1397           0 :     SLOG("DropVideoUpToSeekTarget() frame [%" PRId64 ", %" PRId64 "]",
    1398             :          aVideo->mTime.ToMicroseconds(), aVideo->GetEndTime().ToMicroseconds());
    1399           0 :     const auto target = mSeekJob.mTarget->GetTime();
    1400             : 
    1401             :     // If the frame end time is less than the seek target, we won't want
    1402             :     // to display this frame after the seek, so discard it.
    1403           0 :     if (target >= aVideo->GetEndTime()) {
    1404           0 :       SLOG("DropVideoUpToSeekTarget() pop video frame [%" PRId64 ", %" PRId64
    1405             :            "] target=%" PRId64,
    1406             :            aVideo->mTime.ToMicroseconds(),
    1407             :            aVideo->GetEndTime().ToMicroseconds(),
    1408             :            target.ToMicroseconds());
    1409           0 :       mFirstVideoFrameAfterSeek = aVideo;
    1410             :     } else {
    1411           0 :       if (target >= aVideo->mTime &&
    1412           0 :           aVideo->GetEndTime() >= target) {
    1413             :         // The seek target lies inside this frame's time slice. Adjust the
    1414             :         // frame's start time to match the seek target.
    1415           0 :         aVideo->UpdateTimestamp(target);
    1416             :       }
    1417           0 :       mFirstVideoFrameAfterSeek = nullptr;
    1418             : 
    1419           0 :       SLOG("DropVideoUpToSeekTarget() found video frame [%" PRId64 ", %" PRId64
    1420             :            "] containing target=%" PRId64,
    1421             :            aVideo->mTime.ToMicroseconds(),
    1422             :            aVideo->GetEndTime().ToMicroseconds(),
    1423             :            target.ToMicroseconds());
    1424             : 
    1425           0 :       MOZ_ASSERT(VideoQueue().GetSize() == 0,
    1426             :                  "Should be the 1st sample after seeking");
    1427           0 :       mMaster->PushVideo(aVideo);
    1428           0 :       mDoneVideoSeeking = true;
    1429             :     }
    1430             : 
    1431           0 :     return NS_OK;
    1432             :   }
    1433             : 
    1434           0 :   void MaybeFinishSeek()
    1435             :   {
    1436           0 :     if (mDoneAudioSeeking && mDoneVideoSeeking) {
    1437           0 :       SeekCompleted();
    1438             :     }
    1439           0 :   }
    1440             : 
    1441             :   /*
    1442             :    * Track the current seek promise made by the reader.
    1443             :    */
    1444             :   MozPromiseRequestHolder<MediaDecoderReader::SeekPromise> mSeekRequest;
    1445             : 
    1446             :   /*
    1447             :    * Internal state.
    1448             :    */
    1449             :   media::TimeUnit mCurrentTimeBeforeSeek;
    1450             :   bool mDoneAudioSeeking = false;
    1451             :   bool mDoneVideoSeeking = false;
    1452             :   MozPromiseRequestHolder<WaitForDataPromise> mWaitRequest;
    1453             : 
    1454             :   // This temporarily stores the first frame we decode after we seek.
    1455             :   // This is so that if we hit end of stream while we're decoding to reach
    1456             :   // the seek target, we will still have a frame that we can display as the
    1457             :   // last frame in the media.
    1458             :   RefPtr<VideoData> mFirstVideoFrameAfterSeek;
    1459             : };
    1460             : 
    1461             : /*
    1462             :  * Remove samples from the queue until aCompare() returns false.
    1463             :  * aCompare A function object with the signature bool(int64_t) which returns
    1464             :  *          true for samples that should be removed.
    1465             :  */
    1466             : template <typename Type, typename Function>
    1467             : static void
    1468           0 : DiscardFrames(MediaQueue<Type>& aQueue, const Function& aCompare)
    1469             : {
    1470           0 :   while(aQueue.GetSize() > 0) {
    1471           0 :     if (aCompare(aQueue.PeekFront()->mTime.ToMicroseconds())) {
    1472           0 :       RefPtr<Type> releaseMe = aQueue.PopFront();
    1473           0 :       continue;
    1474             :     }
    1475           0 :     break;
    1476             :   }
    1477           0 : }
    1478             : 
    1479           0 : class MediaDecoderStateMachine::NextFrameSeekingState
    1480             :   : public MediaDecoderStateMachine::SeekingState
    1481             : {
    1482             : public:
    1483           0 :   explicit NextFrameSeekingState(Master* aPtr) : SeekingState(aPtr) { }
    1484             : 
    1485           0 :   RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
    1486             :                                           EventVisibility aVisibility)
    1487             :   {
    1488           0 :     MOZ_ASSERT(aSeekJob.mTarget->IsNextFrame());
    1489           0 :     mCurrentTime = mMaster->GetMediaTime();
    1490           0 :     mDuration = mMaster->Duration();
    1491           0 :     return SeekingState::Enter(Move(aSeekJob), aVisibility);
    1492             :   }
    1493             : 
    1494           0 :   void Exit() override
    1495             :   {
    1496             :     // Disconnect my async seek operation.
    1497           0 :     if (mAsyncSeekTask) { mAsyncSeekTask->Cancel(); }
    1498             : 
    1499             :     // Disconnect MediaDecoder.
    1500           0 :     mSeekJob.RejectIfExists(__func__);
    1501           0 :   }
    1502             : 
    1503           0 :   void HandleAudioDecoded(AudioData* aAudio) override
    1504             :   {
    1505           0 :     mMaster->PushAudio(aAudio);
    1506           0 :   }
    1507             : 
    1508           0 :   void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart) override
    1509             :   {
    1510           0 :     MOZ_ASSERT(aVideo);
    1511           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1512           0 :     MOZ_ASSERT(NeedMoreVideo());
    1513             : 
    1514           0 :     if (aVideo->mTime > mCurrentTime) {
    1515           0 :       mMaster->PushVideo(aVideo);
    1516           0 :       FinishSeek();
    1517             :     } else {
    1518           0 :       RequestVideoData();
    1519             :     }
    1520           0 :   }
    1521             : 
    1522           0 :   void HandleWaitingForAudio() override
    1523             :   {
    1524           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1525             :     // We don't care about audio decode errors in this state which will be
    1526             :     // handled by other states after seeking.
    1527           0 :   }
    1528             : 
    1529           0 :   void HandleAudioCanceled() override
    1530             :   {
    1531           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1532             :     // We don't care about audio decode errors in this state which will be
    1533             :     // handled by other states after seeking.
    1534           0 :   }
    1535             : 
    1536           0 :   void HandleEndOfAudio() override
    1537             :   {
    1538           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1539             :     // We don't care about audio decode errors in this state which will be
    1540             :     // handled by other states after seeking.
    1541           0 :   }
    1542             : 
    1543           0 :   void HandleWaitingForVideo() override
    1544             :   {
    1545           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1546           0 :     MOZ_ASSERT(NeedMoreVideo());
    1547           0 :     mMaster->WaitForData(MediaData::VIDEO_DATA);
    1548           0 :   }
    1549             : 
    1550           0 :   void HandleVideoCanceled() override
    1551             :   {
    1552           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1553           0 :     MOZ_ASSERT(NeedMoreVideo());
    1554           0 :     RequestVideoData();
    1555           0 :   }
    1556             : 
    1557           0 :   void HandleEndOfVideo() override
    1558             :   {
    1559           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1560           0 :     MOZ_ASSERT(NeedMoreVideo());
    1561           0 :     VideoQueue().Finish();
    1562           0 :     FinishSeek();
    1563           0 :   }
    1564             : 
    1565           0 :   void HandleAudioWaited(MediaData::Type aType) override
    1566             :   {
    1567             :     // We don't care about audio in this state.
    1568           0 :   }
    1569             : 
    1570           0 :   void HandleVideoWaited(MediaData::Type aType) override
    1571             :   {
    1572           0 :     MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
    1573           0 :     MOZ_ASSERT(NeedMoreVideo());
    1574           0 :     RequestVideoData();
    1575           0 :   }
    1576             : 
    1577           0 :   TimeUnit CalculateNewCurrentTime() const override
    1578             :   {
    1579             :     // The HTMLMediaElement.currentTime should be updated to the seek target
    1580             :     // which has been updated to the next frame's time.
    1581           0 :     return mSeekJob.mTarget->GetTime();
    1582             :   }
    1583             : 
    1584           0 :   void DoSeek() override
    1585             :   {
    1586           0 :     auto currentTime = mCurrentTime;
    1587           0 :     DiscardFrames(VideoQueue(), [currentTime] (int64_t aSampleTime) {
    1588           0 :       return aSampleTime <= currentTime.ToMicroseconds();
    1589           0 :     });
    1590             : 
    1591             :     // If there is a pending video request, finish the seeking if we don't need
    1592             :     // more data, or wait for HandleVideoDecoded() to finish seeking.
    1593           0 :     if (mMaster->IsRequestingVideoData()) {
    1594           0 :       if (!NeedMoreVideo()) {
    1595           0 :         FinishSeek();
    1596             :       }
    1597           0 :       return;
    1598             :     }
    1599             : 
    1600             :     // Otherwise, we need to do the seek operation asynchronously for a special
    1601             :     // case (bug504613.ogv) which has no data at all, the 1st seekToNextFrame()
    1602             :     // operation reaches the end of the media. If we did the seek operation
    1603             :     // synchronously, we immediately resolve the SeekPromise in mSeekJob and
    1604             :     // then switch to the CompletedState which dispatches an "ended" event.
    1605             :     // However, the ThenValue of the SeekPromise has not yet been set, so the
    1606             :     // promise resolving is postponed and then the JS developer receives the
    1607             :     // "ended" event before the seek promise is resolved.
    1608             :     // An asynchronous seek operation helps to solve this issue since while the
    1609             :     // seek is actually performed, the ThenValue of SeekPromise has already
    1610             :     // been set so that it won't be postponed.
    1611           0 :     RefPtr<Runnable> r = mAsyncSeekTask = new AysncNextFrameSeekTask(this);
    1612           0 :     OwnerThread()->Dispatch(r.forget());
    1613             :   }
    1614             : 
    1615             : private:
    1616           0 :   void DoSeekInternal()
    1617             :   {
    1618             :     // We don't need to discard frames to the mCurrentTime here because we have
    1619             :     // done it at DoSeek() and any video data received in between either
    1620             :     // finishes the seek operation or be discarded, see HandleVideoDecoded().
    1621             : 
    1622           0 :     if (!NeedMoreVideo()) {
    1623           0 :       FinishSeek();
    1624           0 :     } else if (!mMaster->IsRequestingVideoData()
    1625           0 :                && !mMaster->IsWaitingVideoData()) {
    1626           0 :       RequestVideoData();
    1627             :     }
    1628           0 :   }
    1629             : 
    1630           0 :   class AysncNextFrameSeekTask : public Runnable
    1631             :   {
    1632             :   public:
    1633           0 :     explicit AysncNextFrameSeekTask(NextFrameSeekingState* aStateObject)
    1634           0 :       : Runnable("MediaDecoderStateMachine::NextFrameSeekingState::"
    1635             :                  "AysncNextFrameSeekTask")
    1636           0 :       , mStateObj(aStateObject)
    1637             :     {
    1638           0 :     }
    1639             : 
    1640           0 :     void Cancel() { mStateObj = nullptr; }
    1641             : 
    1642           0 :     NS_IMETHOD Run() override
    1643             :     {
    1644           0 :       if (mStateObj) {
    1645           0 :         mStateObj->DoSeekInternal();
    1646             :       }
    1647           0 :       return NS_OK;
    1648             :     }
    1649             : 
    1650             :   private:
    1651             :     NextFrameSeekingState* mStateObj;
    1652             :   };
    1653             : 
    1654           0 :   void RequestVideoData()
    1655             :   {
    1656           0 :     mMaster->RequestVideoData(media::TimeUnit());
    1657           0 :   }
    1658             : 
    1659           0 :   bool NeedMoreVideo() const
    1660             :   {
    1661             :     // Need to request video when we have none and video queue is not finished.
    1662           0 :     return VideoQueue().GetSize() == 0
    1663           0 :            && !VideoQueue().IsFinished();
    1664             :   }
    1665             : 
    1666             :   // Update the seek target's time before resolving this seek task, the updated
    1667             :   // time will be used in the MDSM::SeekCompleted() to update the MDSM's
    1668             :   // position.
    1669           0 :   void UpdateSeekTargetTime()
    1670             :   {
    1671           0 :     RefPtr<VideoData> data = VideoQueue().PeekFront();
    1672           0 :     if (data) {
    1673           0 :       mSeekJob.mTarget->SetTime(data->mTime);
    1674             :     } else {
    1675           0 :       MOZ_ASSERT(VideoQueue().AtEndOfStream());
    1676           0 :       mSeekJob.mTarget->SetTime(mDuration);
    1677             :     }
    1678           0 :   }
    1679             : 
    1680           0 :   void FinishSeek()
    1681             :   {
    1682           0 :     MOZ_ASSERT(!NeedMoreVideo());
    1683           0 :     UpdateSeekTargetTime();
    1684           0 :     auto time = mSeekJob.mTarget->GetTime().ToMicroseconds();
    1685           0 :     DiscardFrames(AudioQueue(), [time] (int64_t aSampleTime) {
    1686             :       return aSampleTime < time;
    1687           0 :     });
    1688           0 :     SeekCompleted();
    1689           0 :   }
    1690             : 
    1691             :   /*
    1692             :    * Internal state.
    1693             :    */
    1694             :   TimeUnit mCurrentTime;
    1695             :   TimeUnit mDuration;
    1696             :   RefPtr<AysncNextFrameSeekTask> mAsyncSeekTask;
    1697             : };
    1698             : 
    1699           0 : class MediaDecoderStateMachine::NextFrameSeekingFromDormantState
    1700             :   : public MediaDecoderStateMachine::AccurateSeekingState
    1701             : {
    1702             : public:
    1703           0 :   explicit NextFrameSeekingFromDormantState(Master* aPtr)
    1704           0 :     : AccurateSeekingState(aPtr)
    1705             :   {
    1706           0 :   }
    1707             : 
    1708           0 :   RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aCurrentSeekJob,
    1709             :                                           SeekJob&& aFutureSeekJob)
    1710             :   {
    1711           0 :     mFutureSeekJob = Move(aFutureSeekJob);
    1712             : 
    1713           0 :     AccurateSeekingState::Enter(Move(aCurrentSeekJob),
    1714           0 :                                 EventVisibility::Suppressed);
    1715             : 
    1716           0 :     return mFutureSeekJob.mPromise.Ensure(__func__);
    1717             :   }
    1718             : 
    1719           0 :   void Exit() override
    1720             :   {
    1721           0 :     mFutureSeekJob.RejectIfExists(__func__);
    1722           0 :     AccurateSeekingState::Exit();
    1723           0 :   }
    1724             : 
    1725             : private:
    1726             :   SeekJob mFutureSeekJob;
    1727             : 
    1728             :   // We don't want to transition to DecodingState once this seek completes,
    1729             :   // instead, we transition to NextFrameSeekingState.
    1730           0 :   void GoToNextState() override
    1731             :   {
    1732           0 :     SetState<NextFrameSeekingState>(Move(mFutureSeekJob),
    1733           0 :                                     EventVisibility::Observable);
    1734           0 :   }
    1735             : };
    1736             : 
    1737           0 : class MediaDecoderStateMachine::VideoOnlySeekingState
    1738             :   : public MediaDecoderStateMachine::AccurateSeekingState
    1739             : {
    1740             : public:
    1741           0 :   explicit VideoOnlySeekingState(Master* aPtr) : AccurateSeekingState(aPtr) { }
    1742             : 
    1743           0 :   RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
    1744             :                                           EventVisibility aVisibility)
    1745             :   {
    1746           0 :     MOZ_ASSERT(aSeekJob.mTarget->IsVideoOnly());
    1747           0 :     MOZ_ASSERT(aVisibility == EventVisibility::Suppressed);
    1748             : 
    1749             :     RefPtr<MediaDecoder::SeekPromise> p =
    1750           0 :       AccurateSeekingState::Enter(Move(aSeekJob), aVisibility);
    1751             : 
    1752             :     // Dispatch a mozvideoonlyseekbegin event to indicate UI for corresponding
    1753             :     // changes.
    1754           0 :     mMaster->mOnPlaybackEvent.Notify(MediaEventType::VideoOnlySeekBegin);
    1755             : 
    1756           0 :     return p.forget();
    1757             :   }
    1758             : 
    1759           0 :   void Exit() override
    1760             :   {
    1761             :     // We are completing or discarding this video-only seek operation now,
    1762             :     // dispatch an event so that the UI can change in response to the end
    1763             :     // of video-only seek.
    1764           0 :     mMaster->mOnPlaybackEvent.Notify(MediaEventType::VideoOnlySeekCompleted);
    1765             : 
    1766           0 :     AccurateSeekingState::Exit();
    1767           0 :   }
    1768             : 
    1769           0 :   void HandleAudioDecoded(AudioData* aAudio) override
    1770             :   {
    1771           0 :     MOZ_ASSERT(mDoneAudioSeeking && !mDoneVideoSeeking,
    1772             :                "Seek shouldn't be finished");
    1773           0 :     MOZ_ASSERT(aAudio);
    1774             : 
    1775             :     // Video-only seek doesn't reset audio decoder. There might be pending audio
    1776             :     // requests when AccurateSeekTask::Seek() begins. We will just store the
    1777             :     // data without checking |mDiscontinuity| or calling
    1778             :     // DropAudioUpToSeekTarget().
    1779           0 :     mMaster->PushAudio(aAudio);
    1780           0 :   }
    1781             : 
    1782           0 :   void HandleWaitingForAudio() override { }
    1783             : 
    1784           0 :   void HandleAudioCanceled() override { }
    1785             : 
    1786           0 :   void HandleEndOfAudio() override { }
    1787             : 
    1788           0 :   void HandleAudioWaited(MediaData::Type aType) override
    1789             :   {
    1790           0 :     MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking,
    1791             :                "Seek shouldn't be finished");
    1792             : 
    1793             :     // Ignore pending requests from video-only seek.
    1794           0 :   }
    1795             : 
    1796           0 :   void DoSeek() override
    1797             :   {
    1798             :     // TODO: keep decoding audio.
    1799           0 :     mDoneAudioSeeking = true;
    1800           0 :     mDoneVideoSeeking = !Info().HasVideo();
    1801             : 
    1802           0 :     mMaster->ResetDecode(TrackInfo::kVideoTrack);
    1803             : 
    1804           0 :     DemuxerSeek();
    1805           0 :   }
    1806             : };
    1807             : 
    1808             : RefPtr<MediaDecoder::SeekPromise>
    1809           0 : MediaDecoderStateMachine::DormantState::HandleSeek(SeekTarget aTarget)
    1810             : {
    1811           0 :   if (aTarget.IsNextFrame()) {
    1812             :     // NextFrameSeekingState doesn't reset the decoder unlike
    1813             :     // AccurateSeekingState. So we first must come out of dormant by seeking to
    1814             :     // mPendingSeek and continue later with the NextFrameSeek
    1815           0 :     SLOG("Changed state to SEEKING (to %" PRId64 ")",
    1816             :         aTarget.GetTime().ToMicroseconds());
    1817           0 :     SeekJob seekJob;
    1818           0 :     seekJob.mTarget = Some(aTarget);
    1819             :     return StateObject::SetState<NextFrameSeekingFromDormantState>(
    1820           0 :       Move(mPendingSeek), Move(seekJob));
    1821             :   }
    1822             : 
    1823           0 :   return StateObject::HandleSeek(aTarget);
    1824             : }
    1825             : 
    1826             : /**
    1827             :  * Purpose: stop playback until enough data is decoded to continue playback.
    1828             :  *
    1829             :  * Transition to:
    1830             :  *   SEEKING if any seek request.
    1831             :  *   SHUTDOWN if any decode error.
    1832             :  *   COMPLETED when having decoded all audio/video data.
    1833             :  *   DECODING when having decoded enough data to continue playback.
    1834             :  */
    1835           0 : class MediaDecoderStateMachine::BufferingState
    1836             :   : public MediaDecoderStateMachine::StateObject
    1837             : {
    1838             : public:
    1839           0 :   explicit BufferingState(Master* aPtr) : StateObject(aPtr) { }
    1840             : 
    1841           0 :   void Enter()
    1842             :   {
    1843           0 :     if (mMaster->IsPlaying()) {
    1844           0 :       mMaster->StopPlayback();
    1845             :     }
    1846             : 
    1847           0 :     mBufferingStart = TimeStamp::Now();
    1848             : 
    1849           0 :     MediaStatistics stats = mMaster->GetStatistics();
    1850           0 :     SLOG("Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
    1851             :          stats.mPlaybackRate / 1024,
    1852             :          stats.mPlaybackRateReliable ? "" : " (unreliable)",
    1853             :          stats.mDownloadRate / 1024,
    1854             :          stats.mDownloadRateReliable ? "" : " (unreliable)");
    1855             : 
    1856           0 :     mMaster->ScheduleStateMachineIn(TimeUnit::FromMicroseconds(USECS_PER_S));
    1857             : 
    1858           0 :     mMaster->UpdateNextFrameStatus(
    1859           0 :       MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING);
    1860           0 :   }
    1861             : 
    1862             :   void Step() override;
    1863             : 
    1864           0 :   State GetState() const override { return DECODER_STATE_BUFFERING; }
    1865             : 
    1866           0 :   void HandleAudioDecoded(AudioData* aAudio) override
    1867             :   {
    1868             :     // This might be the sample we need to exit buffering.
    1869             :     // Schedule Step() to check it.
    1870           0 :     mMaster->PushAudio(aAudio);
    1871           0 :     mMaster->ScheduleStateMachine();
    1872           0 :   }
    1873             : 
    1874           0 :   void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart) override
    1875             :   {
    1876             :     // This might be the sample we need to exit buffering.
    1877             :     // Schedule Step() to check it.
    1878           0 :     mMaster->PushVideo(aVideo);
    1879           0 :     mMaster->ScheduleStateMachine();
    1880           0 :   }
    1881             : 
    1882           0 :   void HandleAudioCanceled() override { mMaster->RequestAudioData(); }
    1883             : 
    1884           0 :   void HandleVideoCanceled() override
    1885             :   {
    1886           0 :     mMaster->RequestVideoData(media::TimeUnit());
    1887           0 :   }
    1888             : 
    1889           0 :   void HandleWaitingForAudio() override
    1890             :   {
    1891           0 :     mMaster->WaitForData(MediaData::AUDIO_DATA);
    1892           0 :   }
    1893             : 
    1894           0 :   void HandleWaitingForVideo() override
    1895             :   {
    1896           0 :     mMaster->WaitForData(MediaData::VIDEO_DATA);
    1897           0 :   }
    1898             : 
    1899           0 :   void HandleAudioWaited(MediaData::Type aType) override
    1900             :   {
    1901           0 :     mMaster->RequestAudioData();
    1902           0 :   }
    1903             : 
    1904           0 :   void HandleVideoWaited(MediaData::Type aType) override
    1905             :   {
    1906           0 :     mMaster->RequestVideoData(media::TimeUnit());
    1907           0 :   }
    1908             : 
    1909             :   void HandleEndOfAudio() override;
    1910             :   void HandleEndOfVideo() override;
    1911             : 
    1912           0 :   void HandleVideoSuspendTimeout() override
    1913             :   {
    1914             :     // No video, so nothing to suspend.
    1915           0 :     if (!mMaster->HasVideo()) {
    1916           0 :      return;
    1917             :     }
    1918             : 
    1919           0 :     mMaster->mVideoDecodeSuspended = true;
    1920           0 :     mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
    1921           0 :     Reader()->SetVideoBlankDecode(true);
    1922             :   }
    1923             : 
    1924             : private:
    1925             :   void DispatchDecodeTasksIfNeeded();
    1926             : 
    1927             :   TimeStamp mBufferingStart;
    1928             : 
    1929             :   // The maximum number of second we spend buffering when we are short on
    1930             :   // unbuffered data.
    1931             :   const uint32_t mBufferingWait = 15;
    1932             : };
    1933             : 
    1934             : /**
    1935             :  * Purpose: play all the decoded data and fire the 'ended' event.
    1936             :  *
    1937             :  * Transition to:
    1938             :  *   SEEKING if any seek request.
    1939             :  */
    1940           0 : class MediaDecoderStateMachine::CompletedState
    1941             :   : public MediaDecoderStateMachine::StateObject
    1942             : {
    1943             : public:
    1944           0 :   explicit CompletedState(Master* aPtr) : StateObject(aPtr) { }
    1945             : 
    1946           0 :   void Enter()
    1947             :   {
    1948             :     // TODO : use more approriate way to decide whether need to release
    1949             :     // resource in bug1367983.
    1950             : #ifndef MOZ_WIDGET_ANDROID
    1951           0 :     if (!mMaster->mLooping) {
    1952             :       // We've decoded all samples.
    1953             :       // We don't need decoders anymore if not looping.
    1954           0 :       Reader()->ReleaseResources();
    1955             :     }
    1956             : #endif
    1957           0 :     bool hasNextFrame = (!mMaster->HasAudio() || !mMaster->mAudioCompleted)
    1958           0 :                         && (!mMaster->HasVideo() || !mMaster->mVideoCompleted);
    1959             : 
    1960           0 :     mMaster->UpdateNextFrameStatus(
    1961             :       hasNextFrame ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
    1962           0 :                    : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
    1963             : 
    1964           0 :     Step();
    1965           0 :   }
    1966             : 
    1967           0 :   void Exit() override
    1968             :   {
    1969           0 :     mSentPlaybackEndedEvent = false;
    1970           0 :   }
    1971             : 
    1972           0 :   void Step() override
    1973             :   {
    1974           0 :     if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING
    1975           0 :         && mMaster->IsPlaying()) {
    1976           0 :       mMaster->StopPlayback();
    1977             :     }
    1978             : 
    1979             :     // Play the remaining media. We want to run AdvanceFrame() at least
    1980             :     // once to ensure the current playback position is advanced to the
    1981             :     // end of the media, and so that we update the readyState.
    1982           0 :     if ((mMaster->HasVideo() && !mMaster->mVideoCompleted)
    1983           0 :         || (mMaster->HasAudio() && !mMaster->mAudioCompleted)) {
    1984             :       // Start playback if necessary to play the remaining media.
    1985           0 :       mMaster->MaybeStartPlayback();
    1986           0 :       mMaster->UpdatePlaybackPositionPeriodically();
    1987           0 :       MOZ_ASSERT(!mMaster->IsPlaying()
    1988             :                  || mMaster->IsStateMachineScheduled(),
    1989             :                  "Must have timer scheduled");
    1990           0 :       return;
    1991             :     }
    1992             : 
    1993             :     // StopPlayback in order to reset the IsPlaying() state so audio
    1994             :     // is restarted correctly.
    1995           0 :     mMaster->StopPlayback();
    1996             : 
    1997           0 :     if (!mSentPlaybackEndedEvent) {
    1998             :       auto clockTime =
    1999           0 :         std::max(mMaster->AudioEndTime(), mMaster->VideoEndTime());
    2000           0 :       clockTime = std::max(clockTime, mMaster->Duration());
    2001           0 :       mMaster->UpdatePlaybackPosition(clockTime);
    2002             : 
    2003             :       // Ensure readyState is updated before firing the 'ended' event.
    2004           0 :       mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
    2005             : 
    2006           0 :       mMaster->mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
    2007             : 
    2008           0 :       mSentPlaybackEndedEvent = true;
    2009             : 
    2010             :       // MediaSink::GetEndTime() must be called before stopping playback.
    2011           0 :       mMaster->StopMediaSink();
    2012             :     }
    2013             :   }
    2014             : 
    2015           0 :   State GetState() const override
    2016             :   {
    2017           0 :     return DECODER_STATE_COMPLETED;
    2018             :   }
    2019             : 
    2020           0 :   void HandleAudioCaptured() override
    2021             :   {
    2022             :     // MediaSink is changed. Schedule Step() to check if we can start playback.
    2023           0 :     mMaster->ScheduleStateMachine();
    2024           0 :   }
    2025             : 
    2026           0 :   void HandleVideoSuspendTimeout() override
    2027             :   {
    2028             :     // Do nothing since no decoding is going on.
    2029           0 :   }
    2030             : 
    2031           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
    2032             :   {
    2033             :     // Resume the video decoder and seek to the last video frame.
    2034             :     // This triggers a video-only seek which won't update the playback position.
    2035           0 :     StateObject::HandleResumeVideoDecoding(mMaster->mDecodedVideoEndTime);
    2036           0 :   }
    2037             : 
    2038           0 :   void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override
    2039             :   {
    2040           0 :     if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
    2041             :       // Schedule Step() to check if we can start playback.
    2042           0 :       mMaster->ScheduleStateMachine();
    2043             :     }
    2044           0 :   }
    2045             : 
    2046             : private:
    2047             :   bool mSentPlaybackEndedEvent = false;
    2048             : };
    2049             : 
    2050             : /**
    2051             :  * Purpose: release all resources allocated by MDSM.
    2052             :  *
    2053             :  * Transition to:
    2054             :  *   None since this is the final state.
    2055             :  *
    2056             :  * Transition from:
    2057             :  *   Any states other than SHUTDOWN.
    2058             :  */
    2059           0 : class MediaDecoderStateMachine::ShutdownState
    2060             :   : public MediaDecoderStateMachine::StateObject
    2061             : {
    2062             : public:
    2063           0 :   explicit ShutdownState(Master* aPtr) : StateObject(aPtr) { }
    2064             : 
    2065             :   RefPtr<ShutdownPromise> Enter();
    2066             : 
    2067           0 :   void Exit() override
    2068             :   {
    2069           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
    2070             :   }
    2071             : 
    2072           0 :   State GetState() const override
    2073             :   {
    2074           0 :     return DECODER_STATE_SHUTDOWN;
    2075             :   }
    2076             : 
    2077           0 :   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
    2078             :   {
    2079           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in shutdown state.");
    2080             :     return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
    2081             :   }
    2082             : 
    2083           0 :   RefPtr<ShutdownPromise> HandleShutdown() override
    2084             :   {
    2085           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
    2086             :     return nullptr;
    2087             :   }
    2088             : 
    2089           0 :   void HandleVideoSuspendTimeout() override
    2090             :   {
    2091           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
    2092             :   }
    2093             : 
    2094           0 :   void HandleResumeVideoDecoding(const TimeUnit&) override
    2095             :   {
    2096           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
    2097             :   }
    2098             : };
    2099             : 
    2100             : RefPtr<MediaDecoder::SeekPromise>
    2101           0 : MediaDecoderStateMachine::
    2102             : StateObject::HandleSeek(SeekTarget aTarget)
    2103             : {
    2104           0 :   SLOG("Changed state to SEEKING (to %" PRId64 ")", aTarget.GetTime().ToMicroseconds());
    2105           0 :   SeekJob seekJob;
    2106           0 :   seekJob.mTarget = Some(aTarget);
    2107           0 :   return SetSeekingState(Move(seekJob), EventVisibility::Observable);
    2108             : }
    2109             : 
    2110             : RefPtr<ShutdownPromise>
    2111           0 : MediaDecoderStateMachine::
    2112             : StateObject::HandleShutdown()
    2113             : {
    2114           0 :   return SetState<ShutdownState>();
    2115             : }
    2116             : 
    2117             : static void
    2118           0 : ReportRecoveryTelemetry(const TimeStamp& aRecoveryStart,
    2119             :                         const MediaInfo& aMediaInfo,
    2120             :                         bool aIsHardwareAccelerated)
    2121             : {
    2122           0 :   MOZ_ASSERT(NS_IsMainThread());
    2123           0 :   if (!aMediaInfo.HasVideo()) {
    2124           0 :     return;
    2125             :   }
    2126             : 
    2127             :   // Keyed by audio+video or video alone, hardware acceleration,
    2128             :   // and by a resolution range.
    2129           0 :   nsCString key(aMediaInfo.HasAudio() ? "AV" : "V");
    2130           0 :   key.AppendASCII(aIsHardwareAccelerated ? "(hw)," : ",");
    2131             :   static const struct { int32_t mH; const char* mRes; } sResolutions[] = {
    2132             :     {  240, "0-240" },
    2133             :     {  480, "241-480" },
    2134             :     {  720, "481-720" },
    2135             :     { 1080, "721-1080" },
    2136             :     { 2160, "1081-2160" }
    2137             :   };
    2138           0 :   const char* resolution = "2161+";
    2139           0 :   int32_t height = aMediaInfo.mVideo.mImage.height;
    2140           0 :   for (const auto& res : sResolutions) {
    2141           0 :     if (height <= res.mH) {
    2142           0 :       resolution = res.mRes;
    2143           0 :       break;
    2144             :     }
    2145             :   }
    2146           0 :   key.AppendASCII(resolution);
    2147             : 
    2148           0 :   TimeDuration duration = TimeStamp::Now() - aRecoveryStart;
    2149           0 :   double duration_ms = duration.ToMilliseconds();
    2150           0 :   Telemetry::Accumulate(Telemetry::VIDEO_SUSPEND_RECOVERY_TIME_MS,
    2151             :                         key,
    2152           0 :                         uint32_t(duration_ms + 0.5));
    2153           0 :   Telemetry::Accumulate(Telemetry::VIDEO_SUSPEND_RECOVERY_TIME_MS,
    2154           0 :                         NS_LITERAL_CSTRING("All"),
    2155           0 :                         uint32_t(duration_ms + 0.5));
    2156             : }
    2157             : 
    2158             : void
    2159           0 : MediaDecoderStateMachine::
    2160             : StateObject::HandleResumeVideoDecoding(const TimeUnit& aTarget)
    2161             : {
    2162           0 :   MOZ_ASSERT(mMaster->mVideoDecodeSuspended);
    2163             : 
    2164             :   // Start counting recovery time from right now.
    2165           0 :   TimeStamp start = TimeStamp::Now();
    2166             : 
    2167             :   // Local reference to mInfo, so that it will be copied in the lambda below.
    2168           0 :   auto& info = Info();
    2169           0 :   bool hw = Reader()->VideoIsHardwareAccelerated();
    2170             : 
    2171             :   // Start video-only seek to the current time.
    2172           0 :   SeekJob seekJob;
    2173             : 
    2174             :   // We use fastseek to optimize the resuming time.
    2175             :   // FastSeek is only used for video-only media since we don't need to worry
    2176             :   // about A/V sync.
    2177             :   // Don't use fastSeek if we want to seek to the end because it might seek to a
    2178             :   // keyframe before the last frame (if the last frame itself is not a keyframe)
    2179             :   // and we always want to present the final frame to the user when seeking to
    2180             :   // the end.
    2181           0 :   const auto type = mMaster->HasAudio() || aTarget == mMaster->Duration()
    2182           0 :                     ? SeekTarget::Type::Accurate
    2183           0 :                     : SeekTarget::Type::PrevSyncPoint;
    2184             : 
    2185           0 :   seekJob.mTarget.emplace(aTarget, type, true /* aVideoOnly */);
    2186             : 
    2187             :   // Hold mMaster->mAbstractMainThread here because this->mMaster will be
    2188             :   // invalid after the current state object is deleted in SetState();
    2189           0 :   RefPtr<AbstractThread> mainThread = mMaster->mAbstractMainThread;
    2190             : 
    2191           0 :   SetSeekingState(Move(seekJob), EventVisibility::Suppressed)->Then(
    2192             :     mainThread, __func__,
    2193           0 :     [start, info, hw](){ ReportRecoveryTelemetry(start, info, hw); },
    2194           0 :     [](){});
    2195           0 : }
    2196             : 
    2197             : RefPtr<MediaDecoder::SeekPromise>
    2198           0 : MediaDecoderStateMachine::
    2199             : StateObject::SetSeekingState(SeekJob&& aSeekJob, EventVisibility aVisibility)
    2200             : {
    2201           0 :   if (aSeekJob.mTarget->IsAccurate() || aSeekJob.mTarget->IsFast()) {
    2202           0 :     if (aSeekJob.mTarget->IsVideoOnly()) {
    2203           0 :       return SetState<VideoOnlySeekingState>(Move(aSeekJob), aVisibility);
    2204             :     }
    2205           0 :     return SetState<AccurateSeekingState>(Move(aSeekJob), aVisibility);
    2206             :   }
    2207             : 
    2208           0 :   if (aSeekJob.mTarget->IsNextFrame()) {
    2209           0 :     return SetState<NextFrameSeekingState>(Move(aSeekJob), aVisibility);
    2210             :   }
    2211             : 
    2212           0 :   MOZ_ASSERT_UNREACHABLE("Unknown SeekTarget::Type.");
    2213             :   return nullptr;
    2214             : }
    2215             : 
    2216             : void
    2217           0 : MediaDecoderStateMachine::
    2218             : DecodeMetadataState::OnMetadataRead(MetadataHolder&& aMetadata)
    2219             : {
    2220           0 :   mMetadataRequest.Complete();
    2221             : 
    2222             :   // Set mode to PLAYBACK after reading metadata.
    2223           0 :   Resource()->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
    2224             : 
    2225           0 :   mMaster->mInfo.emplace(*aMetadata.mInfo);
    2226           0 :   mMaster->mMediaSeekable = Info().mMediaSeekable;
    2227           0 :   mMaster->mMediaSeekableOnlyInBufferedRanges =
    2228           0 :     Info().mMediaSeekableOnlyInBufferedRanges;
    2229             : 
    2230           0 :   if (Info().mMetadataDuration.isSome()) {
    2231           0 :     mMaster->RecomputeDuration();
    2232           0 :   } else if (Info().mUnadjustedMetadataEndTime.isSome()) {
    2233           0 :     const TimeUnit unadjusted = Info().mUnadjustedMetadataEndTime.ref();
    2234           0 :     const TimeUnit adjustment = Info().mStartTime;
    2235           0 :     mMaster->mInfo->mMetadataDuration.emplace(unadjusted - adjustment);
    2236           0 :     mMaster->RecomputeDuration();
    2237             :   }
    2238             : 
    2239             :   // If we don't know the duration by this point, we assume infinity, per spec.
    2240           0 :   if (mMaster->mDuration.Ref().isNothing()) {
    2241           0 :     mMaster->mDuration = Some(TimeUnit::FromInfinity());
    2242             :   }
    2243             : 
    2244           0 :   if (mMaster->HasVideo()) {
    2245           0 :     SLOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
    2246             :          Reader()->IsAsync(),
    2247             :          Reader()->VideoIsHardwareAccelerated(),
    2248             :          mMaster->GetAmpleVideoFrames());
    2249             :   }
    2250             : 
    2251           0 :   MOZ_ASSERT(mMaster->mDuration.Ref().isSome());
    2252             : 
    2253           0 :   mMaster->mMetadataLoadedEvent.Notify(
    2254           0 :     Move(aMetadata.mInfo),
    2255           0 :     Move(aMetadata.mTags),
    2256           0 :     MediaDecoderEventVisibility::Observable);
    2257             : 
    2258           0 :   if (Info().IsEncrypted() && !mMaster->mCDMProxy) {
    2259             :     // Metadata parsing was successful but we're still waiting for CDM caps
    2260             :     // to become available so that we can build the correct decryptor/decoder.
    2261           0 :     SetState<WaitForCDMState>();
    2262             :   } else {
    2263           0 :     SetState<DecodingFirstFrameState>();
    2264             :   }
    2265           0 : }
    2266             : 
    2267             : void
    2268           0 : MediaDecoderStateMachine::
    2269             : DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
    2270             : {
    2271           0 :   if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
    2272             :     // Exit dormant when the user wants to play.
    2273           0 :     MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
    2274           0 :     MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
    2275           0 :     SetSeekingState(Move(mPendingSeek), EventVisibility::Suppressed);
    2276             :   }
    2277           0 : }
    2278             : 
    2279             : void
    2280           0 : MediaDecoderStateMachine::
    2281             : WaitForCDMState::HandleCDMProxyReady()
    2282             : {
    2283           0 :   if (mPendingSeek.Exists()) {
    2284           0 :     SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
    2285             :   } else {
    2286           0 :     SetState<DecodingFirstFrameState>();
    2287             :   }
    2288           0 : }
    2289             : 
    2290             : void
    2291           0 : MediaDecoderStateMachine::
    2292             : DecodingFirstFrameState::Enter()
    2293             : {
    2294             :   // Transition to DECODING if we've decoded first frames.
    2295           0 :   if (mMaster->mSentFirstFrameLoadedEvent) {
    2296           0 :     SetState<DecodingState>();
    2297           0 :     return;
    2298             :   }
    2299             : 
    2300           0 :   MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
    2301             : 
    2302             :   // Dispatch tasks to decode first frames.
    2303           0 :   if (mMaster->HasAudio()) {
    2304           0 :     mMaster->RequestAudioData();
    2305             :   }
    2306           0 :   if (mMaster->HasVideo()) {
    2307           0 :     mMaster->RequestVideoData(media::TimeUnit());
    2308             :   }
    2309             : }
    2310             : 
    2311             : void
    2312           0 : MediaDecoderStateMachine::
    2313             : DecodingFirstFrameState::MaybeFinishDecodeFirstFrame()
    2314             : {
    2315           0 :   MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
    2316             : 
    2317           0 :   if ((mMaster->IsAudioDecoding() && AudioQueue().GetSize() == 0)
    2318           0 :       || (mMaster->IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
    2319           0 :     return;
    2320             :   }
    2321             : 
    2322           0 :   mMaster->FinishDecodeFirstFrame();
    2323           0 :   if (mPendingSeek.Exists()) {
    2324           0 :     SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
    2325             :   } else {
    2326           0 :     SetState<DecodingState>();
    2327             :   }
    2328             : }
    2329             : 
    2330             : void
    2331           0 : MediaDecoderStateMachine::
    2332             : DecodingState::Enter()
    2333             : {
    2334           0 :   MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
    2335             : 
    2336           0 :   if (mMaster->mVideoDecodeMode == VideoDecodeMode::Suspend
    2337           0 :       && !mMaster->mVideoDecodeSuspendTimer.IsScheduled()
    2338           0 :       && !mMaster->mVideoDecodeSuspended) {
    2339             :     // If the VideoDecodeMode is Suspend and the timer is not schedule, it means
    2340             :     // the timer has timed out and we should suspend video decoding now if
    2341             :     // necessary.
    2342           0 :     HandleVideoSuspendTimeout();
    2343             :   }
    2344             : 
    2345           0 :   if (!mMaster->IsVideoDecoding() && !mMaster->IsAudioDecoding()) {
    2346           0 :     SetState<CompletedState>();
    2347           0 :     return;
    2348             :   }
    2349             : 
    2350           0 :   mOnAudioPopped = AudioQueue().PopEvent().Connect(
    2351           0 :     OwnerThread(), [this] () {
    2352           0 :     if (mMaster->IsAudioDecoding() && !mMaster->HaveEnoughDecodedAudio()) {
    2353           0 :       EnsureAudioDecodeTaskQueued();
    2354             :     }
    2355           0 :   });
    2356           0 :   mOnVideoPopped = VideoQueue().PopEvent().Connect(
    2357           0 :     OwnerThread(), [this] () {
    2358           0 :     if (mMaster->IsVideoDecoding() && !mMaster->HaveEnoughDecodedVideo()) {
    2359           0 :       EnsureVideoDecodeTaskQueued();
    2360             :     }
    2361           0 :   });
    2362             : 
    2363           0 :   mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_AVAILABLE);
    2364             : 
    2365           0 :   mDecodeStartTime = TimeStamp::Now();
    2366             : 
    2367           0 :   MaybeStopPrerolling();
    2368             : 
    2369             :   // Ensure that we've got tasks enqueued to decode data if we need to.
    2370           0 :   DispatchDecodeTasksIfNeeded();
    2371             : 
    2372           0 :   mMaster->ScheduleStateMachine();
    2373             : 
    2374             :   // Will enter dormant when playback is paused for a while.
    2375           0 :   if (mMaster->mPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
    2376           0 :     StartDormantTimer();
    2377             :   }
    2378             : }
    2379             : 
    2380             : void
    2381           0 : MediaDecoderStateMachine::
    2382             : DecodingState::HandleEndOfAudio()
    2383             : {
    2384           0 :   AudioQueue().Finish();
    2385           0 :   if (!mMaster->IsVideoDecoding()) {
    2386           0 :     SetState<CompletedState>();
    2387             :   } else {
    2388           0 :     MaybeStopPrerolling();
    2389             :   }
    2390           0 : }
    2391             : 
    2392             : void
    2393           0 : MediaDecoderStateMachine::
    2394             : DecodingState::HandleEndOfVideo()
    2395             : {
    2396           0 :   VideoQueue().Finish();
    2397           0 :   if (!mMaster->IsAudioDecoding()) {
    2398           0 :     SetState<CompletedState>();
    2399             :   } else {
    2400           0 :     MaybeStopPrerolling();
    2401             :   }
    2402           0 : }
    2403             : 
    2404             : void
    2405           0 : MediaDecoderStateMachine::
    2406             : DecodingState::DispatchDecodeTasksIfNeeded()
    2407             : {
    2408           0 :   if (mMaster->IsAudioDecoding()
    2409           0 :       && !mMaster->mMinimizePreroll
    2410           0 :       && !mMaster->HaveEnoughDecodedAudio()) {
    2411           0 :     EnsureAudioDecodeTaskQueued();
    2412             :   }
    2413             : 
    2414           0 :   if (mMaster->IsVideoDecoding()
    2415           0 :       && !mMaster->mMinimizePreroll
    2416           0 :       && !mMaster->HaveEnoughDecodedVideo()) {
    2417           0 :     EnsureVideoDecodeTaskQueued();
    2418             :   }
    2419           0 : }
    2420             : 
    2421             : void
    2422           0 : MediaDecoderStateMachine::
    2423             : DecodingState::EnsureAudioDecodeTaskQueued()
    2424             : {
    2425           0 :   if (!mMaster->IsAudioDecoding()
    2426           0 :       || mMaster->IsRequestingAudioData()
    2427           0 :       || mMaster->IsWaitingAudioData()) {
    2428           0 :     return;
    2429             :   }
    2430           0 :   mMaster->RequestAudioData();
    2431             : }
    2432             : 
    2433             : void
    2434           0 : MediaDecoderStateMachine::
    2435             : DecodingState::EnsureVideoDecodeTaskQueued()
    2436             : {
    2437           0 :   if (!mMaster->IsVideoDecoding()
    2438           0 :       || mMaster->IsRequestingVideoData()
    2439           0 :       || mMaster->IsWaitingVideoData()) {
    2440           0 :     return;
    2441             :   }
    2442           0 :   mMaster->RequestVideoData(mMaster->GetMediaTime());
    2443             : }
    2444             : 
    2445             : void
    2446           0 : MediaDecoderStateMachine::
    2447             : DecodingState::MaybeStartBuffering()
    2448             : {
    2449             :   // Buffering makes senses only after decoding first frames.
    2450           0 :   MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
    2451             : 
    2452             :   // Don't enter buffering when MediaDecoder is not playing.
    2453           0 :   if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
    2454           0 :     return;
    2455             :   }
    2456             : 
    2457             :   // Don't enter buffering while prerolling so that the decoder has a chance to
    2458             :   // enqueue some decoded data before we give up and start buffering.
    2459           0 :   if (!mMaster->IsPlaying()) {
    2460           0 :     return;
    2461             :   }
    2462             : 
    2463             :   bool shouldBuffer;
    2464           0 :   if (Reader()->UseBufferingHeuristics()) {
    2465           0 :     shouldBuffer = IsExpectingMoreData()
    2466           0 :                    && mMaster->HasLowDecodedData()
    2467           0 :                    && mMaster->HasLowBufferedData();
    2468             :   } else {
    2469           0 :     shouldBuffer =
    2470           0 :       (mMaster->OutOfDecodedAudio() && mMaster->IsWaitingAudioData())
    2471           0 :       || (mMaster->OutOfDecodedVideo() && mMaster->IsWaitingVideoData());
    2472             :   }
    2473           0 :   if (shouldBuffer) {
    2474           0 :     SetState<BufferingState>();
    2475             :   }
    2476             : }
    2477             : 
    2478             : void
    2479           0 : MediaDecoderStateMachine::
    2480             : SeekingState::SeekCompleted()
    2481             : {
    2482           0 :   const auto newCurrentTime = CalculateNewCurrentTime();
    2483             : 
    2484           0 :   bool isLiveStream = Resource()->IsLiveStream();
    2485           0 :   if (newCurrentTime == mMaster->Duration() && !isLiveStream) {
    2486             :     // Seeked to end of media. Explicitly finish the queues so DECODING
    2487             :     // will transition to COMPLETED immediately. Note we don't do
    2488             :     // this when playing a live stream, since the end of media will advance
    2489             :     // once we download more data!
    2490           0 :     AudioQueue().Finish();
    2491           0 :     VideoQueue().Finish();
    2492             : 
    2493             :     // We won't start MediaSink when paused. m{Audio,Video}Completed will
    2494             :     // remain false and 'playbackEnded' won't be notified. Therefore we
    2495             :     // need to set these flags explicitly when seeking to the end.
    2496           0 :     mMaster->mAudioCompleted = true;
    2497           0 :     mMaster->mVideoCompleted = true;
    2498             : 
    2499             :     // There might still be a pending audio request when doing video-only or
    2500             :     // next-frame seek. Discard it so we won't break the invariants of the
    2501             :     // COMPLETED state by adding audio samples to a finished queue.
    2502           0 :     mMaster->mAudioDataRequest.DisconnectIfExists();
    2503             :   }
    2504             : 
    2505             :   // We want to resolve the seek request prior finishing the first frame
    2506             :   // to ensure that the seeked event is fired prior loadeded.
    2507             :   // Note: SeekJob.Resolve() resets SeekJob.mTarget. Don't use mSeekJob anymore
    2508             :   //       hereafter.
    2509           0 :   mSeekJob.Resolve(__func__);
    2510             : 
    2511             :   // Notify FirstFrameLoaded now if we haven't since we've decoded some data
    2512             :   // for readyState to transition to HAVE_CURRENT_DATA and fire 'loadeddata'.
    2513           0 :   if (!mMaster->mSentFirstFrameLoadedEvent) {
    2514           0 :     mMaster->FinishDecodeFirstFrame();
    2515             :   }
    2516             : 
    2517             :   // Ensure timestamps are up to date.
    2518             :   // Suppressed visibility comes from two cases: (1) leaving dormant state,
    2519             :   // and (2) resuming suspended video decoder. We want both cases to be
    2520             :   // transparent to the user. So we only notify the change when the seek
    2521             :   // request is from the user.
    2522           0 :   if (mVisibility == EventVisibility::Observable) {
    2523             :     // Don't update playback position for video-only seek.
    2524             :     // Otherwise we might have |newCurrentTime > mMediaSink->GetPosition()|
    2525             :     // and fail the assertion in GetClock() since we didn't stop MediaSink.
    2526           0 :     mMaster->UpdatePlaybackPositionInternal(newCurrentTime);
    2527             :   }
    2528             : 
    2529             :   // Try to decode another frame to detect if we're at the end...
    2530           0 :   SLOG("Seek completed, mCurrentPosition=%" PRId64,
    2531             :        mMaster->mCurrentPosition.Ref().ToMicroseconds());
    2532             : 
    2533           0 :   if (mMaster->VideoQueue().PeekFront()) {
    2534           0 :     mMaster->mMediaSink->Redraw(Info().mVideo);
    2535           0 :     mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
    2536             :   }
    2537             : 
    2538           0 :   GoToNextState();
    2539           0 : }
    2540             : 
    2541             : void
    2542           0 : MediaDecoderStateMachine::
    2543             : BufferingState::DispatchDecodeTasksIfNeeded()
    2544             : {
    2545           0 :   if (mMaster->IsAudioDecoding()
    2546           0 :       && !mMaster->HaveEnoughDecodedAudio()
    2547           0 :       && !mMaster->IsRequestingAudioData()
    2548           0 :       && !mMaster->IsWaitingAudioData()) {
    2549           0 :     mMaster->RequestAudioData();
    2550             :   }
    2551             : 
    2552           0 :   if (mMaster->IsVideoDecoding()
    2553           0 :       && !mMaster->HaveEnoughDecodedVideo()
    2554           0 :       && !mMaster->IsRequestingVideoData()
    2555           0 :       && !mMaster->IsWaitingVideoData()) {
    2556           0 :     mMaster->RequestVideoData(media::TimeUnit());
    2557             :   }
    2558           0 : }
    2559             : 
    2560             : void
    2561           0 : MediaDecoderStateMachine::
    2562             : BufferingState::Step()
    2563             : {
    2564           0 :   TimeStamp now = TimeStamp::Now();
    2565           0 :   MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
    2566             : 
    2567             :   // With buffering heuristics we will remain in the buffering state if
    2568             :   // we've not decoded enough data to begin playback, or if we've not
    2569             :   // downloaded a reasonable amount of data inside our buffering time.
    2570           0 :   if (Reader()->UseBufferingHeuristics()) {
    2571           0 :     TimeDuration elapsed = now - mBufferingStart;
    2572           0 :     bool isLiveStream = Resource()->IsLiveStream();
    2573           0 :     if ((isLiveStream || !mMaster->CanPlayThrough())
    2574           0 :         && elapsed
    2575           0 :            < TimeDuration::FromSeconds(mBufferingWait * mMaster->mPlaybackRate)
    2576           0 :         && mMaster->HasLowBufferedData(TimeUnit::FromSeconds(mBufferingWait))
    2577           0 :         && IsExpectingMoreData()) {
    2578           0 :       SLOG("Buffering: wait %ds, timeout in %.3lfs",
    2579             :            mBufferingWait, mBufferingWait - elapsed.ToSeconds());
    2580           0 :       mMaster->ScheduleStateMachineIn(TimeUnit::FromMicroseconds(USECS_PER_S));
    2581           0 :       DispatchDecodeTasksIfNeeded();
    2582           0 :       return;
    2583             :     }
    2584           0 :   } else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
    2585           0 :     DispatchDecodeTasksIfNeeded();
    2586           0 :     MOZ_ASSERT(!mMaster->OutOfDecodedAudio()
    2587             :                || mMaster->IsRequestingAudioData()
    2588             :                || mMaster->IsWaitingAudioData());
    2589           0 :     MOZ_ASSERT(!mMaster->OutOfDecodedVideo()
    2590             :                || mMaster->IsRequestingVideoData()
    2591             :                || mMaster->IsWaitingVideoData());
    2592           0 :     SLOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
    2593             :          "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
    2594             :          mMaster->OutOfDecodedAudio(), mMaster->AudioRequestStatus(),
    2595             :          mMaster->OutOfDecodedVideo(), mMaster->VideoRequestStatus());
    2596           0 :     return;
    2597             :   }
    2598             : 
    2599           0 :   SLOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
    2600           0 :   SetState<DecodingState>();
    2601             : }
    2602             : 
    2603             : void
    2604           0 : MediaDecoderStateMachine::
    2605             : BufferingState::HandleEndOfAudio()
    2606             : {
    2607           0 :   AudioQueue().Finish();
    2608           0 :   if (!mMaster->IsVideoDecoding()) {
    2609           0 :     SetState<CompletedState>();
    2610             :   } else {
    2611             :     // Check if we can exit buffering.
    2612           0 :     mMaster->ScheduleStateMachine();
    2613             :   }
    2614           0 : }
    2615             : 
    2616             : void
    2617           0 : MediaDecoderStateMachine::
    2618             : BufferingState::HandleEndOfVideo()
    2619             : {
    2620           0 :   VideoQueue().Finish();
    2621           0 :   if (!mMaster->IsAudioDecoding()) {
    2622           0 :     SetState<CompletedState>();
    2623             :   } else {
    2624             :     // Check if we can exit buffering.
    2625           0 :     mMaster->ScheduleStateMachine();
    2626             :   }
    2627           0 : }
    2628             : 
    2629             : RefPtr<ShutdownPromise>
    2630           0 : MediaDecoderStateMachine::
    2631             : ShutdownState::Enter()
    2632             : {
    2633           0 :   auto master = mMaster;
    2634             : 
    2635           0 :   master->mDelayedScheduler.Reset();
    2636             : 
    2637             :   // Shutdown happens while decode timer is active, we need to disconnect and
    2638             :   // dispose of the timer.
    2639           0 :   master->CancelSuspendTimer();
    2640             : 
    2641           0 :   master->mCDMProxyPromise.DisconnectIfExists();
    2642             : 
    2643           0 :   if (master->IsPlaying()) {
    2644           0 :     master->StopPlayback();
    2645             :   }
    2646             : 
    2647           0 :   master->mAudioDataRequest.DisconnectIfExists();
    2648           0 :   master->mVideoDataRequest.DisconnectIfExists();
    2649           0 :   master->mAudioWaitRequest.DisconnectIfExists();
    2650           0 :   master->mVideoWaitRequest.DisconnectIfExists();
    2651             : 
    2652           0 :   master->ResetDecode();
    2653           0 :   master->StopMediaSink();
    2654           0 :   master->mMediaSink->Shutdown();
    2655             : 
    2656             :   // Prevent dangling pointers by disconnecting the listeners.
    2657           0 :   master->mAudioQueueListener.Disconnect();
    2658           0 :   master->mVideoQueueListener.Disconnect();
    2659           0 :   master->mMetadataManager.Disconnect();
    2660           0 :   master->mOnMediaNotSeekable.Disconnect();
    2661             : 
    2662             :   // Disconnect canonicals and mirrors before shutting down our task queue.
    2663           0 :   master->mBuffered.DisconnectIfConnected();
    2664           0 :   master->mExplicitDuration.DisconnectIfConnected();
    2665           0 :   master->mPlayState.DisconnectIfConnected();
    2666           0 :   master->mNextPlayState.DisconnectIfConnected();
    2667           0 :   master->mVolume.DisconnectIfConnected();
    2668           0 :   master->mPreservesPitch.DisconnectIfConnected();
    2669           0 :   master->mLooping.DisconnectIfConnected();
    2670           0 :   master->mSameOriginMedia.DisconnectIfConnected();
    2671           0 :   master->mMediaPrincipalHandle.DisconnectIfConnected();
    2672           0 :   master->mPlaybackBytesPerSecond.DisconnectIfConnected();
    2673           0 :   master->mPlaybackRateReliable.DisconnectIfConnected();
    2674           0 :   master->mDecoderPosition.DisconnectIfConnected();
    2675             : 
    2676           0 :   master->mDuration.DisconnectAll();
    2677           0 :   master->mNextFrameStatus.DisconnectAll();
    2678           0 :   master->mCurrentPosition.DisconnectAll();
    2679           0 :   master->mPlaybackOffset.DisconnectAll();
    2680           0 :   master->mIsAudioDataAudible.DisconnectAll();
    2681             : 
    2682             :   // Shut down the watch manager to stop further notifications.
    2683           0 :   master->mWatchManager.Shutdown();
    2684             : 
    2685           0 :   return Reader()->Shutdown()->Then(
    2686           0 :     OwnerThread(), __func__, master,
    2687             :     &MediaDecoderStateMachine::FinishShutdown,
    2688           0 :     &MediaDecoderStateMachine::FinishShutdown);
    2689             : }
    2690             : 
    2691             : #define INIT_WATCHABLE(name, val) \
    2692             :   name(val, "MediaDecoderStateMachine::" #name)
    2693             : #define INIT_MIRROR(name, val) \
    2694             :   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Mirror)")
    2695             : #define INIT_CANONICAL(name, val) \
    2696             :   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Canonical)")
    2697             : 
    2698           0 : MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
    2699           0 :                                                    MediaDecoderReader* aReader) :
    2700             :   mDecoderID(aDecoder),
    2701             :   mAbstractMainThread(aDecoder->AbstractMainThread()),
    2702           0 :   mFrameStats(&aDecoder->GetFrameStatistics()),
    2703             :   mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
    2704           0 :   mAudioChannel(aDecoder->GetAudioChannel()),
    2705             :   mTaskQueue(new TaskQueue(
    2706           0 :     GetMediaThreadPool(MediaThreadType::PLAYBACK),
    2707           0 :     "MDSM::mTaskQueue", /* aSupportsTailDispatch = */ true)),
    2708             :   mWatchManager(this, mTaskQueue),
    2709             :   mDispatchedStateMachine(false),
    2710             :   mDelayedScheduler(mTaskQueue),
    2711             :   mCurrentFrameID(0),
    2712           0 :   INIT_WATCHABLE(mObservedDuration, TimeUnit()),
    2713           0 :   mReader(new MediaDecoderReaderWrapper(mTaskQueue, aReader)),
    2714             :   mPlaybackRate(1.0),
    2715             :   mLowAudioThreshold(detail::LOW_AUDIO_THRESHOLD),
    2716             :   mAmpleAudioThreshold(detail::AMPLE_AUDIO_THRESHOLD),
    2717             :   mAudioCaptured(false),
    2718           0 :   mMinimizePreroll(aDecoder->GetMinimizePreroll()),
    2719             :   mSentFirstFrameLoadedEvent(false),
    2720             :   mVideoDecodeSuspended(false),
    2721             :   mVideoDecodeSuspendTimer(mTaskQueue),
    2722           0 :   mOutputStreamManager(new OutputStreamManager()),
    2723             :   mResource(aDecoder->GetResource()),
    2724             :   mVideoDecodeMode(VideoDecodeMode::Normal),
    2725           0 :   mIsMSE(aDecoder->IsMSE()),
    2726           0 :   INIT_MIRROR(mBuffered, TimeIntervals()),
    2727           0 :   INIT_MIRROR(mExplicitDuration, Maybe<double>()),
    2728             :   INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
    2729             :   INIT_MIRROR(mNextPlayState, MediaDecoder::PLAY_STATE_PAUSED),
    2730             :   INIT_MIRROR(mVolume, 1.0),
    2731             :   INIT_MIRROR(mPreservesPitch, true),
    2732             :   INIT_MIRROR(mLooping, false),
    2733             :   INIT_MIRROR(mSameOriginMedia, false),
    2734             :   INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
    2735             :   INIT_MIRROR(mPlaybackBytesPerSecond, 0.0),
    2736             :   INIT_MIRROR(mPlaybackRateReliable, true),
    2737             :   INIT_MIRROR(mDecoderPosition, 0),
    2738           0 :   INIT_CANONICAL(mDuration, NullableTimeUnit()),
    2739             :   INIT_CANONICAL(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE),
    2740           0 :   INIT_CANONICAL(mCurrentPosition, TimeUnit::Zero()),
    2741             :   INIT_CANONICAL(mPlaybackOffset, 0),
    2742           0 :   INIT_CANONICAL(mIsAudioDataAudible, false)
    2743             : #ifdef XP_WIN
    2744             :   , mShouldUseHiResTimers(Preferences::GetBool("media.hi-res-timers.enabled", true))
    2745             : #endif
    2746             : {
    2747           0 :   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
    2748           0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
    2749             : 
    2750           0 :   InitVideoQueuePrefs();
    2751           0 : }
    2752             : 
    2753             : #undef INIT_WATCHABLE
    2754             : #undef INIT_MIRROR
    2755             : #undef INIT_CANONICAL
    2756             : 
    2757           0 : MediaDecoderStateMachine::~MediaDecoderStateMachine()
    2758             : {
    2759           0 :   MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread.");
    2760           0 :   MOZ_COUNT_DTOR(MediaDecoderStateMachine);
    2761             : 
    2762             : #ifdef XP_WIN
    2763             :   MOZ_ASSERT(!mHiResTimersRequested);
    2764             : #endif
    2765           0 : }
    2766             : 
    2767             : void
    2768           0 : MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
    2769             : {
    2770           0 :   MOZ_ASSERT(OnTaskQueue());
    2771             : 
    2772             :   // Connect mirrors.
    2773           0 :   mBuffered.Connect(mReader->CanonicalBuffered());
    2774           0 :   mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
    2775           0 :   mPlayState.Connect(aDecoder->CanonicalPlayState());
    2776           0 :   mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
    2777           0 :   mVolume.Connect(aDecoder->CanonicalVolume());
    2778           0 :   mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
    2779           0 :   mLooping.Connect(aDecoder->CanonicalLooping());
    2780           0 :   mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
    2781           0 :   mMediaPrincipalHandle.Connect(aDecoder->CanonicalMediaPrincipalHandle());
    2782           0 :   mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
    2783           0 :   mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
    2784           0 :   mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
    2785             : 
    2786             :   // Initialize watchers.
    2787           0 :   mWatchManager.Watch(mBuffered,
    2788           0 :                       &MediaDecoderStateMachine::BufferedRangeUpdated);
    2789           0 :   mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
    2790           0 :   mWatchManager.Watch(mPreservesPitch,
    2791           0 :                       &MediaDecoderStateMachine::PreservesPitchChanged);
    2792           0 :   mWatchManager.Watch(mExplicitDuration,
    2793           0 :                       &MediaDecoderStateMachine::RecomputeDuration);
    2794           0 :   mWatchManager.Watch(mObservedDuration,
    2795           0 :                       &MediaDecoderStateMachine::RecomputeDuration);
    2796           0 :   mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
    2797             : 
    2798           0 :   MOZ_ASSERT(!mStateObj);
    2799           0 :   auto* s = new DecodeMetadataState(this);
    2800           0 :   mStateObj.reset(s);
    2801           0 :   s->Enter();
    2802           0 : }
    2803             : 
    2804             : void
    2805           0 : MediaDecoderStateMachine::AudioAudibleChanged(bool aAudible)
    2806             : {
    2807           0 :   mIsAudioDataAudible = aAudible;
    2808           0 : }
    2809             : 
    2810             : media::MediaSink*
    2811           0 : MediaDecoderStateMachine::CreateAudioSink()
    2812             : {
    2813           0 :   RefPtr<MediaDecoderStateMachine> self = this;
    2814           0 :   auto audioSinkCreator = [self] () {
    2815           0 :     MOZ_ASSERT(self->OnTaskQueue());
    2816             :     AudioSink* audioSink = new AudioSink(
    2817           0 :       self->mTaskQueue, self->mAudioQueue,
    2818           0 :       self->GetMediaTime(),
    2819           0 :       self->Info().mAudio, self->mAudioChannel);
    2820             : 
    2821           0 :     self->mAudibleListener = audioSink->AudibleEvent().Connect(
    2822           0 :       self->mTaskQueue, self.get(),
    2823           0 :       &MediaDecoderStateMachine::AudioAudibleChanged);
    2824           0 :     return audioSink;
    2825           0 :   };
    2826           0 :   return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
    2827             : }
    2828             : 
    2829             : already_AddRefed<media::MediaSink>
    2830           0 : MediaDecoderStateMachine::CreateMediaSink(bool aAudioCaptured)
    2831             : {
    2832             :   RefPtr<media::MediaSink> audioSink =
    2833             :     aAudioCaptured
    2834             :     ? new DecodedStream(mTaskQueue, mAbstractMainThread, mAudioQueue,
    2835             :                         mVideoQueue, mOutputStreamManager,
    2836           0 :                         mSameOriginMedia.Ref(), mMediaPrincipalHandle.Ref())
    2837           0 :     : CreateAudioSink();
    2838             : 
    2839             :   RefPtr<media::MediaSink> mediaSink =
    2840             :     new VideoSink(mTaskQueue, audioSink, mVideoQueue,
    2841           0 :                   mVideoFrameContainer, *mFrameStats,
    2842           0 :                   sVideoQueueSendToCompositorSize);
    2843           0 :   return mediaSink.forget();
    2844             : }
    2845             : 
    2846             : TimeUnit
    2847           0 : MediaDecoderStateMachine::GetDecodedAudioDuration()
    2848             : {
    2849           0 :   MOZ_ASSERT(OnTaskQueue());
    2850           0 :   if (mMediaSink->IsStarted()) {
    2851             :     // mDecodedAudioEndTime might be smaller than GetClock() when there is
    2852             :     // overlap between 2 adjacent audio samples or when we are playing
    2853             :     // a chained ogg file.
    2854           0 :     return std::max(mDecodedAudioEndTime - GetClock(), TimeUnit::Zero());
    2855             :   }
    2856             :   // MediaSink not started. All audio samples are in the queue.
    2857           0 :   return TimeUnit::FromMicroseconds(AudioQueue().Duration());
    2858             : }
    2859             : 
    2860             : bool
    2861           0 : MediaDecoderStateMachine::HaveEnoughDecodedAudio()
    2862             : {
    2863           0 :   MOZ_ASSERT(OnTaskQueue());
    2864           0 :   auto ampleAudio = mAmpleAudioThreshold.MultDouble(mPlaybackRate);
    2865           0 :   return AudioQueue().GetSize() > 0
    2866           0 :          && GetDecodedAudioDuration() >= ampleAudio;
    2867             : }
    2868             : 
    2869           0 : bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
    2870             : {
    2871           0 :   MOZ_ASSERT(OnTaskQueue());
    2872           0 :   return VideoQueue().GetSize() >= GetAmpleVideoFrames() * mPlaybackRate + 1;
    2873             : }
    2874             : 
    2875             : void
    2876           0 : MediaDecoderStateMachine::PushAudio(AudioData* aSample)
    2877             : {
    2878           0 :   MOZ_ASSERT(OnTaskQueue());
    2879           0 :   MOZ_ASSERT(aSample);
    2880           0 :   AudioQueue().Push(aSample);
    2881           0 : }
    2882             : 
    2883             : void
    2884           0 : MediaDecoderStateMachine::PushVideo(VideoData* aSample)
    2885             : {
    2886           0 :   MOZ_ASSERT(OnTaskQueue());
    2887           0 :   MOZ_ASSERT(aSample);
    2888           0 :   aSample->mFrameID = ++mCurrentFrameID;
    2889           0 :   VideoQueue().Push(aSample);
    2890           0 : }
    2891             : 
    2892             : void
    2893           0 : MediaDecoderStateMachine::OnAudioPopped(const RefPtr<AudioData>& aSample)
    2894             : {
    2895           0 :   MOZ_ASSERT(OnTaskQueue());
    2896           0 :   mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
    2897           0 : }
    2898             : 
    2899             : void
    2900           0 : MediaDecoderStateMachine::OnVideoPopped(const RefPtr<VideoData>& aSample)
    2901             : {
    2902           0 :   MOZ_ASSERT(OnTaskQueue());
    2903           0 :   mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
    2904           0 : }
    2905             : 
    2906             : bool
    2907           0 : MediaDecoderStateMachine::IsAudioDecoding()
    2908             : {
    2909           0 :   MOZ_ASSERT(OnTaskQueue());
    2910           0 :   return HasAudio() && !AudioQueue().IsFinished();
    2911             : }
    2912             : 
    2913             : bool
    2914           0 : MediaDecoderStateMachine::IsVideoDecoding()
    2915             : {
    2916           0 :   MOZ_ASSERT(OnTaskQueue());
    2917           0 :   return HasVideo() && !VideoQueue().IsFinished();
    2918             : }
    2919             : 
    2920           0 : bool MediaDecoderStateMachine::IsPlaying() const
    2921             : {
    2922           0 :   MOZ_ASSERT(OnTaskQueue());
    2923           0 :   return mMediaSink->IsPlaying();
    2924             : }
    2925             : 
    2926           0 : void MediaDecoderStateMachine::SetMediaNotSeekable()
    2927             : {
    2928           0 :   mMediaSeekable = false;
    2929           0 : }
    2930             : 
    2931           0 : nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
    2932             : {
    2933           0 :   MOZ_ASSERT(NS_IsMainThread());
    2934             : 
    2935             :   // Dispatch initialization that needs to happen on that task queue.
    2936           0 :   nsCOMPtr<nsIRunnable> r = NewRunnableMethod<RefPtr<MediaDecoder>>(
    2937             :     "MediaDecoderStateMachine::InitializationTask",
    2938             :     this,
    2939             :     &MediaDecoderStateMachine::InitializationTask,
    2940           0 :     aDecoder);
    2941           0 :   mTaskQueue->DispatchStateChange(r.forget());
    2942             : 
    2943           0 :   mAudioQueueListener = AudioQueue().PopEvent().Connect(
    2944           0 :     mTaskQueue, this, &MediaDecoderStateMachine::OnAudioPopped);
    2945           0 :   mVideoQueueListener = VideoQueue().PopEvent().Connect(
    2946           0 :     mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped);
    2947             : 
    2948           0 :   mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
    2949             : 
    2950           0 :   mOnMediaNotSeekable = mReader->OnMediaNotSeekable().Connect(
    2951           0 :     OwnerThread(), this, &MediaDecoderStateMachine::SetMediaNotSeekable);
    2952             : 
    2953           0 :   mMediaSink = CreateMediaSink(mAudioCaptured);
    2954             : 
    2955           0 :   aDecoder->RequestCDMProxy()->Then(
    2956           0 :     OwnerThread(), __func__, this,
    2957             :     &MediaDecoderStateMachine::OnCDMProxyReady,
    2958             :     &MediaDecoderStateMachine::OnCDMProxyNotReady)
    2959           0 :   ->Track(mCDMProxyPromise);
    2960             : 
    2961           0 :   nsresult rv = mReader->Init();
    2962           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2963             : 
    2964           0 :   mReader->SetCanonicalDuration(&mDuration);
    2965             : 
    2966           0 :   return NS_OK;
    2967             : }
    2968             : 
    2969             : void
    2970           0 : MediaDecoderStateMachine::StopPlayback()
    2971             : {
    2972           0 :   MOZ_ASSERT(OnTaskQueue());
    2973           0 :   LOG("StopPlayback()");
    2974             : 
    2975           0 :   mOnPlaybackEvent.Notify(MediaEventType::PlaybackStopped);
    2976             : 
    2977           0 :   if (IsPlaying()) {
    2978           0 :     mMediaSink->SetPlaying(false);
    2979           0 :     MOZ_ASSERT(!IsPlaying());
    2980             : #ifdef XP_WIN
    2981             :     if (mHiResTimersRequested) {
    2982             :       mHiResTimersRequested = false;
    2983             :       timeEndPeriod(1);
    2984             :     }
    2985             : #endif
    2986             :   }
    2987           0 : }
    2988             : 
    2989           0 : void MediaDecoderStateMachine::MaybeStartPlayback()
    2990             : {
    2991           0 :   MOZ_ASSERT(OnTaskQueue());
    2992             :   // Should try to start playback only after decoding first frames.
    2993           0 :   MOZ_ASSERT(mSentFirstFrameLoadedEvent);
    2994             : 
    2995           0 :   if (IsPlaying()) {
    2996             :     // Logging this case is really spammy - don't do it.
    2997           0 :     return;
    2998             :   }
    2999             : 
    3000           0 :   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
    3001           0 :     LOG("Not starting playback [mPlayState=%d]", mPlayState.Ref());
    3002           0 :     return;
    3003             :   }
    3004             : 
    3005           0 :   LOG("MaybeStartPlayback() starting playback");
    3006           0 :   mOnPlaybackEvent.Notify(MediaEventType::PlaybackStarted);
    3007           0 :   StartMediaSink();
    3008             : 
    3009             : #ifdef XP_WIN
    3010             :   if (!mHiResTimersRequested && mShouldUseHiResTimers) {
    3011             :     mHiResTimersRequested = true;
    3012             :     // Ensure high precision timers are enabled on Windows, otherwise the state
    3013             :     // machine isn't woken up at reliable intervals to set the next frame, and we
    3014             :     // drop frames while painting. Note that each call must be matched by a
    3015             :     // corresponding timeEndPeriod() call. Enabling high precision timers causes
    3016             :     // the CPU to wake up more frequently on Windows 7 and earlier, which causes
    3017             :     // more CPU load and battery use. So we only enable high precision timers
    3018             :     // when we're actually playing.
    3019             :     timeBeginPeriod(1);
    3020             :   }
    3021             : #endif
    3022             : 
    3023           0 :   if (!IsPlaying()) {
    3024           0 :     mMediaSink->SetPlaying(true);
    3025           0 :     MOZ_ASSERT(IsPlaying());
    3026             :   }
    3027             : }
    3028             : 
    3029             : void
    3030           0 : MediaDecoderStateMachine::UpdatePlaybackPositionInternal(const TimeUnit& aTime)
    3031             : {
    3032           0 :   MOZ_ASSERT(OnTaskQueue());
    3033           0 :   LOGV("UpdatePlaybackPositionInternal(%" PRId64 ")", aTime.ToMicroseconds());
    3034             : 
    3035           0 :   mCurrentPosition = aTime;
    3036           0 :   NS_ASSERTION(mCurrentPosition.Ref() >= TimeUnit::Zero(),
    3037             :                "CurrentTime should be positive!");
    3038           0 :   mObservedDuration = std::max(mObservedDuration.Ref(), mCurrentPosition.Ref());
    3039           0 : }
    3040             : 
    3041             : void
    3042           0 : MediaDecoderStateMachine::UpdatePlaybackPosition(const TimeUnit& aTime)
    3043             : {
    3044           0 :   MOZ_ASSERT(OnTaskQueue());
    3045           0 :   UpdatePlaybackPositionInternal(aTime);
    3046             : 
    3047           0 :   bool fragmentEnded = mFragmentEndTime.IsValid()
    3048           0 :     && GetMediaTime() >= mFragmentEndTime;
    3049           0 :   mMetadataManager.DispatchMetadataIfNeeded(aTime);
    3050             : 
    3051           0 :   if (fragmentEnded) {
    3052           0 :     StopPlayback();
    3053             :   }
    3054           0 : }
    3055             : 
    3056             : /* static */ const char*
    3057           0 : MediaDecoderStateMachine::ToStateStr(State aState)
    3058             : {
    3059           0 :   switch (aState) {
    3060           0 :     case DECODER_STATE_DECODING_METADATA:   return "DECODING_METADATA";
    3061           0 :     case DECODER_STATE_WAIT_FOR_CDM:        return "WAIT_FOR_CDM";
    3062           0 :     case DECODER_STATE_DORMANT:             return "DORMANT";
    3063           0 :     case DECODER_STATE_DECODING_FIRSTFRAME: return "DECODING_FIRSTFRAME";
    3064           0 :     case DECODER_STATE_DECODING:            return "DECODING";
    3065           0 :     case DECODER_STATE_SEEKING:             return "SEEKING";
    3066           0 :     case DECODER_STATE_BUFFERING:           return "BUFFERING";
    3067           0 :     case DECODER_STATE_COMPLETED:           return "COMPLETED";
    3068           0 :     case DECODER_STATE_SHUTDOWN:            return "SHUTDOWN";
    3069           0 :     default: MOZ_ASSERT_UNREACHABLE("Invalid state.");
    3070             :   }
    3071             :   return "UNKNOWN";
    3072             : }
    3073             : 
    3074             : const char*
    3075           0 : MediaDecoderStateMachine::ToStateStr()
    3076             : {
    3077           0 :   MOZ_ASSERT(OnTaskQueue());
    3078           0 :   return ToStateStr(mStateObj->GetState());
    3079             : }
    3080             : 
    3081           0 : void MediaDecoderStateMachine::VolumeChanged()
    3082             : {
    3083           0 :   MOZ_ASSERT(OnTaskQueue());
    3084           0 :   mMediaSink->SetVolume(mVolume);
    3085           0 : }
    3086             : 
    3087           0 : void MediaDecoderStateMachine::RecomputeDuration()
    3088             : {
    3089           0 :   MOZ_ASSERT(OnTaskQueue());
    3090             : 
    3091           0 :   TimeUnit duration;
    3092           0 :   if (mExplicitDuration.Ref().isSome()) {
    3093           0 :     double d = mExplicitDuration.Ref().ref();
    3094           0 :     if (IsNaN(d)) {
    3095             :       // We have an explicit duration (which means that we shouldn't look at
    3096             :       // any other duration sources), but the duration isn't ready yet.
    3097           0 :       return;
    3098             :     }
    3099             :     // We don't fire duration changed for this case because it should have
    3100             :     // already been fired on the main thread when the explicit duration was set.
    3101           0 :     duration = TimeUnit::FromSeconds(d);
    3102           0 :   } else if (mInfo.isSome() && Info().mMetadataDuration.isSome()) {
    3103             :     // We need to check mInfo.isSome() because that this method might be invoked
    3104             :     // while mObservedDuration is changed which might before the metadata been
    3105             :     // read.
    3106           0 :     duration = Info().mMetadataDuration.ref();
    3107             :   } else {
    3108           0 :     return;
    3109             :   }
    3110             : 
    3111             :   // Only adjust the duration when an explicit duration isn't set (MSE).
    3112             :   // The duration is always exactly known with MSE and there's no need to adjust
    3113             :   // it based on what may have been seen in the past; in particular as this data
    3114             :   // may no longer exist such as when the mediasource duration was reduced.
    3115           0 :   if (mExplicitDuration.Ref().isNothing()
    3116           0 :       && duration < mObservedDuration.Ref()) {
    3117           0 :     duration = mObservedDuration;
    3118             :   }
    3119             : 
    3120           0 :   MOZ_ASSERT(duration >= TimeUnit::Zero());
    3121           0 :   mDuration = Some(duration);
    3122             : }
    3123             : 
    3124             : RefPtr<ShutdownPromise>
    3125           0 : MediaDecoderStateMachine::Shutdown()
    3126             : {
    3127           0 :   MOZ_ASSERT(OnTaskQueue());
    3128           0 :   return mStateObj->HandleShutdown();
    3129             : }
    3130             : 
    3131           0 : void MediaDecoderStateMachine::PlayStateChanged()
    3132             : {
    3133           0 :   MOZ_ASSERT(OnTaskQueue());
    3134             : 
    3135           0 :   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
    3136           0 :     CancelSuspendTimer();
    3137           0 :   } else if (mMinimizePreroll) {
    3138             :     // Once we start playing, we don't want to minimize our prerolling, as we
    3139             :     // assume the user is likely to want to keep playing in future. This needs
    3140             :     // to happen before we invoke StartDecoding().
    3141           0 :     mMinimizePreroll = false;
    3142             :   }
    3143             : 
    3144           0 :   mStateObj->HandlePlayStateChanged(mPlayState);
    3145           0 : }
    3146             : 
    3147           0 : void MediaDecoderStateMachine::SetVideoDecodeMode(VideoDecodeMode aMode)
    3148             : {
    3149           0 :   nsCOMPtr<nsIRunnable> r = NewRunnableMethod<VideoDecodeMode>(
    3150             :     "MediaDecoderStateMachine::SetVideoDecodeModeInternal",
    3151             :     this,
    3152             :     &MediaDecoderStateMachine::SetVideoDecodeModeInternal,
    3153           0 :     aMode);
    3154           0 :   OwnerThread()->DispatchStateChange(r.forget());
    3155           0 : }
    3156             : 
    3157           0 : void MediaDecoderStateMachine::SetVideoDecodeModeInternal(VideoDecodeMode aMode)
    3158             : {
    3159           0 :   MOZ_ASSERT(OnTaskQueue());
    3160           0 :   LOG("VideoDecodeModeChanged: VideoDecodeMode=(%s->%s), mVideoDecodeSuspended=%c",
    3161             :       mVideoDecodeMode == VideoDecodeMode::Normal ? "Normal" : "Suspend",
    3162             :       aMode == VideoDecodeMode::Normal ? "Normal" : "Suspend",
    3163             :       mVideoDecodeSuspended ? 'T' : 'F');
    3164             : 
    3165           0 :   if (!MediaPrefs::MDSMSuspendBackgroundVideoEnabled()) {
    3166           0 :     return;
    3167             :   }
    3168             : 
    3169           0 :   if (aMode == mVideoDecodeMode) {
    3170           0 :     return;
    3171             :   }
    3172             : 
    3173             :   // Set new video decode mode.
    3174           0 :   mVideoDecodeMode = aMode;
    3175             : 
    3176             :   // Start timer to trigger suspended video decoding.
    3177           0 :   if (mVideoDecodeMode == VideoDecodeMode::Suspend) {
    3178           0 :     TimeStamp target = TimeStamp::Now() + SuspendBackgroundVideoDelay();
    3179             : 
    3180           0 :     RefPtr<MediaDecoderStateMachine> self = this;
    3181           0 :     mVideoDecodeSuspendTimer.Ensure(target,
    3182           0 :                                     [=]() { self->OnSuspendTimerResolved(); },
    3183           0 :                                     [] () { MOZ_DIAGNOSTIC_ASSERT(false); });
    3184           0 :     mOnPlaybackEvent.Notify(MediaEventType::StartVideoSuspendTimer);
    3185           0 :     return;
    3186             :   }
    3187             : 
    3188             :   // Resuming from suspended decoding
    3189             : 
    3190             :   // If suspend timer exists, destroy it.
    3191           0 :   CancelSuspendTimer();
    3192             : 
    3193           0 :   if (mVideoDecodeSuspended) {
    3194           0 :     const auto target = mMediaSink->IsStarted() ? GetClock() : GetMediaTime();
    3195           0 :     mStateObj->HandleResumeVideoDecoding(target + detail::RESUME_VIDEO_PREMIUM);
    3196             :   }
    3197             : }
    3198             : 
    3199           0 : void MediaDecoderStateMachine::BufferedRangeUpdated()
    3200             : {
    3201           0 :   MOZ_ASSERT(OnTaskQueue());
    3202             : 
    3203             :   // While playing an unseekable stream of unknown duration, mObservedDuration
    3204             :   // is updated (in AdvanceFrame()) as we play. But if data is being downloaded
    3205             :   // faster than played, mObserved won't reflect the end of playable data
    3206             :   // since we haven't played the frame at the end of buffered data. So update
    3207             :   // mObservedDuration here as new data is downloaded to prevent such a lag.
    3208           0 :   if (!mBuffered.Ref().IsInvalid()) {
    3209             :     bool exists;
    3210           0 :     media::TimeUnit end{mBuffered.Ref().GetEnd(&exists)};
    3211           0 :     if (exists) {
    3212           0 :       mObservedDuration = std::max(mObservedDuration.Ref(), end);
    3213             :     }
    3214             :   }
    3215           0 : }
    3216             : 
    3217             : RefPtr<MediaDecoder::SeekPromise>
    3218           0 : MediaDecoderStateMachine::Seek(const SeekTarget& aTarget)
    3219             : {
    3220           0 :   MOZ_ASSERT(OnTaskQueue());
    3221             : 
    3222             :   // We need to be able to seek in some way
    3223           0 :   if (!mMediaSeekable && !mMediaSeekableOnlyInBufferedRanges) {
    3224           0 :     LOGW("Seek() should not be called on a non-seekable media");
    3225             :     return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true,
    3226           0 :                                                       __func__);
    3227             :   }
    3228             : 
    3229           0 :   if (aTarget.IsNextFrame() && !HasVideo()) {
    3230           0 :     LOGW("Ignore a NextFrameSeekTask on a media file without video track.");
    3231             :     return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true,
    3232           0 :                                                       __func__);
    3233             :   }
    3234             : 
    3235           0 :   MOZ_ASSERT(mDuration.Ref().isSome(), "We should have got duration already");
    3236             : 
    3237           0 :   return mStateObj->HandleSeek(aTarget);
    3238             : }
    3239             : 
    3240             : RefPtr<MediaDecoder::SeekPromise>
    3241           0 : MediaDecoderStateMachine::InvokeSeek(const SeekTarget& aTarget)
    3242             : {
    3243             :   return InvokeAsync(
    3244           0 :            OwnerThread(), this, __func__,
    3245           0 :            &MediaDecoderStateMachine::Seek, aTarget);
    3246             : }
    3247             : 
    3248           0 : void MediaDecoderStateMachine::StopMediaSink()
    3249             : {
    3250           0 :   MOZ_ASSERT(OnTaskQueue());
    3251           0 :   if (mMediaSink->IsStarted()) {
    3252           0 :     LOG("Stop MediaSink");
    3253           0 :     mAudibleListener.DisconnectIfExists();
    3254             : 
    3255           0 :     mMediaSink->Stop();
    3256           0 :     mMediaSinkAudioPromise.DisconnectIfExists();
    3257           0 :     mMediaSinkVideoPromise.DisconnectIfExists();
    3258             :   }
    3259           0 : }
    3260             : 
    3261             : void
    3262           0 : MediaDecoderStateMachine::RequestAudioData()
    3263             : {
    3264           0 :   MOZ_ASSERT(OnTaskQueue());
    3265           0 :   MOZ_ASSERT(IsAudioDecoding());
    3266           0 :   MOZ_ASSERT(!IsRequestingAudioData());
    3267           0 :   MOZ_ASSERT(!IsWaitingAudioData());
    3268           0 :   LOGV("Queueing audio task - queued=%" PRIuSIZE ", decoder-queued=%" PRIuSIZE,
    3269             :        AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
    3270             : 
    3271           0 :   RefPtr<MediaDecoderStateMachine> self = this;
    3272           0 :   mReader->RequestAudioData()->Then(
    3273           0 :     OwnerThread(), __func__,
    3274           0 :     [this, self] (RefPtr<AudioData> aAudio) {
    3275           0 :       MOZ_ASSERT(aAudio);
    3276           0 :       mAudioDataRequest.Complete();
    3277             :       // audio->GetEndTime() is not always mono-increasing in chained ogg.
    3278           0 :       mDecodedAudioEndTime = std::max(
    3279           0 :         aAudio->GetEndTime(), mDecodedAudioEndTime);
    3280           0 :       LOGV("OnAudioDecoded [%" PRId64 ",%" PRId64 "]",
    3281             :            aAudio->mTime.ToMicroseconds(),
    3282             :            aAudio->GetEndTime().ToMicroseconds());
    3283           0 :       mStateObj->HandleAudioDecoded(aAudio);
    3284           0 :     },
    3285           0 :     [this, self] (const MediaResult& aError) {
    3286           0 :       LOGV("OnAudioNotDecoded aError=%" PRIu32, static_cast<uint32_t>(aError.Code()));
    3287           0 :       mAudioDataRequest.Complete();
    3288           0 :       switch (aError.Code()) {
    3289             :         case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
    3290           0 :           mStateObj->HandleWaitingForAudio();
    3291           0 :           break;
    3292             :         case NS_ERROR_DOM_MEDIA_CANCELED:
    3293           0 :           mStateObj->HandleAudioCanceled();
    3294           0 :           break;
    3295             :         case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
    3296           0 :           mStateObj->HandleEndOfAudio();
    3297           0 :           break;
    3298             :         default:
    3299           0 :           DecodeError(aError);
    3300             :       }
    3301           0 :     })->Track(mAudioDataRequest);
    3302           0 : }
    3303             : 
    3304             : void
    3305           0 : MediaDecoderStateMachine::RequestVideoData(const media::TimeUnit& aCurrentTime)
    3306             : {
    3307           0 :   MOZ_ASSERT(OnTaskQueue());
    3308           0 :   MOZ_ASSERT(IsVideoDecoding());
    3309           0 :   MOZ_ASSERT(!IsRequestingVideoData());
    3310           0 :   MOZ_ASSERT(!IsWaitingVideoData());
    3311           0 :   LOGV("Queueing video task - queued=%" PRIuSIZE ", decoder-queued=%" PRIoSIZE
    3312             :        ", stime=%" PRId64,
    3313             :        VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(),
    3314             :        aCurrentTime.ToMicroseconds());
    3315             : 
    3316           0 :   TimeStamp videoDecodeStartTime = TimeStamp::Now();
    3317           0 :   RefPtr<MediaDecoderStateMachine> self = this;
    3318           0 :   mReader->RequestVideoData(aCurrentTime)->Then(
    3319           0 :     OwnerThread(), __func__,
    3320           0 :     [this, self, videoDecodeStartTime] (RefPtr<VideoData> aVideo) {
    3321           0 :       MOZ_ASSERT(aVideo);
    3322           0 :       mVideoDataRequest.Complete();
    3323             :       // Handle abnormal or negative timestamps.
    3324           0 :       mDecodedVideoEndTime = std::max(
    3325           0 :         mDecodedVideoEndTime, aVideo->GetEndTime());
    3326           0 :       LOGV("OnVideoDecoded [%" PRId64 ",%" PRId64 "]",
    3327             :            aVideo->mTime.ToMicroseconds(),
    3328             :            aVideo->GetEndTime().ToMicroseconds());
    3329           0 :       mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
    3330           0 :     },
    3331           0 :     [this, self] (const MediaResult& aError) {
    3332           0 :       LOGV("OnVideoNotDecoded aError=%" PRIu32 , static_cast<uint32_t>(aError.Code()));
    3333           0 :       mVideoDataRequest.Complete();
    3334           0 :       switch (aError.Code()) {
    3335             :         case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
    3336           0 :           mStateObj->HandleWaitingForVideo();
    3337           0 :           break;
    3338             :         case NS_ERROR_DOM_MEDIA_CANCELED:
    3339           0 :           mStateObj->HandleVideoCanceled();
    3340           0 :           break;
    3341             :         case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
    3342           0 :           mStateObj->HandleEndOfVideo();
    3343           0 :           break;
    3344             :         default:
    3345           0 :           DecodeError(aError);
    3346             :       }
    3347           0 :     })->Track(mVideoDataRequest);
    3348           0 : }
    3349             : 
    3350             : void
    3351           0 : MediaDecoderStateMachine::WaitForData(MediaData::Type aType)
    3352             : {
    3353           0 :   MOZ_ASSERT(OnTaskQueue());
    3354           0 :   MOZ_ASSERT(aType == MediaData::AUDIO_DATA || aType == MediaData::VIDEO_DATA);
    3355           0 :   RefPtr<MediaDecoderStateMachine> self = this;
    3356           0 :   if (aType == MediaData::AUDIO_DATA) {
    3357           0 :     mReader->WaitForData(MediaData::AUDIO_DATA)->Then(
    3358           0 :       OwnerThread(), __func__,
    3359           0 :       [self] (MediaData::Type aType) {
    3360           0 :         self->mAudioWaitRequest.Complete();
    3361           0 :         MOZ_ASSERT(aType == MediaData::AUDIO_DATA);
    3362           0 :         self->mStateObj->HandleAudioWaited(aType);
    3363           0 :       },
    3364           0 :       [self] (const WaitForDataRejectValue& aRejection) {
    3365           0 :         self->mAudioWaitRequest.Complete();
    3366           0 :         self->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
    3367           0 :       })->Track(mAudioWaitRequest);
    3368             :   } else {
    3369           0 :     mReader->WaitForData(MediaData::VIDEO_DATA)->Then(
    3370           0 :       OwnerThread(), __func__,
    3371           0 :       [self] (MediaData::Type aType) {
    3372           0 :         self->mVideoWaitRequest.Complete();
    3373           0 :         MOZ_ASSERT(aType == MediaData::VIDEO_DATA);
    3374           0 :         self->mStateObj->HandleVideoWaited(aType);
    3375           0 :       },
    3376           0 :       [self] (const WaitForDataRejectValue& aRejection) {
    3377           0 :         self->mVideoWaitRequest.Complete();
    3378           0 :         self->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
    3379           0 :       })->Track(mVideoWaitRequest);
    3380             :   }
    3381           0 : }
    3382             : 
    3383             : void
    3384           0 : MediaDecoderStateMachine::StartMediaSink()
    3385             : {
    3386           0 :   MOZ_ASSERT(OnTaskQueue());
    3387           0 :   if (!mMediaSink->IsStarted()) {
    3388           0 :     mAudioCompleted = false;
    3389           0 :     mMediaSink->Start(GetMediaTime(), Info());
    3390             : 
    3391           0 :     auto videoPromise = mMediaSink->OnEnded(TrackInfo::kVideoTrack);
    3392           0 :     auto audioPromise = mMediaSink->OnEnded(TrackInfo::kAudioTrack);
    3393             : 
    3394           0 :     if (audioPromise) {
    3395           0 :       audioPromise->Then(
    3396           0 :         OwnerThread(), __func__, this,
    3397             :         &MediaDecoderStateMachine::OnMediaSinkAudioComplete,
    3398             :         &MediaDecoderStateMachine::OnMediaSinkAudioError)
    3399           0 :       ->Track(mMediaSinkAudioPromise);
    3400             :     }
    3401           0 :     if (videoPromise) {
    3402           0 :       videoPromise->Then(
    3403           0 :         OwnerThread(), __func__, this,
    3404             :         &MediaDecoderStateMachine::OnMediaSinkVideoComplete,
    3405             :         &MediaDecoderStateMachine::OnMediaSinkVideoError)
    3406           0 :       ->Track(mMediaSinkVideoPromise);
    3407             :     }
    3408             :   }
    3409           0 : }
    3410             : 
    3411             : bool
    3412           0 : MediaDecoderStateMachine::HasLowDecodedAudio()
    3413             : {
    3414           0 :   MOZ_ASSERT(OnTaskQueue());
    3415           0 :   return IsAudioDecoding()
    3416           0 :          && GetDecodedAudioDuration()
    3417           0 :             < EXHAUSTED_DATA_MARGIN.MultDouble(mPlaybackRate);
    3418             : }
    3419             : 
    3420             : bool
    3421           0 : MediaDecoderStateMachine::HasLowDecodedVideo()
    3422             : {
    3423           0 :   MOZ_ASSERT(OnTaskQueue());
    3424           0 :   return IsVideoDecoding()
    3425           0 :          && VideoQueue().GetSize() < LOW_VIDEO_FRAMES * mPlaybackRate;
    3426             : }
    3427             : 
    3428             : bool
    3429           0 : MediaDecoderStateMachine::HasLowDecodedData()
    3430             : {
    3431           0 :   MOZ_ASSERT(OnTaskQueue());
    3432           0 :   MOZ_ASSERT(mReader->UseBufferingHeuristics());
    3433           0 :   return HasLowDecodedAudio() || HasLowDecodedVideo();
    3434             : }
    3435             : 
    3436           0 : bool MediaDecoderStateMachine::OutOfDecodedAudio()
    3437             : {
    3438           0 :     MOZ_ASSERT(OnTaskQueue());
    3439           0 :     return IsAudioDecoding() && !AudioQueue().IsFinished()
    3440           0 :            && AudioQueue().GetSize() == 0
    3441           0 :            && !mMediaSink->HasUnplayedFrames(TrackInfo::kAudioTrack);
    3442             : }
    3443             : 
    3444             : bool
    3445           0 : MediaDecoderStateMachine::HasLowBufferedData()
    3446             : {
    3447           0 :   MOZ_ASSERT(OnTaskQueue());
    3448           0 :   return HasLowBufferedData(detail::LOW_BUFFER_THRESHOLD);
    3449             : }
    3450             : 
    3451             : bool
    3452           0 : MediaDecoderStateMachine::HasLowBufferedData(const TimeUnit& aThreshold)
    3453             : {
    3454           0 :   MOZ_ASSERT(OnTaskQueue());
    3455             : 
    3456             :   // If we don't have a duration, mBuffered is probably not going to have
    3457             :   // a useful buffered range. Return false here so that we don't get stuck in
    3458             :   // buffering mode for live streams.
    3459           0 :   if (Duration().IsInfinite()) {
    3460           0 :     return false;
    3461             :   }
    3462             : 
    3463           0 :   if (mBuffered.Ref().IsInvalid()) {
    3464           0 :     return false;
    3465             :   }
    3466             : 
    3467             :   // We are never low in decoded data when we don't have audio/video or have
    3468             :   // decoded all audio/video samples.
    3469           0 :   TimeUnit endOfDecodedVideo = (HasVideo() && !VideoQueue().IsFinished())
    3470           0 :     ? mDecodedVideoEndTime : TimeUnit::FromInfinity();
    3471           0 :   TimeUnit endOfDecodedAudio = (HasAudio() && !AudioQueue().IsFinished())
    3472           0 :     ? mDecodedAudioEndTime : TimeUnit::FromInfinity();
    3473             : 
    3474           0 :   auto endOfDecodedData = std::min(endOfDecodedVideo, endOfDecodedAudio);
    3475           0 :   if (Duration() < endOfDecodedData) {
    3476             :     // Our duration is not up to date. No point buffering.
    3477           0 :     return false;
    3478             :   }
    3479             : 
    3480           0 :   if (endOfDecodedData.IsInfinite()) {
    3481             :     // Have decoded all samples. No point buffering.
    3482           0 :     return false;
    3483             :   }
    3484             : 
    3485           0 :   auto start = endOfDecodedData;
    3486           0 :   auto end = std::min(GetMediaTime() + aThreshold, Duration());
    3487           0 :   if (start >= end) {
    3488             :     // Duration of decoded samples is greater than our threshold.
    3489           0 :     return false;
    3490             :   }
    3491           0 :   media::TimeInterval interval(start, end);
    3492           0 :   return !mBuffered.Ref().Contains(interval);
    3493             : }
    3494             : 
    3495             : void
    3496           0 : MediaDecoderStateMachine::DecodeError(const MediaResult& aError)
    3497             : {
    3498           0 :   MOZ_ASSERT(OnTaskQueue());
    3499           0 :   LOGW("Decode error");
    3500             :   // Notify the decode error and MediaDecoder will shut down MDSM.
    3501           0 :   mOnPlaybackErrorEvent.Notify(aError);
    3502           0 : }
    3503             : 
    3504             : void
    3505           0 : MediaDecoderStateMachine::EnqueueFirstFrameLoadedEvent()
    3506             : {
    3507           0 :   MOZ_ASSERT(OnTaskQueue());
    3508             :   // Track value of mSentFirstFrameLoadedEvent from before updating it
    3509           0 :   bool firstFrameBeenLoaded = mSentFirstFrameLoadedEvent;
    3510           0 :   mSentFirstFrameLoadedEvent = true;
    3511             :   MediaDecoderEventVisibility visibility =
    3512           0 :     firstFrameBeenLoaded ? MediaDecoderEventVisibility::Suppressed
    3513           0 :                          : MediaDecoderEventVisibility::Observable;
    3514           0 :   mFirstFrameLoadedEvent.Notify(
    3515           0 :     nsAutoPtr<MediaInfo>(new MediaInfo(Info())), visibility);
    3516           0 : }
    3517             : 
    3518             : void
    3519           0 : MediaDecoderStateMachine::FinishDecodeFirstFrame()
    3520             : {
    3521           0 :   MOZ_ASSERT(OnTaskQueue());
    3522           0 :   MOZ_ASSERT(!mSentFirstFrameLoadedEvent);
    3523           0 :   LOG("FinishDecodeFirstFrame");
    3524             : 
    3525           0 :   mMediaSink->Redraw(Info().mVideo);
    3526             : 
    3527           0 :   LOG("Media duration %" PRId64 ", "
    3528             :       "transportSeekable=%d, mediaSeekable=%d",
    3529             :       Duration().ToMicroseconds(), mResource->IsTransportSeekable(),
    3530             :       mMediaSeekable);
    3531             : 
    3532             :   // Get potentially updated metadata
    3533           0 :   mReader->ReadUpdatedMetadata(mInfo.ptr());
    3534             : 
    3535           0 :   EnqueueFirstFrameLoadedEvent();
    3536           0 : }
    3537             : 
    3538             : RefPtr<ShutdownPromise>
    3539           0 : MediaDecoderStateMachine::BeginShutdown()
    3540             : {
    3541           0 :   return InvokeAsync(OwnerThread(), this, __func__,
    3542           0 :                      &MediaDecoderStateMachine::Shutdown);
    3543             : }
    3544             : 
    3545             : RefPtr<ShutdownPromise>
    3546           0 : MediaDecoderStateMachine::FinishShutdown()
    3547             : {
    3548           0 :   MOZ_ASSERT(OnTaskQueue());
    3549           0 :   LOG("Shutting down state machine task queue");
    3550           0 :   return OwnerThread()->BeginShutdown();
    3551             : }
    3552             : 
    3553             : void
    3554           0 : MediaDecoderStateMachine::RunStateMachine()
    3555             : {
    3556           0 :   MOZ_ASSERT(OnTaskQueue());
    3557             : 
    3558           0 :   mDelayedScheduler.Reset(); // Must happen on state machine task queue.
    3559           0 :   mDispatchedStateMachine = false;
    3560           0 :   mStateObj->Step();
    3561           0 : }
    3562             : 
    3563             : void
    3564           0 : MediaDecoderStateMachine::ResetDecode(TrackSet aTracks)
    3565             : {
    3566           0 :   MOZ_ASSERT(OnTaskQueue());
    3567           0 :   LOG("MediaDecoderStateMachine::Reset");
    3568             : 
    3569             :   // Assert that aTracks specifies to reset the video track because we
    3570             :   // don't currently support resetting just the audio track.
    3571           0 :   MOZ_ASSERT(aTracks.contains(TrackInfo::kVideoTrack));
    3572             : 
    3573           0 :   if (aTracks.contains(TrackInfo::kVideoTrack)) {
    3574           0 :     mDecodedVideoEndTime = TimeUnit::Zero();
    3575           0 :     mVideoCompleted = false;
    3576           0 :     VideoQueue().Reset();
    3577           0 :     mVideoDataRequest.DisconnectIfExists();
    3578           0 :     mVideoWaitRequest.DisconnectIfExists();
    3579             :   }
    3580             : 
    3581           0 :   if (aTracks.contains(TrackInfo::kAudioTrack)) {
    3582           0 :     mDecodedAudioEndTime = TimeUnit::Zero();
    3583           0 :     mAudioCompleted = false;
    3584           0 :     AudioQueue().Reset();
    3585           0 :     mAudioDataRequest.DisconnectIfExists();
    3586           0 :     mAudioWaitRequest.DisconnectIfExists();
    3587             :   }
    3588             : 
    3589           0 :   mPlaybackOffset = 0;
    3590             : 
    3591           0 :   mReader->ResetDecode(aTracks);
    3592           0 : }
    3593             : 
    3594             : media::TimeUnit
    3595           0 : MediaDecoderStateMachine::GetClock(TimeStamp* aTimeStamp) const
    3596             : {
    3597           0 :   MOZ_ASSERT(OnTaskQueue());
    3598           0 :   auto clockTime = mMediaSink->GetPosition(aTimeStamp);
    3599           0 :   NS_ASSERTION(GetMediaTime() <= clockTime, "Clock should go forwards.");
    3600           0 :   return clockTime;
    3601             : }
    3602             : 
    3603             : void
    3604           0 : MediaDecoderStateMachine::UpdatePlaybackPositionPeriodically()
    3605             : {
    3606           0 :   MOZ_ASSERT(OnTaskQueue());
    3607             : 
    3608           0 :   if (!IsPlaying()) {
    3609           0 :     return;
    3610             :   }
    3611             : 
    3612             :   // Cap the current time to the larger of the audio and video end time.
    3613             :   // This ensures that if we're running off the system clock, we don't
    3614             :   // advance the clock to after the media end time.
    3615           0 :   if (VideoEndTime() > TimeUnit::Zero() || AudioEndTime() > TimeUnit::Zero()) {
    3616             : 
    3617           0 :     const auto clockTime = GetClock();
    3618             :     // Skip frames up to the frame at the playback position, and figure out
    3619             :     // the time remaining until it's time to display the next frame and drop
    3620             :     // the current frame.
    3621           0 :     NS_ASSERTION(clockTime >= TimeUnit::Zero(), "Should have positive clock time.");
    3622             : 
    3623             :     // These will be non -1 if we've displayed a video frame, or played an audio
    3624             :     // frame.
    3625           0 :     auto maxEndTime = std::max(VideoEndTime(), AudioEndTime());
    3626           0 :     auto t = std::min(clockTime, maxEndTime);
    3627             :     // FIXME: Bug 1091422 - chained ogg files hit this assertion.
    3628             :     //MOZ_ASSERT(t >= GetMediaTime());
    3629           0 :     if (t > GetMediaTime()) {
    3630           0 :       UpdatePlaybackPosition(t);
    3631             :     }
    3632             :   }
    3633             :   // Note we have to update playback position before releasing the monitor.
    3634             :   // Otherwise, MediaDecoder::AddOutputStream could kick in when we are outside
    3635             :   // the monitor and get a staled value from GetCurrentTimeUs() which hits the
    3636             :   // assertion in GetClock().
    3637             : 
    3638           0 :   int64_t delay = std::max<int64_t>(1, AUDIO_DURATION_USECS / mPlaybackRate);
    3639           0 :   ScheduleStateMachineIn(TimeUnit::FromMicroseconds(delay));
    3640             : }
    3641             : 
    3642             : /* static */ const char*
    3643           0 : MediaDecoderStateMachine::ToStr(NextFrameStatus aStatus)
    3644             : {
    3645           0 :   switch (aStatus) {
    3646             :     case MediaDecoderOwner::NEXT_FRAME_AVAILABLE:
    3647           0 :       return "NEXT_FRAME_AVAILABLE";
    3648             :     case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE:
    3649           0 :       return "NEXT_FRAME_UNAVAILABLE";
    3650             :     case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING:
    3651           0 :       return "NEXT_FRAME_UNAVAILABLE_BUFFERING";
    3652             :     case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING:
    3653           0 :       return "NEXT_FRAME_UNAVAILABLE_SEEKING";
    3654             :     case MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED:
    3655           0 :       return "NEXT_FRAME_UNINITIALIZED";
    3656             :   }
    3657           0 :   return "UNKNOWN";
    3658             : }
    3659             : 
    3660             : void
    3661           0 : MediaDecoderStateMachine::UpdateNextFrameStatus(NextFrameStatus aStatus)
    3662             : {
    3663           0 :   MOZ_ASSERT(OnTaskQueue());
    3664           0 :   if (aStatus != mNextFrameStatus) {
    3665           0 :     LOG("Changed mNextFrameStatus to %s", ToStr(aStatus));
    3666           0 :     mNextFrameStatus = aStatus;
    3667             :   }
    3668           0 : }
    3669             : 
    3670             : bool
    3671           0 : MediaDecoderStateMachine::CanPlayThrough()
    3672             : {
    3673           0 :   MOZ_ASSERT(OnTaskQueue());
    3674           0 :   return GetStatistics().CanPlayThrough();
    3675             : }
    3676             : 
    3677             : MediaStatistics
    3678           0 : MediaDecoderStateMachine::GetStatistics()
    3679             : {
    3680           0 :   MOZ_ASSERT(OnTaskQueue());
    3681             :   MediaStatistics result;
    3682           0 :   result.mDownloadRate =
    3683           0 :     mResource->GetDownloadRate(&result.mDownloadRateReliable);
    3684           0 :   result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
    3685           0 :   result.mTotalBytes = mResource->GetLength();
    3686           0 :   result.mPlaybackRate = mPlaybackBytesPerSecond;
    3687           0 :   result.mPlaybackRateReliable = mPlaybackRateReliable;
    3688           0 :   result.mDecoderPosition = mDecoderPosition;
    3689           0 :   result.mPlaybackPosition = mPlaybackOffset;
    3690           0 :   return result;
    3691             : }
    3692             : 
    3693             : void
    3694           0 : MediaDecoderStateMachine::ScheduleStateMachine()
    3695             : {
    3696           0 :   MOZ_ASSERT(OnTaskQueue());
    3697           0 :   if (mDispatchedStateMachine) {
    3698           0 :     return;
    3699             :   }
    3700           0 :   mDispatchedStateMachine = true;
    3701             : 
    3702           0 :   OwnerThread()->Dispatch(
    3703           0 :     NewRunnableMethod("MediaDecoderStateMachine::RunStateMachine",
    3704             :                       this,
    3705           0 :                       &MediaDecoderStateMachine::RunStateMachine));
    3706             : }
    3707             : 
    3708             : void
    3709           0 : MediaDecoderStateMachine::ScheduleStateMachineIn(const TimeUnit& aTime)
    3710             : {
    3711           0 :   MOZ_ASSERT(OnTaskQueue()); // mDelayedScheduler.Ensure() may Disconnect()
    3712             :                              // the promise, which must happen on the state
    3713             :                              // machine task queue.
    3714           0 :   MOZ_ASSERT(aTime > TimeUnit::Zero());
    3715           0 :   if (mDispatchedStateMachine) {
    3716           0 :     return;
    3717             :   }
    3718             : 
    3719           0 :   TimeStamp target = TimeStamp::Now() + aTime.ToTimeDuration();
    3720             : 
    3721             :   // It is OK to capture 'this' without causing UAF because the callback
    3722             :   // always happens before shutdown.
    3723           0 :   RefPtr<MediaDecoderStateMachine> self = this;
    3724           0 :   mDelayedScheduler.Ensure(target, [self] () {
    3725           0 :     self->mDelayedScheduler.CompleteRequest();
    3726           0 :     self->RunStateMachine();
    3727           0 :   }, [] () {
    3728           0 :     MOZ_DIAGNOSTIC_ASSERT(false);
    3729           0 :   });
    3730             : }
    3731             : 
    3732           0 : bool MediaDecoderStateMachine::OnTaskQueue() const
    3733             : {
    3734           0 :   return OwnerThread()->IsCurrentThreadIn();
    3735             : }
    3736             : 
    3737           0 : bool MediaDecoderStateMachine::IsStateMachineScheduled() const
    3738             : {
    3739           0 :   MOZ_ASSERT(OnTaskQueue());
    3740           0 :   return mDispatchedStateMachine || mDelayedScheduler.IsScheduled();
    3741             : }
    3742             : 
    3743             : void
    3744           0 : MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)
    3745             : {
    3746           0 :   MOZ_ASSERT(OnTaskQueue());
    3747           0 :   MOZ_ASSERT(aPlaybackRate != 0, "Should be handled by MediaDecoder::Pause()");
    3748             : 
    3749           0 :   mPlaybackRate = aPlaybackRate;
    3750           0 :   mMediaSink->SetPlaybackRate(mPlaybackRate);
    3751             : 
    3752             :   // Schedule next cycle to check if we can stop prerolling.
    3753           0 :   ScheduleStateMachine();
    3754           0 : }
    3755             : 
    3756           0 : void MediaDecoderStateMachine::PreservesPitchChanged()
    3757             : {
    3758           0 :   MOZ_ASSERT(OnTaskQueue());
    3759           0 :   mMediaSink->SetPreservesPitch(mPreservesPitch);
    3760           0 : }
    3761             : 
    3762             : TimeUnit
    3763           0 : MediaDecoderStateMachine::AudioEndTime() const
    3764             : {
    3765           0 :   MOZ_ASSERT(OnTaskQueue());
    3766           0 :   if (mMediaSink->IsStarted()) {
    3767           0 :     return mMediaSink->GetEndTime(TrackInfo::kAudioTrack);
    3768             :   }
    3769           0 :   return TimeUnit::Zero();
    3770             : }
    3771             : 
    3772             : TimeUnit
    3773           0 : MediaDecoderStateMachine::VideoEndTime() const
    3774             : {
    3775           0 :   MOZ_ASSERT(OnTaskQueue());
    3776           0 :   if (mMediaSink->IsStarted()) {
    3777           0 :     return mMediaSink->GetEndTime(TrackInfo::kVideoTrack);
    3778             :   }
    3779           0 :   return TimeUnit::Zero();
    3780             : }
    3781             : 
    3782             : void
    3783           0 : MediaDecoderStateMachine::OnMediaSinkVideoComplete()
    3784             : {
    3785           0 :   MOZ_ASSERT(OnTaskQueue());
    3786           0 :   MOZ_ASSERT(HasVideo());
    3787           0 :   LOG("[%s]", __func__);
    3788             : 
    3789           0 :   mMediaSinkVideoPromise.Complete();
    3790           0 :   mVideoCompleted = true;
    3791           0 :   ScheduleStateMachine();
    3792           0 : }
    3793             : 
    3794             : void
    3795           0 : MediaDecoderStateMachine::OnMediaSinkVideoError()
    3796             : {
    3797           0 :   MOZ_ASSERT(OnTaskQueue());
    3798           0 :   MOZ_ASSERT(HasVideo());
    3799           0 :   LOGW("[%s]", __func__);
    3800             : 
    3801           0 :   mMediaSinkVideoPromise.Complete();
    3802           0 :   mVideoCompleted = true;
    3803           0 :   if (HasAudio()) {
    3804           0 :     return;
    3805             :   }
    3806           0 :   DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
    3807             : }
    3808             : 
    3809           0 : void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
    3810             : {
    3811           0 :   MOZ_ASSERT(OnTaskQueue());
    3812           0 :   MOZ_ASSERT(HasAudio());
    3813           0 :   LOG("[%s]", __func__);
    3814             : 
    3815           0 :   mMediaSinkAudioPromise.Complete();
    3816           0 :   mAudioCompleted = true;
    3817             :   // To notify PlaybackEnded as soon as possible.
    3818           0 :   ScheduleStateMachine();
    3819             : 
    3820             :   // Report OK to Decoder Doctor (to know if issue may have been resolved).
    3821           0 :   mOnDecoderDoctorEvent.Notify(
    3822           0 :     DecoderDoctorEvent{DecoderDoctorEvent::eAudioSinkStartup, NS_OK});
    3823           0 : }
    3824             : 
    3825           0 : void MediaDecoderStateMachine::OnMediaSinkAudioError(nsresult aResult)
    3826             : {
    3827           0 :   MOZ_ASSERT(OnTaskQueue());
    3828           0 :   MOZ_ASSERT(HasAudio());
    3829           0 :   LOGW("[%s]", __func__);
    3830             : 
    3831           0 :   mMediaSinkAudioPromise.Complete();
    3832           0 :   mAudioCompleted = true;
    3833             : 
    3834             :   // Result should never be NS_OK in this *error* handler. Report to Dec-Doc.
    3835           0 :   MOZ_ASSERT(NS_FAILED(aResult));
    3836           0 :   mOnDecoderDoctorEvent.Notify(
    3837           0 :     DecoderDoctorEvent{DecoderDoctorEvent::eAudioSinkStartup, aResult});
    3838             : 
    3839             :   // Make the best effort to continue playback when there is video.
    3840           0 :   if (HasVideo()) {
    3841           0 :     return;
    3842             :   }
    3843             : 
    3844             :   // Otherwise notify media decoder/element about this error for it makes
    3845             :   // no sense to play an audio-only file without sound output.
    3846           0 :   DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
    3847             : }
    3848             : 
    3849             : void
    3850           0 : MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
    3851             : {
    3852           0 :   MOZ_ASSERT(OnTaskQueue());
    3853           0 :   mCDMProxyPromise.Complete();
    3854           0 :   mCDMProxy = aProxy;
    3855           0 :   mReader->SetCDMProxy(aProxy);
    3856           0 :   mStateObj->HandleCDMProxyReady();
    3857           0 : }
    3858             : 
    3859             : void
    3860           0 : MediaDecoderStateMachine::OnCDMProxyNotReady()
    3861             : {
    3862           0 :   MOZ_ASSERT(OnTaskQueue());
    3863           0 :   mCDMProxyPromise.Complete();
    3864           0 : }
    3865             : 
    3866             : void
    3867           0 : MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
    3868             : {
    3869           0 :   MOZ_ASSERT(OnTaskQueue());
    3870             : 
    3871           0 :   if (aCaptured == mAudioCaptured) {
    3872           0 :     return;
    3873             :   }
    3874             : 
    3875             :   // Rest these flags so they are consistent with the status of the sink.
    3876             :   // TODO: Move these flags into MediaSink to improve cohesion so we don't need
    3877             :   // to reset these flags when switching MediaSinks.
    3878           0 :   mAudioCompleted = false;
    3879           0 :   mVideoCompleted = false;
    3880             : 
    3881             :   // Backup current playback parameters.
    3882           0 :   MediaSink::PlaybackParams params = mMediaSink->GetPlaybackParams();
    3883             : 
    3884             :   // Stop and shut down the existing sink.
    3885           0 :   StopMediaSink();
    3886           0 :   mMediaSink->Shutdown();
    3887             : 
    3888             :   // Create a new sink according to whether audio is captured.
    3889           0 :   mMediaSink = CreateMediaSink(aCaptured);
    3890             : 
    3891             :   // Restore playback parameters.
    3892           0 :   mMediaSink->SetPlaybackParams(params);
    3893             : 
    3894           0 :   mAudioCaptured = aCaptured;
    3895             : 
    3896             :   // Don't buffer as much when audio is captured because we don't need to worry
    3897             :   // about high latency audio devices.
    3898           0 :   mAmpleAudioThreshold = mAudioCaptured
    3899           0 :     ? detail::AMPLE_AUDIO_THRESHOLD / 2 : detail::AMPLE_AUDIO_THRESHOLD;
    3900             : 
    3901           0 :   mStateObj->HandleAudioCaptured();
    3902             : }
    3903             : 
    3904           0 : uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
    3905             : {
    3906           0 :   MOZ_ASSERT(OnTaskQueue());
    3907           0 :   return (mReader->IsAsync() && mReader->VideoIsHardwareAccelerated())
    3908           0 :          ? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
    3909           0 :          : std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
    3910             : }
    3911             : 
    3912             : nsCString
    3913           0 : MediaDecoderStateMachine::GetDebugInfo()
    3914             : {
    3915           0 :   MOZ_ASSERT(OnTaskQueue());
    3916           0 :   return nsPrintfCString(
    3917             :            "MediaDecoderStateMachine State: GetMediaTime=%" PRId64 " GetClock="
    3918             :            "%" PRId64 " mMediaSink=%p state=%s mPlayState=%d "
    3919             :            "mSentFirstFrameLoadedEvent=%d IsPlaying=%d mAudioStatus=%s "
    3920             :            "mVideoStatus=%s mDecodedAudioEndTime=%" PRId64
    3921             :            " mDecodedVideoEndTime=%" PRId64 "mAudioCompleted=%d "
    3922             :            "mVideoCompleted=%d",
    3923           0 :            GetMediaTime().ToMicroseconds(),
    3924           0 :            mMediaSink->IsStarted() ? GetClock().ToMicroseconds() : -1,
    3925           0 :            mMediaSink.get(), ToStateStr(), mPlayState.Ref(),
    3926           0 :            mSentFirstFrameLoadedEvent, IsPlaying(), AudioRequestStatus(),
    3927             :            VideoRequestStatus(), mDecodedAudioEndTime.ToMicroseconds(),
    3928             :            mDecodedVideoEndTime.ToMicroseconds(),
    3929           0 :            mAudioCompleted, mVideoCompleted)
    3930           0 :          + mStateObj->GetDebugInfo() + nsCString("\n")
    3931           0 :          + mMediaSink->GetDebugInfo();
    3932             : }
    3933             : 
    3934             : RefPtr<MediaDecoder::DebugInfoPromise>
    3935           0 : MediaDecoderStateMachine::RequestDebugInfo()
    3936             : {
    3937             :   using PromiseType = MediaDecoder::DebugInfoPromise;
    3938           0 :   RefPtr<PromiseType::Private> p = new PromiseType::Private(__func__);
    3939           0 :   RefPtr<MediaDecoderStateMachine> self = this;
    3940           0 :   OwnerThread()->Dispatch(
    3941           0 :     NS_NewRunnableFunction(
    3942             :       "MediaDecoderStateMachine::RequestDebugInfo",
    3943           0 :       [self, p]() { p->Resolve(self->GetDebugInfo(), __func__); }),
    3944             :     AbstractThread::AssertDispatchSuccess,
    3945           0 :     AbstractThread::TailDispatch);
    3946           0 :   return p.forget();
    3947             : }
    3948             : 
    3949           0 : void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
    3950             :                                                bool aFinishWhenEnded)
    3951             : {
    3952           0 :   MOZ_ASSERT(NS_IsMainThread());
    3953           0 :   LOG("AddOutputStream aStream=%p!", aStream);
    3954           0 :   mOutputStreamManager->Add(aStream, aFinishWhenEnded);
    3955             :   nsCOMPtr<nsIRunnable> r =
    3956           0 :     NewRunnableMethod<bool>("MediaDecoderStateMachine::SetAudioCaptured",
    3957             :                             this,
    3958             :                             &MediaDecoderStateMachine::SetAudioCaptured,
    3959           0 :                             true);
    3960           0 :   OwnerThread()->Dispatch(r.forget());
    3961           0 : }
    3962             : 
    3963           0 : void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream)
    3964             : {
    3965           0 :   MOZ_ASSERT(NS_IsMainThread());
    3966           0 :   LOG("RemoveOutputStream=%p!", aStream);
    3967           0 :   mOutputStreamManager->Remove(aStream);
    3968           0 :   if (mOutputStreamManager->IsEmpty()) {
    3969             :     nsCOMPtr<nsIRunnable> r =
    3970           0 :       NewRunnableMethod<bool>("MediaDecoderStateMachine::SetAudioCaptured",
    3971             :                               this,
    3972             :                               &MediaDecoderStateMachine::SetAudioCaptured,
    3973           0 :                               false);
    3974           0 :     OwnerThread()->Dispatch(r.forget());
    3975             :   }
    3976           0 : }
    3977             : 
    3978             : size_t
    3979           0 : MediaDecoderStateMachine::SizeOfVideoQueue() const
    3980             : {
    3981           0 :   return mReader->SizeOfVideoQueueInBytes();
    3982             : }
    3983             : 
    3984             : size_t
    3985           0 : MediaDecoderStateMachine::SizeOfAudioQueue() const
    3986             : {
    3987           0 :   return mReader->SizeOfAudioQueueInBytes();
    3988             : }
    3989             : 
    3990             : AbstractCanonical<media::TimeIntervals>*
    3991           0 : MediaDecoderStateMachine::CanonicalBuffered() const
    3992             : {
    3993           0 :   return mReader->CanonicalBuffered();
    3994             : }
    3995             : 
    3996             : MediaEventSource<void>&
    3997           0 : MediaDecoderStateMachine::OnMediaNotSeekable() const
    3998             : {
    3999           0 :   return mReader->OnMediaNotSeekable();
    4000             : }
    4001             : 
    4002             : const char*
    4003           0 : MediaDecoderStateMachine::AudioRequestStatus() const
    4004             : {
    4005           0 :   MOZ_ASSERT(OnTaskQueue());
    4006           0 :   if (IsRequestingAudioData()) {
    4007           0 :     MOZ_DIAGNOSTIC_ASSERT(!IsWaitingAudioData());
    4008           0 :     return "pending";
    4009           0 :   } else if (IsWaitingAudioData()) {
    4010           0 :     return "waiting";
    4011             :   }
    4012           0 :   return "idle";
    4013             : }
    4014             : 
    4015             : const char*
    4016           0 : MediaDecoderStateMachine::VideoRequestStatus() const
    4017             : {
    4018           0 :   MOZ_ASSERT(OnTaskQueue());
    4019           0 :   if (IsRequestingVideoData()) {
    4020           0 :     MOZ_DIAGNOSTIC_ASSERT(!IsWaitingVideoData());
    4021           0 :     return "pending";
    4022           0 :   } else if (IsWaitingVideoData()) {
    4023           0 :     return "waiting";
    4024             :   }
    4025           0 :   return "idle";
    4026             : }
    4027             : 
    4028             : void
    4029           0 : MediaDecoderStateMachine::OnSuspendTimerResolved()
    4030             : {
    4031           0 :   LOG("OnSuspendTimerResolved");
    4032           0 :   mVideoDecodeSuspendTimer.CompleteRequest();
    4033           0 :   mStateObj->HandleVideoSuspendTimeout();
    4034           0 : }
    4035             : 
    4036             : void
    4037           0 : MediaDecoderStateMachine::CancelSuspendTimer()
    4038             : {
    4039           0 :   LOG("CancelSuspendTimer: State: %s, Timer.IsScheduled: %c",
    4040             :       ToStateStr(mStateObj->GetState()),
    4041             :       mVideoDecodeSuspendTimer.IsScheduled() ? 'T' : 'F');
    4042           0 :   MOZ_ASSERT(OnTaskQueue());
    4043           0 :   if (mVideoDecodeSuspendTimer.IsScheduled()) {
    4044           0 :     mOnPlaybackEvent.Notify(MediaEventType::CancelVideoSuspendTimer);
    4045             :   }
    4046           0 :   mVideoDecodeSuspendTimer.Reset();
    4047           0 : }
    4048             : 
    4049             : } // namespace mozilla
    4050             : 
    4051             : // avoid redefined macro in unified build
    4052             : #undef LOG
    4053             : #undef LOGV
    4054             : #undef LOGW
    4055             : #undef SLOGW
    4056             : #undef NS_DispatchToMainThread

Generated by: LCOV version 1.13