Bug 1421179. P1 - associate data with playback events published by MDSM. draft
authorJW Wang <jwwang@mozilla.com>
Fri, 01 Dec 2017 10:33:44 +0800
changeset 706075 0d65bbc2f8c61ff296a03548d2f6d349229970fa
parent 706013 210b84992c56056ce4018e087d95d7caecc89b35
child 706076 77d8acea6140581fd20deaf802872f9a21bd5980
child 706212 52c5478f9e28f67d957868b0d3852a8a2f9ad707
push id91691
push userjwwang@mozilla.com
push dateFri, 01 Dec 2017 07:25:53 +0000
bugs1421179
milestone59.0a1
Bug 1421179. P1 - associate data with playback events published by MDSM. This is required for we want to associate playback offset with the PlaybackStarted/PlaybackStopped events. MozReview-Commit-ID: JkRhC2QE7kr
dom/media/ChannelMediaDecoder.cpp
dom/media/ChannelMediaDecoder.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/ChannelMediaDecoder.cpp
+++ b/dom/media/ChannelMediaDecoder.cpp
@@ -346,31 +346,31 @@ ChannelMediaDecoder::CanPlayThroughImpl(
 bool
 ChannelMediaDecoder::IsLiveStream()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mResource->IsLiveStream();
 }
 
 void
-ChannelMediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
+ChannelMediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MediaDecoder::OnPlaybackEvent(aEvent);
-  switch (aEvent) {
-    case MediaEventType::PlaybackStarted:
+  switch (aEvent.mType) {
+    case MediaPlaybackEvent::PlaybackStarted:
       mPlaybackStatistics.Start();
       break;
-    case MediaEventType::PlaybackStopped:
+    case MediaPlaybackEvent::PlaybackStopped:
       mPlaybackStatistics.Stop();
       ComputePlaybackRate();
       break;
     default:
       break;
   }
+  MediaDecoder::OnPlaybackEvent(Move(aEvent));
 }
 
 void
 ChannelMediaDecoder::DurationChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   AbstractThread::AutoEnter context(AbstractMainThread());
   MediaDecoder::DurationChanged();
--- a/dom/media/ChannelMediaDecoder.h
+++ b/dom/media/ChannelMediaDecoder.h
@@ -51,17 +51,17 @@ class ChannelMediaDecoder : public Media
     // The decoder to send notifications. Main-thread only.
     ChannelMediaDecoder* mDecoder = nullptr;
     nsCOMPtr<nsITimer> mTimer;
     bool mTimerArmed = false;
     const RefPtr<AbstractThread> mAbstractMainThread;
   };
 
 protected:
-  void OnPlaybackEvent(MediaEventType aEvent) override;
+  void OnPlaybackEvent(MediaPlaybackEvent&& aEvent) override;
   void DurationChanged() override;
   void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
                       UniquePtr<MetadataTags> aTags,
                       MediaDecoderEventVisibility aEventVisibility) override;
 
   RefPtr<ResourceCallback> mResourceCallback;
   RefPtr<BaseMediaResource> mResource;
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -523,48 +523,48 @@ MediaDecoder::NotifyXPCOMShutdown()
 MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
   MediaMemoryTracker::RemoveMediaDecoder(this);
 }
 
 void
-MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
+MediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent)
 {
-  switch (aEvent) {
-    case MediaEventType::PlaybackEnded:
+  switch (aEvent.mType) {
+    case MediaPlaybackEvent::PlaybackEnded:
       PlaybackEnded();
       break;
-    case MediaEventType::SeekStarted:
+    case MediaPlaybackEvent::SeekStarted:
       SeekingStarted();
       break;
-    case MediaEventType::Loop:
+    case MediaPlaybackEvent::Loop:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("seeked"));
       break;
-    case MediaEventType::Invalidate:
+    case MediaPlaybackEvent::Invalidate:
       Invalidate();
       break;
-    case MediaEventType::EnterVideoSuspend:
+    case MediaPlaybackEvent::EnterVideoSuspend:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
       break;
-    case MediaEventType::ExitVideoSuspend:
+    case MediaPlaybackEvent::ExitVideoSuspend:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
       break;
-    case MediaEventType::StartVideoSuspendTimer:
+    case MediaPlaybackEvent::StartVideoSuspendTimer:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozstartvideosuspendtimer"));
       break;
-    case MediaEventType::CancelVideoSuspendTimer:
+    case MediaPlaybackEvent::CancelVideoSuspendTimer:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
       break;
-    case MediaEventType::VideoOnlySeekBegin:
+    case MediaPlaybackEvent::VideoOnlySeekBegin:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekbegin"));
       break;
-    case MediaEventType::VideoOnlySeekCompleted:
+    case MediaPlaybackEvent::VideoOnlySeekCompleted:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekcompleted"));
       break;
     default:
       break;
   }
 }
 
 void
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -34,18 +34,18 @@ class nsIPrincipal;
 
 namespace mozilla {
 
 class AbstractThread;
 class FrameStatistics;
 class VideoFrameContainer;
 class MediaFormatReader;
 class MediaDecoderStateMachine;
+struct MediaPlaybackEvent;
 
-enum class MediaEventType : int8_t;
 enum class Visibility : uint8_t;
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with MediaDecoder::GetCurrentTime implementation.
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
@@ -419,17 +419,17 @@ protected:
     MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     mExplicitDuration = Some(aValue);
 
     // We Invoke DurationChanged explicitly, rather than using a watcher, so
     // that it takes effect immediately, rather than at the end of the current task.
     DurationChanged();
   }
 
