Bug 1118589 - MSE: Run appendBuffer internal's asynchronously. r=cajbir, a=sledru
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 26 Jan 2015 21:33:56 +1100
changeset 243071 afc24a951c4e
parent 243070 c3a59f01db15
child 243072 8b4f59c3ae71
push id4382
push userryanvm@gmail.com
push date2015-01-28 14:58 +0000
treeherdermozilla-beta@f35aa2298df8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir, sledru
bugs1118589
milestone36.0
Bug 1118589 - MSE: Run appendBuffer internal's asynchronously. r=cajbir, a=sledru
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
+#include <time.h>
 
 struct JSContext;
 class JSObject;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
 
@@ -31,24 +32,47 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
 #define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define MSE_DEBUG(...)
 #define MSE_DEBUGV(...)
 #define MSE_API(...)
 #endif
 
-// RangeRemoval must be synchronous if appendBuffer is also synchronous.
-// While waiting for bug 1118589 to land, ensure RangeRemoval is synchronous
-#define APPENDBUFFER_IS_SYNCHRONOUS
-
 namespace mozilla {
 
 namespace dom {
 
+class AppendDataRunnable : public nsRunnable {
+public:
+  AppendDataRunnable(SourceBuffer* aSourceBuffer,
+                     const uint8_t* aData,
+                     uint32_t aLength,
+                     double aTimestampOffset)
+  : mSourceBuffer(aSourceBuffer)
+  , mTimestampOffset(aTimestampOffset)
+  {
+    mData.AppendElements(aData, aLength);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
+
+    mSourceBuffer->AppendData(mData.Elements(),
+                              mData.Length(),
+                              mTimestampOffset);
+
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<SourceBuffer> mSourceBuffer;
+  nsTArray<uint8_t> mData;
+  double mTimestampOffset;
+};
+
 class RangeRemovalRunnable : public nsRunnable {
 public:
   RangeRemovalRunnable(SourceBuffer* aSourceBuffer,
                      double aStart,
                      double aEnd)
   : mSourceBuffer(aSourceBuffer)
   , mStart(aStart)
   , mEnd(aEnd)
@@ -235,46 +259,34 @@ SourceBuffer::Remove(double aStart, doub
   RangeRemoval(aStart, aEnd);
 }
 
 void
 SourceBuffer::RangeRemoval(double aStart, double aEnd)
 {
   StartUpdating();
 
-#if defined(APPENDBUFFER_IS_SYNCHRONOUS)
-  DoRangeRemoval(aStart, aEnd);
-
-  // 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);
-#else
   nsRefPtr<nsIRunnable> task = new RangeRemovalRunnable(this, aStart, aEnd);
   NS_DispatchToMainThread(task);
-#endif
 }
 
 void
 SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
 {
   if (!mUpdating) {
     // abort was called in between.
     return;
   }
   if (mTrackBuffer && !IsInfinite(aStart)) {
     int64_t start = aStart * USECS_PER_S;
     int64_t end = IsInfinite(aEnd) ? INT64_MAX : (int64_t)(aEnd * USECS_PER_S);
     mTrackBuffer->RangeRemoval(start, end);
   }
 
-#if !defined(APPENDBUFFER_IS_SYNCHRONOUS)
   StopUpdating();
-#endif
 }
 
 void
 SourceBuffer::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("SourceBuffer(%p)::Detach", this);
   Abort();
@@ -400,36 +412,51 @@ SourceBuffer::AppendData(const uint8_t* 
   MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
   if (!PrepareAppend(aRv)) {
     return;
   }
   StartUpdating();
 
   MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
              "We don't handle timestampOffset for sequence mode yet");
+  nsRefPtr<nsIRunnable> task =
+    new AppendDataRunnable(this, aData, aLength, mTimestampOffset);
+  NS_DispatchToMainThread(task);
+}
+
+void
+SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, double aTimestampOffset)
+{
+  if (!mUpdating) {
+    // The buffer append algorithm has been interrupted by abort().
+    //
+    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
+    // the first StopUpdating() runnable runs, then a second StopUpdating()
+    // runnable will be scheduled, but still only one (the first) will queue
+    // events.
+    return;
+  }
+
+  MOZ_ASSERT(mMediaSource);
+
   if (aLength) {
-    if (!mTrackBuffer->AppendData(aData, aLength, mTimestampOffset * USECS_PER_S)) {
-      nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethodWithArg<bool>(this, &SourceBuffer::AppendError, true);
-      NS_DispatchToMainThread(event);
+    if (!mTrackBuffer->AppendData(aData, aLength, aTimestampOffset * USECS_PER_S)) {
+      AppendError(true);
       return;
     }
 
     if (mTrackBuffer->HasInitSegment()) {
       mMediaSource->QueueInitializationEvent();
     }
 
     CheckEndTime();
   }
 
-  // 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);
-}
+  StopUpdating();
+ }
 
 void
 SourceBuffer::AppendError(bool aDecoderError)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mUpdating) {
     // The buffer append algorithm has been interrupted by abort().
     return;
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -117,31 +117,34 @@ public:
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~SourceBuffer();
 
   friend class AsyncEventRunner<SourceBuffer>;
+  friend class AppendDataRunnable;
   void DispatchSimpleEvent(const char* aName);
   void QueueAsyncSimpleEvent(const char* aName);
 
   // Update mUpdating and fire the appropriate events.
   void StartUpdating();
   void StopUpdating();
   void AbortUpdating();
 
   // If the media segment contains data beyond the current duration,
   // then run the duration change algorithm with new duration set to the
   // maximum of the current duration and the group end timestamp.
   void CheckEndTime();
 
   // Shared implementation of AppendBuffer overloads.
   void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
+  void AppendData(const uint8_t* aData, uint32_t aLength,
+                  double aTimestampOffset);
 
   // Implement the "Append Error Algorithm".
   // Will call endOfStream() with "decode" error if aDecodeError is true.
   // 3.5.3 Append Error Algorithm
   // http://w3c.github.io/media-source/#sourcebuffer-append-error
   void AppendError(bool aDecoderError);
 
   // Implements the "Prepare Append Algorithm".  Returns true if the append