Bug 1135785 - Hoist some work onto the state machine thread and tighten down our assertions. r=cpearce
authorBobby Holley <bobbyholley@gmail.com>
Mon, 23 Feb 2015 15:43:16 -0800
changeset 261590 0b402720106c3ab03a2df8ddd0ff6beab9c6bd3b
parent 261589 6a49d13612c82fae502d59005255068c4ffc2023
child 261591 a622dbe33efb6e9053073ebd8c51cbd3493111dd
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1135785
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1135785 - Hoist some work onto the state machine thread and tighten down our assertions. r=cpearce
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaQueue.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -305,32 +305,30 @@ bool MediaDecoderStateMachine::HasFuture
 
 bool MediaDecoderStateMachine::HaveNextFrameData() {
   AssertCurrentThreadInMonitor();
   return (!HasAudio() || HasFutureAudio()) &&
          (!HasVideo() || VideoQueue().GetSize() > 0);
 }
 
 int64_t MediaDecoderStateMachine::GetDecodedAudioDuration() {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
   int64_t audioDecoded = AudioQueue().Duration();
   if (mAudioEndTime != -1) {
     audioDecoded += mAudioEndTime - GetMediaTime();
   }
   return audioDecoded;
 }
 
 void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
                                                DecodedStreamData* aStream,
                                                AudioSegment* aOutput)
 {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   // This logic has to mimic AudioSink closely to make sure we write
   // the exact same silences
   CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
       UsecsToFrames(mInfo.mAudio.mRate, aStream->mInitialTime + mStartTime);
   CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudio.mRate, aAudio->mTime);
 
