Bug 1064570 - Run end of SourceBuffer update algorithms asynchronously per spec. r=cajbir
authorMatthew Gregan <kinetik@flim.org>
Tue, 09 Sep 2014 10:29:41 +1200
changeset 204236 82ecf7b5594fc923023c6803263b1dc024bd4b2f
parent 204235 bb9d094bfd938f285f6ca9eb7d1bcb918025a7a4
child 204237 8988fac69d4b3198893e75ca204932b7a138b7c0
push id27452
push usercbook@mozilla.com
push dateTue, 09 Sep 2014 13:57:12 +0000
treeherdermozilla-central@2eaf94a4f837 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1064570
milestone35.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 1064570 - Run end of SourceBuffer update algorithms asynchronously per spec. r=cajbir
content/media/mediasource/SourceBuffer.cpp
content/media/mediasource/test/test_BufferedSeek.html
content/media/mediasource/test/test_FrameSelection.html
content/media/mediasource/test/test_MediaSource.html
content/media/mediasource/test/test_SplitAppend.html
content/media/mediasource/test/test_SplitAppendDelay.html
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -435,18 +435,23 @@ SourceBuffer::Remove(double aStart, doub
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
   if (mUpdating || mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   StartUpdating();
-  /// TODO: Run coded frame removal algorithm asynchronously (would call StopUpdating()).
-  StopUpdating();
+  /// TODO: Run coded frame removal algorithm.
+
+  // Run the final step of the coded frame removal algorithm asynchronously
+  // to ensure the SourceBuffer's updating flag transition behaves as
+  // required by the spec.
+  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
+  NS_DispatchToMainThread(event);
 }
 
 void
 SourceBuffer::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("SourceBuffer(%p)::Detach", this);
   if (mTrackBuffer) {
@@ -556,17 +561,17 @@ SourceBuffer::AppendData(const uint8_t* 
     return;
   }
   if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
     mMediaSource->SetReadyState(MediaSourceReadyState::Open);
   }
   // TODO: Run coded frame eviction algorithm.
   // TODO: Test buffer full flag.
   StartUpdating();
-  // TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
+  // TODO: Run more of the buffer append algorithm asynchronously.
   if (mParser->IsInitSegmentPresent(aData, aLength)) {
     MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
     mMediaSource->QueueInitializationEvent();
     mTrackBuffer->DiscardDecoder();
     if (!mTrackBuffer->NewDecoder()) {
       aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
       return;
     }
@@ -627,17 +632,22 @@ SourceBuffer::AppendData(const uint8_t* 
   if (evicted) {
     MSE_DEBUG("SourceBuffer(%p)::AppendData Evict; current buffered start=%f",
               this, GetBufferedStart());
 
     // We notify that we've evicted from the time range 0 through to
     // the current start point.
     mMediaSource->NotifyEvicted(0.0, GetBufferedStart());
   }
-  StopUpdating();
+
+  // Run the final step of the buffer append algorithm asynchronously to
+  // ensure the SourceBuffer's updating flag transition behaves as required
+  // by the spec.
+  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
+  NS_DispatchToMainThread(event);
 
   // Schedule the state machine thread to ensure playback starts
   // if required when data is appended.
   mMediaSource->GetDecoder()->ScheduleStateMachineThread();
 }
 
 double
 SourceBuffer::GetBufferedStart()
--- a/content/media/mediasource/test/test_BufferedSeek.html
+++ b/content/media/mediasource/test/test_BufferedSeek.html
@@ -20,17 +20,19 @@ runWithMSE(function () {
   v.src = URL.createObjectURL(ms);
   document.body.appendChild(v);
 
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer));
-      ms.endOfStream();
+      sb.addEventListener("updateend", function () {
+        ms.endOfStream()
+      });
     });
 
     var target = 2;
 
     v.addEventListener("loadedmetadata", function () {
       if (v.currentTime != target &&
           v.buffered.length &&
           target >= v.buffered.start(0) &&
--- a/content/media/mediasource/test/test_FrameSelection.html
+++ b/content/media/mediasource/test/test_FrameSelection.html
@@ -36,19 +36,26 @@ runWithMSE(function () {
     v.addEventListener("loadedmetadata", function () {
       is(v.currentTime, 0, "currentTime has incorrect initial value");
       is(v.videoWidth, 320, "videoWidth has incorrect initial value");
       is(v.videoHeight, 240, "videoHeight has incorrect initial value");
 
       fetchWithXHR("seek_lowres.webm", function (arrayBuffer) {
         // Append initialization segment.
         sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 438));
-        // Append media segment covering range [2, 4].
-        sb.appendBuffer(new Uint8Array(arrayBuffer, 51003));
-        ms.endOfStream();
+        var first = true;
+        sb.addEventListener("updateend", function () {
+          if (first) {
+            // Append media segment covering range [2, 4].
+            sb.appendBuffer(new Uint8Array(arrayBuffer, 51003));
+            first = false;
+          } else {
+            ms.endOfStream();
+          }
+        });
         target = targets.shift();
         v.currentTime = target.currentTime;
       });
     });
 
     v.addEventListener("seeked", function () {
       is(v.currentTime, target.currentTime, "Video currentTime not at target");
 
--- a/content/media/mediasource/test/test_MediaSource.html
+++ b/content/media/mediasource/test/test_MediaSource.html
@@ -47,17 +47,26 @@ runWithMSE(function () {
     var sb = ms.addSourceBuffer("video/webm");
     ok(sb, "Create a SourceBuffer");
     is(ms.sourceBuffers.length, 1, "MediaSource.sourceBuffers is expected length");
     is(ms.sourceBuffers[0], sb, "SourceBuffer in list matches our SourceBuffer");
     is(ms.activeSourceBuffers[0], sb, "SourceBuffer in active list matches our SourceBuffer");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer));
+      is(sb.updating, true, "SourceBuffer.updating is expected value after appendBuffer");
+    });
+
+    sb.addEventListener("update", function () {
+      is(sb.updating, false, "SourceBuffer.updating is expected value in update event");
       ms.endOfStream();
+    });
+
+    sb.addEventListener("updateend", function () {
+      is(sb.updating, false, "SourceBuffer.updating is expected value in updateend event");
       v.play();
     });
   });
 
   ms.addEventListener("sourceended", function () {
     ok(true, "Receive a sourceended event");
     is(ms.readyState, "ended", "MediaSource must be in ended state after sourceended");
   });
--- a/content/media/mediasource/test/test_SplitAppend.html
+++ b/content/media/mediasource/test/test_SplitAppend.html
@@ -20,18 +20,25 @@ runWithMSE(function () {
   v.src = URL.createObjectURL(ms);
   document.body.appendChild(v);
 
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
-      sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
-      ms.endOfStream();
+      var first = true;
+      sb.addEventListener("updateend", function () {
+        if (first) {
+          sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
+          first = false;
+        } else {
+          ms.endOfStream();
+        }
+      });
       v.play();
     });
   });
 
   v.addEventListener("ended", function () {
     is(v.duration, 4, "Video has correct duration");
     is(v.currentTime, 4, "Video has played to end");
     v.parentNode.removeChild(v);
--- a/content/media/mediasource/test/test_SplitAppendDelay.html
+++ b/content/media/mediasource/test/test_SplitAppendDelay.html
@@ -20,20 +20,27 @@ runWithMSE(function () {
   v.src = URL.createObjectURL(ms);
   document.body.appendChild(v);
 
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 318));
-      window.setTimeout(function () {
-        sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
-        ms.endOfStream();
-      }, 1000);
+      var first = true;
+      sb.addEventListener("updateend", function () {
+        if (first) {
+          window.setTimeout(function () {
+            sb.appendBuffer(new Uint8Array(arrayBuffer, 318));
+            first = false;
+          }, 1000);
+        } else {
+          ms.endOfStream();
+        }
+      });
       v.play();
     });
   });
 
   v.addEventListener("ended", function () {
     is(v.duration, 4, "Video has correct duration");
     is(v.currentTime, 4, "Video has played to end");
     v.parentNode.removeChild(v);