-  virtual void OnPlaybackEvent(MediaEventType aEvent);
+  virtual void OnPlaybackEvent(MediaPlaybackEvent&& aEvent);
 
   // Called when the metadata from the media file has been loaded by the
   // state machine. Call on the main thread only.
   virtual void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
                               UniquePtr<MetadataTags> aTags,
                               MediaDecoderEventVisibility aEventVisibility);
 
   /******
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -674,17 +674,17 @@ public:
   void HandleVideoSuspendTimeout() override
   {
     // No video, so nothing to suspend.
     if (!mMaster->HasVideo()) {
       return;
     }
 
     mMaster->mVideoDecodeSuspended = true;
-    mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
+    mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::EnterVideoSuspend);
     Reader()->SetVideoBlankDecode(true);
   }
 
   void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override
   {
     if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
       // Schedule Step() to check if we can start playback.
       mMaster->ScheduleStateMachine();
@@ -827,31 +827,31 @@ public:
     mSeekJob = Move(aSeekJob);
     mVisibility = aVisibility;
 
     // Always switch off the blank decoder otherwise we might become visible
     // in the middle of seeking and won't have a valid video frame to show
     // when seek is done.
     if (mMaster->mVideoDecodeSuspended) {
       mMaster->mVideoDecodeSuspended = false;
-      mMaster->mOnPlaybackEvent.Notify(MediaEventType::ExitVideoSuspend);
+      mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::ExitVideoSuspend);
       Reader()->SetVideoBlankDecode(false);
     }
 
     // Suppressed visibility comes from two cases: (1) leaving dormant state,
     // and (2) resuming suspended video decoder. We want both cases to be
     // transparent to the user. So we only notify the change when the seek
     // request is from the user.
     if (mVisibility == EventVisibility::Observable) {
       // Don't stop playback for a video-only seek since we want to keep playing
       // audio and we don't need to stop playback while leaving dormant for the
       // playback should has been stopped.
       mMaster->StopPlayback();
       mMaster->UpdatePlaybackPositionInternal(mSeekJob.mTarget->GetTime());
-      mMaster->mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
+      mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::SeekStarted);
       mMaster->mOnNextFrameStatus.Notify(
         MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
     }
 
     RefPtr<MediaDecoder::SeekPromise> p = mSeekJob.mPromise.Ensure(__func__);
 
     DoSeek();
 
@@ -1637,27 +1637,28 @@ public:
     MOZ_ASSERT(aSeekJob.mTarget->IsVideoOnly());
     MOZ_ASSERT(aVisibility == EventVisibility::Suppressed);
 
     RefPtr<MediaDecoder::SeekPromise> p =
       AccurateSeekingState::Enter(Move(aSeekJob), aVisibility);
 
     // Dispatch a mozvideoonlyseekbegin event to indicate UI for corresponding
     // changes.
-    mMaster->mOnPlaybackEvent.Notify(MediaEventType::VideoOnlySeekBegin);
+    mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::VideoOnlySeekBegin);
 
     return p.forget();
   }
 
   void Exit() override
   {
     // We are completing or discarding this video-only seek operation now,
     // dispatch an event so that the UI can change in response to the end
     // of video-only seek.
-    mMaster->mOnPlaybackEvent.Notify(MediaEventType::VideoOnlySeekCompleted);
+    mMaster->mOnPlaybackEvent.Notify(
+      MediaPlaybackEvent::VideoOnlySeekCompleted);
 
     AccurateSeekingState::Exit();
   }
 
   void HandleAudioDecoded(AudioData* aAudio) override
   {
     MOZ_ASSERT(mDoneAudioSeeking && !mDoneVideoSeeking,
                "Seek shouldn't be finished");
@@ -1853,17 +1854,17 @@ public:
   void HandleVideoSuspendTimeout() override
   {
     // No video, so nothing to suspend.
     if (!mMaster->HasVideo()) {
      return;
     }
 
     mMaster->mVideoDecodeSuspended = true;
-    mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
+    mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::EnterVideoSuspend);
     Reader()->SetVideoBlankDecode(true);
   }
 
 private:
   TimeStamp mBufferingStart;
 
   // The maximum number of second we spend buffering when we are short on
   // unbuffered data.
@@ -1942,17 +1943,17 @@ public:
         mMaster->mDuration = Some(clockTime);
       }
       mMaster->UpdatePlaybackPosition(clockTime);
 
       // Ensure readyState is updated before firing the 'ended' event.
       mMaster->mOnNextFrameStatus.Notify(
         MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
 
-      mMaster->mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
+      mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::PlaybackEnded);
 
       mSentPlaybackEndedEvent = true;
 
       // MediaSink::GetEndTime() must be called before stopping playback.
       mMaster->StopMediaSink();
     }
   }
 
@@ -2324,17 +2325,17 @@ DecodingState::Step()
 
   TimeUnit before = mMaster->GetMediaTime();
   mMaster->UpdatePlaybackPositionPeriodically();
 
   // Fire the `seeking` and `seeked` events to meet the HTML spec
   // when the media is looped back from the end to the beginning.
   if (before > mMaster->GetMediaTime()) {
     MOZ_ASSERT(mMaster->mLooping);
-    mMaster->mOnPlaybackEvent.Notify(MediaEventType::Loop);
+    mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::Loop);
   // After looping is cancelled, the time won't be corrected, and therefore we
   // can check it to see if the end of the media track is reached. Make sure
   // the media is started before comparing the time, or it's meaningless.
   // Without checking IsStarted(), the media will be terminated immediately
   // after seeking forward. When the state is just transited from seeking state,
   // GetClock() is smaller than GetMediaTime(), since GetMediaTime() is updated
   // upon seek is completed while GetClock() will be updated after the media is
   // started again.
@@ -2504,17 +2505,17 @@ SeekingState::SeekCompleted()
   }
 
   // Try to decode another frame to detect if we're at the end...
   SLOG("Seek completed, mCurrentPosition=%" PRId64,
        mMaster->mCurrentPosition.Ref().ToMicroseconds());
 
   if (mMaster->VideoQueue().PeekFront()) {
     mMaster->mMediaSink->Redraw(Info().mVideo);
-    mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
+    mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::Invalidate);
   }
 
   GoToNextState();
 }
 
 void
 MediaDecoderStateMachine::
 BufferingState::Step()
@@ -2900,17 +2901,17 @@ nsresult MediaDecoderStateMachine::Init(
 }
 
 void
 MediaDecoderStateMachine::StopPlayback()
 {
   MOZ_ASSERT(OnTaskQueue());
   LOG("StopPlayback()");
 
-  mOnPlaybackEvent.Notify(MediaEventType::PlaybackStopped);
+  mOnPlaybackEvent.Notify(MediaPlaybackEvent::PlaybackStopped);
 
   if (IsPlaying()) {
     mMediaSink->SetPlaying(false);
     MOZ_ASSERT(!IsPlaying());
 #ifdef XP_WIN
     if (mHiResTimersRequested) {
       mHiResTimersRequested = false;
       timeEndPeriod(1);
@@ -2931,17 +2932,17 @@ void MediaDecoderStateMachine::MaybeStar
   }
 
   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
     LOG("Not starting playback [mPlayState=%d]", mPlayState.Ref());
     return;
   }
 
   LOG("MaybeStartPlayback() starting playback");
-  mOnPlaybackEvent.Notify(MediaEventType::PlaybackStarted);
+  mOnPlaybackEvent.Notify(MediaPlaybackEvent::PlaybackStarted);
   StartMediaSink();
 
 #ifdef XP_WIN
   if (!mHiResTimersRequested && mShouldUseHiResTimers) {
     mHiResTimersRequested = true;
     // Ensure high precision timers are enabled on Windows, otherwise the state
     // machine isn't woken up at reliable intervals to set the next frame, and we
     // drop frames while painting. Note that each call must be matched by a
@@ -3077,17 +3078,17 @@ void MediaDecoderStateMachine::SetVideoD
   // Start timer to trigger suspended video decoding.
   if (mVideoDecodeMode == VideoDecodeMode::Suspend) {
     TimeStamp target = TimeStamp::Now() + SuspendBackgroundVideoDelay();
 
     RefPtr<MediaDecoderStateMachine> self = this;
     mVideoDecodeSuspendTimer.Ensure(target,
                                     [=]() { self->OnSuspendTimerResolved(); },
                                     [] () { MOZ_DIAGNOSTIC_ASSERT(false); });
-    mOnPlaybackEvent.Notify(MediaEventType::StartVideoSuspendTimer);
+    mOnPlaybackEvent.Notify(MediaPlaybackEvent::StartVideoSuspendTimer);
     return;
   }
 
   // Resuming from suspended decoding
 
   // If suspend timer exists, destroy it.
   CancelSuspendTimer();
 
@@ -3948,17 +3949,17 @@ MediaDecoderStateMachine::OnSuspendTimer
 void
 MediaDecoderStateMachine::CancelSuspendTimer()
 {
   LOG("CancelSuspendTimer: State: %s, Timer.IsScheduled: %c",
       ToStateStr(mStateObj->GetState()),
       mVideoDecodeSuspendTimer.IsScheduled() ? 'T' : 'F');
   MOZ_ASSERT(OnTaskQueue());
   if (mVideoDecodeSuspendTimer.IsScheduled()) {
-    mOnPlaybackEvent.Notify(MediaEventType::CancelVideoSuspendTimer);
+    mOnPlaybackEvent.Notify(MediaPlaybackEvent::CancelVideoSuspendTimer);
   }
   mVideoDecodeSuspendTimer.Reset();
 }
 
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef LOG
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -109,30 +109,42 @@ class AbstractThread;
 class AudioSegment;
 class DecodedStream;
 class OutputStreamManager;
 class ReaderProxy;
 class TaskQueue;
 
 extern LazyLogModule gMediaDecoderLog;
 
-enum class MediaEventType : int8_t
+struct MediaPlaybackEvent
 {
-  PlaybackStarted,
-  PlaybackStopped,
-  PlaybackEnded,
-  SeekStarted,
-  Loop,
-  Invalidate,
-  EnterVideoSuspend,
-  ExitVideoSuspend,
-  StartVideoSuspendTimer,
-  CancelVideoSuspendTimer,
-  VideoOnlySeekBegin,
-  VideoOnlySeekCompleted,
+  enum EventType
+  {
+    PlaybackStarted,
+    PlaybackStopped,
+    PlaybackEnded,
+    SeekStarted,
+    Loop,
+    Invalidate,
+    EnterVideoSuspend,
+    ExitVideoSuspend,
+    StartVideoSuspendTimer,
+    CancelVideoSuspendTimer,
+    VideoOnlySeekBegin,
+    VideoOnlySeekCompleted,
+  } mType;
+
+  using DataType = Variant<Nothing, int64_t>;
+  DataType mData;
+
+  MOZ_IMPLICIT MediaPlaybackEvent(EventType aType)
+    : mType(aType)
+    , mData(Nothing{})
+  {
+  }
 };
 
 enum class VideoDecodeMode : uint8_t
 {
   Normal,
   Suspend
 };
 
@@ -241,18 +253,20 @@ public:
                       UniquePtr<MetadataTags>,
                       MediaDecoderEventVisibility>&
   MetadataLoadedEvent() { return mMetadataLoadedEvent; }
 
   MediaEventSourceExc<nsAutoPtr<MediaInfo>,
                       MediaDecoderEventVisibility>&
   FirstFrameLoadedEvent() { return mFirstFrameLoadedEvent; }
 
-  MediaEventSource<MediaEventType>&
-  OnPlaybackEvent() { return mOnPlaybackEvent; }
+  MediaEventSource<MediaPlaybackEvent>& OnPlaybackEvent()
+  {
+    return mOnPlaybackEvent;
+  }
   MediaEventSource<MediaResult>&
   OnPlaybackErrorEvent() { return mOnPlaybackErrorEvent; }
 
   MediaEventSource<DecoderDoctorEvent>&
   OnDecoderDoctorEvent() { return mOnDecoderDoctorEvent; }
 
   MediaEventSource<NextFrameStatus>&
   OnNextFrameStatus() { return mOnNextFrameStatus; }
@@ -654,17 +668,17 @@ private:
   MediaEventListener mOnMediaNotSeekable;
 
   MediaEventProducerExc<UniquePtr<MediaInfo>,
                         UniquePtr<MetadataTags>,
                         MediaDecoderEventVisibility> mMetadataLoadedEvent;
   MediaEventProducerExc<nsAutoPtr<MediaInfo>,
                         MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
 
-  MediaEventProducer<MediaEventType> mOnPlaybackEvent;
+  MediaEventProducer<MediaPlaybackEvent> mOnPlaybackEvent;
   MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
 
   MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
 
   MediaEventProducer<NextFrameStatus> mOnNextFrameStatus;
 
   const bool mIsMSE;