Bug 1133625: Return an error when attempting to append too much data. r=cajbir a=lmandel
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 20 Feb 2015 14:19:13 +1300
changeset 249951 050e1d7b5246886dd76187172f083a8d06e17459
parent 249950 cbf454c3c189e9930713c5c0129657c72b706143
child 249952 77ec05774a77df5ecbd7a70a7a8bf354f626f2e9
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir, lmandel
bugs1133625
milestone37.0a2
Bug 1133625: Return an error when attempting to append too much data. r=cajbir a=lmandel Implement part 6 of Prepare Append Algorithm: http://w3c.github.io/media-source/#sourcebuffer-prepare-append "If the buffer full flag equals true, then throw a QuotaExceededError exception and abort these step."
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/TrackBuffer.cpp
dom/media/mediasource/TrackBuffer.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -553,16 +553,25 @@ SourceBuffer::PrepareAppend(const uint8_
     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, newBufferStartTime);
   }
 
+  // See if we have enough free space to append our new data.
+  // As we can only evict once we have playable data, we must give a chance
+  // to the DASH player to provide a complete media segment.
+  if ((mTrackBuffer->GetSize() > mEvictionThreshold - aLength) &&
+      !mTrackBuffer->HasOnlyIncompleteMedia()) {
+    aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
+    return nullptr;
+  }
+
   nsRefPtr<LargeDataBuffer> data = new LargeDataBuffer();
   if (!data->AppendElements(aData, aLength)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
   // TODO: Test buffer full flag.
   return data.forget();
 }
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -305,20 +305,17 @@ TrackBuffer::EvictData(double aPlaybackT
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
   if (!mCurrentDecoder) {
     return false;
   }
 
-  int64_t totalSize = 0;
-  for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
-    totalSize += mDecoders[i]->GetResource()->GetSize();
-  }
+  int64_t totalSize = GetSize();
 
   int64_t toEvict = totalSize - aThreshold;
   if (toEvict <= 0 || mInitializedDecoders.IsEmpty()) {
     return false;
   }
 
   // Get a list of initialized decoders.
   nsTArray<SourceBufferDecoder*> decoders;
@@ -448,16 +445,37 @@ TrackBuffer::RemoveEmptyDecoders(nsTArra
         buffered->GetStartTime() < 0.0 ||
         buffered->GetEndTime() < 0.0) {
       MSE_DEBUG("remove empty decoders=%d", i);
       RemoveDecoder(aDecoders[i]);
     }
   }
 }
 
+int64_t
+TrackBuffer::GetSize()
+{
+  int64_t totalSize = 0;
+  for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
+    totalSize += mInitializedDecoders[i]->GetResource()->GetSize();
+  }
+  return totalSize;
+}
+
+bool
+TrackBuffer::HasOnlyIncompleteMedia()
+{
+  if (!mCurrentDecoder) {
+    return false;
+  }
+  nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
+  mCurrentDecoder->GetBuffered(buffered);
+  return mCurrentDecoder->GetResource()->GetSize() && !buffered->Length();
+}
+
 void
 TrackBuffer::EvictBefore(double aTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
     int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime);
     if (endOffset > 0) {
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -99,16 +99,23 @@ public:
   // Implementation is only partial, we can only trim a buffer.
   // Returns true if data was evicted.
   // Times are in microseconds.
   bool RangeRemoval(int64_t aStart, int64_t aEnd);
 
   // Abort any pending appendBuffer by rejecting any pending promises.
   void AbortAppendData();
 
+  // Return the size used by all decoders managed by this TrackBuffer.
+  int64_t GetSize();
+
+  // Return true if we have a partial media segment being appended that is
+  // currently not playable.
+  bool HasOnlyIncompleteMedia();
+
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif