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
--- 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;