@@ -923,16 +921,17 @@ MediaDecoderStateMachine::AcquireMonitor
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   DecodeError();
 }
 
 void
 MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
   if ((IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
       (IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
     return;
   }
   if (NS_FAILED(FinishDecodeFirstFrame())) {
     DecodeError();
   }
@@ -1043,16 +1042,17 @@ MediaDecoderStateMachine::OnVideoDecoded
       return;
     }
   }
 }
 
 void
 MediaDecoderStateMachine::CheckIfSeekComplete()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   const bool videoSeekComplete = IsVideoSeekComplete();
   if (HasVideo() && !videoSeekComplete) {
     // We haven't reached the target. Ensure we have requested another sample.
     if (NS_FAILED(EnsureVideoDecodeTaskQueued())) {
       DECODER_WARN("Failed to request video during seek");
       DecodeError();
@@ -1070,17 +1070,17 @@ MediaDecoderStateMachine::CheckIfSeekCom
 
   SAMPLE_LOG("CheckIfSeekComplete() audioSeekComplete=%d videoSeekComplete=%d",
              audioSeekComplete, videoSeekComplete);
 
   if (audioSeekComplete && videoSeekComplete) {
     mDecodeToSeekTarget = false;
     RefPtr<nsIRunnable> task(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
-    nsresult rv = DecodeTaskQueue()->Dispatch(task);
+    nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
       DecodeError();
     }
   }
 }
 
 bool
 MediaDecoderStateMachine::IsAudioDecoding()
@@ -1143,33 +1143,39 @@ nsresult MediaDecoderStateMachine::Init(
   rv = mReader->Init(cloneReader);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::StopPlayback()
 {
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only, and we can invoke
+  // DispatchDecodeTasksIfNeeded directly.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
   DECODER_LOG("StopPlayback()");
 
   AssertCurrentThreadInMonitor();
 
   mDecoder->NotifyPlaybackStopped();
 
   if (IsPlaying()) {
     mPlayDuration = GetClock() - mStartTime;
     SetPlayStartTime(TimeStamp());
   }
   // Notify the audio sink, so that it notices that we've stopped playing,
   // so it can pause audio playback.
   mDecoder->GetReentrantMonitor().NotifyAll();
   NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()");
   mDecoder->UpdateStreamBlockingForStateMachinePlaying();
 
-  DispatchDecodeTasksIfNeeded();
+  nsCOMPtr<nsIRunnable> event =
+    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded);
+  GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 void MediaDecoderStateMachine::SetSyncPointForMediaStream()
 {
   AssertCurrentThreadInMonitor();
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
   if (!stream) {
@@ -1239,19 +1245,20 @@ void MediaDecoderStateMachine::MaybeStar
 
   mDecoder->GetReentrantMonitor().NotifyAll();
   mDecoder->UpdateStreamBlockingForStateMachinePlaying();
   DispatchDecodeTasksIfNeeded();
 }
 
 void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
 {
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
   SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld) (mStartTime=%lld)", aTime, mStartTime);
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine thread.");
   AssertCurrentThreadInMonitor();
 
   NS_ASSERTION(mStartTime >= 0, "Should have positive mStartTime");
   mCurrentFrameTime = aTime - mStartTime;
   NS_ASSERTION(mCurrentFrameTime >= 0, "CurrentTime should be positive!");
   if (aTime > mEndTime) {
     NS_ASSERTION(mCurrentFrameTime > GetDuration(),
                  "CurrentTime must be after duration if aTime > endTime!");
@@ -1536,18 +1543,17 @@ void MediaDecoderStateMachine::Shutdown(
   if (mAudioSink) {
     mAudioSink->PrepareToShutdown();
   }
   mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
 void MediaDecoderStateMachine::StartDecoding()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mState == DECODER_STATE_DECODING) {
     return;
   }
   SetState(DECODER_STATE_DECODING);
 
   mDecodeStartTime = TimeStamp::Now();
 
@@ -1638,16 +1644,20 @@ void MediaDecoderStateMachine::PlayInter
     DispatchDecodeTasksIfNeeded();
   }
 
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::ResetPlayback()
 {
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
+
   // We should be reseting because we're seeking, shutting down, or
   // entering dormant state. We could also be in the process of going dormant,
   // and have just switched to exiting dormant before we finished entering
   // dormant, hence the DECODING_NONE case below.
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(mState == DECODER_STATE_SEEKING ||
              mState == DECODER_STATE_SHUTDOWN ||
              mState == DECODER_STATE_DORMANT ||
@@ -1780,18 +1790,19 @@ MediaDecoderStateMachine::StartSeek(cons
   if (mAudioCaptured) {
     mDecoder->RecreateDecodedStream(seekTime - mStartTime);
   }
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::StopAudioThread()
 {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  // XXXbholley - Needed because DecodeSeek runs on the decode thread.
+  // Once bug 1135170 lands, this becomes state-machine only.
+  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
   AssertCurrentThreadInMonitor();
 
   if (mStopAudioThread) {
     // Audio sink is being stopped in another thread. Wait until finished.
     while (mAudioSink) {
       mDecoder->GetReentrantMonitor().Wait();
     }
     return;
@@ -1829,37 +1840,38 @@ MediaDecoderStateMachine::EnqueueDecodeM
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
 {
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
 
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
-  nsresult rv = DecodeTaskQueue()->Dispatch(task);
+  nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 void
 MediaDecoderStateMachine::SetReaderIdle()
 {
-#ifdef PR_LOGGING
-  {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    DECODER_LOG("SetReaderIdle() audioQueue=%lld videoQueue=%lld",
-                GetDecodedAudioDuration(),
-                VideoQueue().Duration());
-  }
-#endif
   MOZ_ASSERT(OnDecodeThread());
+  DECODER_LOG("Invoking SetReaderIdle()");
   mReader->SetIdle();
 }
 
 void
+MediaDecoderStateMachine::AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded()
+{
+  MOZ_ASSERT(OnStateMachineThread());
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  DispatchDecodeTasksIfNeeded();
+}
+
+void
 MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
 {
   AssertCurrentThreadInMonitor();
 
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
@@ -1905,63 +1917,63 @@ MediaDecoderStateMachine::DispatchDecode
   if (needToDecodeAudio) {
     EnsureAudioDecodeTaskQueued();
   }
   if (needToDecodeVideo) {
     EnsureVideoDecodeTaskQueued();
   }
 
   if (needIdle) {
+    DECODER_LOG("Dispatching SetReaderIdle() audioQueue=%lld videoQueue=%lld",
+                GetDecodedAudioDuration(),
+                VideoQueue().Duration());
     RefPtr<nsIRunnable> event = NS_NewRunnableMethod(
         this, &MediaDecoderStateMachine::SetReaderIdle);
     nsresult rv = DecodeTaskQueue()->Dispatch(event.forget());
     if (NS_FAILED(rv) && mState != DECODER_STATE_SHUTDOWN) {
       DECODER_WARN("Failed to dispatch event to set decoder idle state");
     }
   }
 }
 
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeSeekTask()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeSeek));
   nsresult rv = DecodeTaskQueue()->Dispatch(task);
   if (NS_FAILED(rv)) {
     DECODER_WARN("Dispatch DecodeSeek task failed.");
     DecodeError();
   }
 
   return rv;
 }
 
 nsresult
 MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
 
   if (NeedToDecodeAudio()) {
     return EnsureAudioDecodeTaskQueued();
   }
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
 
   SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%s",
               IsAudioDecoding(), AudioRequestStatus());
 
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
@@ -1983,38 +1995,35 @@ MediaDecoderStateMachine::EnsureAudioDec
                   &MediaDecoderStateMachine::OnAudioNotDecoded));
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
 
   if (NeedToDecodeVideo()) {
     return EnsureVideoDecodeTaskQueued();
   }
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%s",
              IsVideoDecoding(), VideoRequestStatus());
 
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
-
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_DECODING_FIRSTFRAME &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
     return NS_OK;
   }
 
   if (!IsVideoDecoding() || mVideoDataRequest.Exists() ||
@@ -2041,18 +2050,17 @@ MediaDecoderStateMachine::EnsureVideoDec
                   &MediaDecoderStateMachine::OnVideoDecoded,
                   &MediaDecoderStateMachine::OnVideoNotDecoded));
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::StartAudioThread()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
   if (mAudioCaptured) {
     NS_ASSERTION(mStopAudioThread, "mStopAudioThread must always be true if audio is captured");
     return NS_OK;
   }
 
   mStopAudioThread = false;
   if (HasAudio() && !mAudioSink) {
@@ -2301,59 +2309,58 @@ MediaDecoderStateMachine::EnqueueFirstFr
     new FirstFrameLoadedEventRunner(mDecoder, info, mSentFirstFrameLoadedEvent);
   NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   mSentFirstFrameLoadedEvent = true;
 }
 
 void
 MediaDecoderStateMachine::CallDecodeFirstFrame()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mState != DECODER_STATE_DECODING_FIRSTFRAME) {
     return;
   }
   if (NS_FAILED(DecodeFirstFrame())) {
     DECODER_WARN("Decode failed to start, shutting down decoder");
     DecodeError();
   }
 }
 
 nsresult
 MediaDecoderStateMachine::DecodeFirstFrame()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
   DECODER_LOG("DecodeFirstFrame started");
 
   if (HasAudio()) {
     RefPtr<nsIRunnable> decodeTask(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
-    AudioQueue().AddPopListener(decodeTask, DecodeTaskQueue());
+    AudioQueue().AddPopListener(decodeTask, GetStateMachineThread());
   }
   if (HasVideo()) {
     RefPtr<nsIRunnable> decodeTask(
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
-    VideoQueue().AddPopListener(decodeTask, DecodeTaskQueue());
+    VideoQueue().AddPopListener(decodeTask, GetStateMachineThread());
   }
 
   if (IsRealTime()) {
     SetStartTime(0);
     nsresult res = FinishDecodeFirstFrame();
     NS_ENSURE_SUCCESS(res, res);
   } else if (mSentFirstFrameLoadedEvent) {
     // We're resuming from dormant state, so we don't need to request
     // the first samples in order to determine the media start time,
     // we have the start time from last time we loaded.
     SetStartTime(mStartTime);
     nsresult res = FinishDecodeFirstFrame();
     NS_ENSURE_SUCCESS(res, res);
   } else {
-    // NB: We're already on the decode thread, but we proxy these anyway so that
-    // we don't need to worry about dropping locks.
     if (HasAudio()) {
       mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
                                              __func__, &MediaDecoderReader::RequestAudioData)
         ->RefableThen(mScheduler.get(), __func__, this,
                       &MediaDecoderStateMachine::OnAudioDecoded,
                       &MediaDecoderStateMachine::OnAudioNotDecoded));
     }
     if (HasVideo()) {
@@ -2368,17 +2375,17 @@ MediaDecoderStateMachine::DecodeFirstFra
 
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::FinishDecodeFirstFrame()
 {
   AssertCurrentThreadInMonitor();
-  MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread(), "Currently ambiguous - Fixed up in next patch");
+  MOZ_ASSERT(OnStateMachineThread());
   DECODER_LOG("FinishDecodeFirstFrame");
 
   if (mState == DECODER_STATE_SHUTDOWN) {
     return NS_ERROR_FAILURE;
   }
 
   if (!IsRealTime() && !mSentFirstFrameLoadedEvent) {
     const VideoData* v = VideoQueue().PeekFront();
@@ -2513,18 +2520,18 @@ void MediaDecoderStateMachine::DecodeSee
   }
 
   mDecodeToSeekTarget = false;
 
   if (!currentTimeChanged) {
     DECODER_LOG("Seek !currentTimeChanged...");
     mDropAudioUntilNextDiscontinuity = false;
     mDropVideoUntilNextDiscontinuity = false;
-    nsresult rv = DecodeTaskQueue()->Dispatch(
-      NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
+    nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted);
+    nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
       DecodeError();
     }
   } else {
     // The seek target is different than the current playback position,
     // we'll need to seek the playback position, so shutdown our decode
     // thread and audio sink.
     StopAudioThread();
@@ -2556,17 +2563,21 @@ MediaDecoderStateMachine::OnSeekComplete
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mWaitingForDecoderSeek = false;
   mCancelingSeek = false;
 
   // We must decode the first samples of active streams, so we can determine
   // the new stream time. So dispatch tasks to do that.
   mDecodeToSeekTarget = true;
-  DispatchDecodeTasksIfNeeded();
+
+  // XXXbholley - This can become a direct call once bug 1135170 lands.
+  nsCOMPtr<nsIRunnable> event =
+    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded);
+  GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 void
 MediaDecoderStateMachine::OnSeekFailed(nsresult aResult)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   bool wasCanceled = mCancelingSeek;
   mWaitingForDecoderSeek = false;
@@ -2584,25 +2595,25 @@ MediaDecoderStateMachine::OnSeekFailed(n
                   &MediaDecoderStateMachine::OnSeekFailed);
     mWaitingForDecoderSeek = true;
   }
 }
 
 void
 MediaDecoderStateMachine::SeekCompleted()
 {
+  MOZ_ASSERT(OnStateMachineThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   // We must reset the seek target when exiting this function, but not
   // before, as if we dropped the monitor in any function called here,
   // we may begin a new seek on the state machine thread, and be in
   // an inconsistent state.
   AutoSetOnScopeExit<SeekTarget> reset(mCurrentSeekTarget, SeekTarget());
 
-  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   if (mState != DECODER_STATE_SEEKING) {
     return;
   }
 
   int64_t seekTime = mCurrentSeekTarget.mTime;
   int64_t newCurrentTime = mCurrentSeekTarget.mTime;
 
   // Setup timestamp state.
@@ -2970,18 +2981,17 @@ nsresult MediaDecoderStateMachine::RunSt
   }
 
   return NS_OK;
 }
 
 void
 MediaDecoderStateMachine::FlushDecoding()
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   AssertCurrentThreadInMonitor();
 
   {
     // Put a task in the decode queue to abort any decoding operations.
     // The reader is not supposed to put any tasks to deliver samples into
     // the queue after this runs (unless we request another sample from it).
     RefPtr<nsIRunnable> task;
     task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ResetDecode);
@@ -3022,18 +3032,17 @@ MediaDecoderStateMachine::ResetDecode()
     }
   }
   mReader->ResetDecode();
 }
 
 void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
                                                 TimeStamp aTarget)
 {
-  NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
-               "Should be on state machine or decode thread.");
+  MOZ_ASSERT(OnStateMachineThread());
   mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
 
   if (aData->mDuplicate) {
     return;
   }
 
   VERBOSE_LOG("playing video frame %lld (queued=%i, state-machine=%i, decoder-queued=%i)",
               aData->mTime, VideoQueue().GetSize() + mReader->SizeOfVideoQueueInFrames(),
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -614,17 +614,17 @@ protected:
 
   // Dispatches a LoadedMetadataEvent.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   void EnqueueLoadedMetadataEvent();
 
   void EnqueueFirstFrameLoadedEvent();
 
-  // Dispatches a task to the decode task queue to begin decoding content.
+  // Dispatches a task to the state machine thread to begin decoding content.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   nsresult EnqueueDecodeFirstFrameTask();
 
   // Dispatches a task to the decode task queue to seek the decoder.
   // The decoder monitor must be held.
   nsresult EnqueueDecodeSeekTask();
 
@@ -649,16 +649,17 @@ protected:
   // the decode task queue, don't call it directly.
   void SetReaderIdle();
 
   // Re-evaluates the state and determines whether we need to dispatch
   // events to run the decode, or if not whether we should set the reader
   // to idle mode. This is threadsafe, and can be called from any thread.
   // The decoder monitor must be held.
   void DispatchDecodeTasksIfNeeded();
+  void AcquireMonitorAndInvokeDispatchDecodeTasksIfNeeded();
 
   // Returns the "media time". This is the absolute time which the media
   // playback has reached. i.e. this returns values in the range
   // [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
   // not start at 0. Note this is different to the value returned
   // by GetCurrentTime(), which is in the range [0,duration].
   int64_t GetMediaTime() const {
     AssertCurrentThreadInMonitor();
@@ -676,17 +677,17 @@ protected:
 
   // Load metadata. Called on the decode thread. The decoder monitor
   // must be held with exactly one lock count.
   nsresult DecodeMetadata();
 
   // Wraps the call to DecodeMetadata(), signals a DecodeError() on failure.
   void CallDecodeMetadata();
 
-  // Initiate first content decoding. Called on the decode thread.
+  // Initiate first content decoding. Called on the state machine thread.
   // The decoder monitor must be held with exactly one lock count.
   nsresult DecodeFirstFrame();
 
   // Wraps the call to DecodeFirstFrame(), signals a DecodeError() on failure.
   void CallDecodeFirstFrame();
 
   // Checks whether we're finished decoding first audio and/or video packets,
   // and switches to DECODING state if so.
--- a/dom/media/MediaQueue.h
+++ b/dom/media/MediaQueue.h
@@ -152,45 +152,45 @@ template <class T> class MediaQueue : pr
     return frames;
   }
 
   void ClearListeners() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     mPopListeners.Clear();
   }
 
-  void AddPopListener(nsIRunnable* aRunnable, MediaTaskQueue* aTaskQueue) {
+  void AddPopListener(nsIRunnable* aRunnable, nsIEventTarget* aTarget) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mPopListeners.AppendElement(Listener(aRunnable, aTaskQueue));
+    mPopListeners.AppendElement(Listener(aRunnable, aTarget));
   }
 
 private:
   mutable ReentrantMonitor mReentrantMonitor;
 
   struct Listener {
-    Listener(nsIRunnable* aRunnable, MediaTaskQueue* aTaskQueue)
+    Listener(nsIRunnable* aRunnable, nsIEventTarget* aTarget)
       : mRunnable(aRunnable)
-      , mTarget(aTaskQueue)
+      , mTarget(aTarget)
     {
     }
     Listener(const Listener& aOther)
       : mRunnable(aOther.mRunnable)
       , mTarget(aOther.mTarget)
     {
     }
     RefPtr<nsIRunnable> mRunnable;
-    RefPtr<MediaTaskQueue> mTarget;
+    RefPtr<nsIEventTarget> mTarget;
   };
 
   nsTArray<Listener> mPopListeners;
 
   void NotifyPopListeners() {
     for (uint32_t i = 0; i < mPopListeners.Length(); i++) {
       Listener& l = mPopListeners[i];
-      l.mTarget->Dispatch(l.mRunnable);
+      l.mTarget->Dispatch(l.mRunnable, NS_DISPATCH_NORMAL);
     }
   }
 
   // True when we've decoded the last frame of data in the
   // bitstream for which we're queueing frame data.
   bool mEndOfStream;
 };