LCOV - code coverage report
Current view: top level - dom/media/mediasource - MediaSource.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 300 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "MediaSource.h"
       8             : 
       9             : #if MOZ_AV1
      10             : #include "AOMDecoder.h"
      11             : #endif
      12             : #include "AsyncEventRunner.h"
      13             : #include "DecoderTraits.h"
      14             : #include "Benchmark.h"
      15             : #include "DecoderDoctorDiagnostics.h"
      16             : #include "MediaContainerType.h"
      17             : #include "MediaResult.h"
      18             : #include "MediaSourceDemuxer.h"
      19             : #include "MediaSourceUtils.h"
      20             : #include "SourceBuffer.h"
      21             : #include "SourceBufferList.h"
      22             : #include "mozilla/ErrorResult.h"
      23             : #include "mozilla/FloatingPoint.h"
      24             : #include "mozilla/Preferences.h"
      25             : #include "mozilla/dom/BindingDeclarations.h"
      26             : #include "mozilla/dom/HTMLMediaElement.h"
      27             : #include "mozilla/mozalloc.h"
      28             : #include "nsDebug.h"
      29             : #include "nsError.h"
      30             : #include "nsIRunnable.h"
      31             : #include "nsIScriptObjectPrincipal.h"
      32             : #include "nsPIDOMWindow.h"
      33             : #include "nsString.h"
      34             : #include "nsThreadUtils.h"
      35             : #include "mozilla/Logging.h"
      36             : #include "nsServiceManagerUtils.h"
      37             : #include "mozilla/gfx/gfxVars.h"
      38             : #include "mozilla/Sprintf.h"
      39             : 
      40             : #ifdef MOZ_WIDGET_ANDROID
      41             : #include "AndroidBridge.h"
      42             : #endif
      43             : 
      44             : struct JSContext;
      45             : class JSObject;
      46             : 
      47           0 : mozilla::LogModule* GetMediaSourceLog()
      48             : {
      49             :   static mozilla::LazyLogModule sLogModule("MediaSource");
      50           0 :   return sLogModule;
      51             : }
      52             : 
      53           0 : mozilla::LogModule* GetMediaSourceAPILog()
      54             : {
      55             :   static mozilla::LazyLogModule sLogModule("MediaSource");
      56           0 :   return sLogModule;
      57             : }
      58             : 
      59             : #define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      60             : #define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      61             : 
      62             : // Arbitrary limit.
      63             : static const unsigned int MAX_SOURCE_BUFFERS = 16;
      64             : 
      65             : namespace mozilla {
      66             : 
      67             : // Returns true if we should enable MSE webm regardless of preferences.
      68             : // 1. If MP4/H264 isn't supported:
      69             : //   * Windows XP
      70             : //   * Windows Vista and Server 2008 without the optional "Platform Update Supplement"
      71             : //   * N/KN editions (Europe and Korea) of Windows 7/8/8.1/10 without the
      72             : //     optional "Windows Media Feature Pack"
      73             : // 2. If H264 hardware acceleration is not available.
      74             : // 3. The CPU is considered to be fast enough
      75             : static bool
      76           0 : IsWebMForced(DecoderDoctorDiagnostics* aDiagnostics)
      77             : {
      78             :   bool mp4supported =
      79           0 :     DecoderTraits::IsMP4SupportedType(MediaContainerType(MEDIAMIMETYPE("video/mp4")),
      80           0 :                                       aDiagnostics);
      81           0 :   bool hwsupported = gfx::gfxVars::CanUseHardwareVideoDecoding();
      82             : #ifdef MOZ_WIDGET_ANDROID
      83             :   return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast() ||
      84             :          java::HardwareCodecCapabilityUtils::HasHWVP9();
      85             : #else
      86           0 :   return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast();
      87             : #endif
      88             : }
      89             : 
      90             : namespace dom {
      91             : 
      92             : /* static */
      93             : nsresult
      94           0 : MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics)
      95             : {
      96           0 :   if (aType.IsEmpty()) {
      97           0 :     return NS_ERROR_DOM_TYPE_ERR;
      98             :   }
      99             : 
     100           0 :   Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType);
     101           0 :   if (!containerType) {
     102           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     103             :   }
     104             : 
     105           0 :   if (DecoderTraits::CanHandleContainerType(*containerType, aDiagnostics)
     106             :       == CANPLAY_NO) {
     107           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     108             :   }
     109             : 
     110             :   // Now we know that this media type could be played.
     111             :   // MediaSource imposes extra restrictions, and some prefs.
     112           0 :   const MediaMIMEType& mimeType = containerType->Type();
     113           0 :   if (mimeType == MEDIAMIMETYPE("video/mp4") ||
     114           0 :       mimeType == MEDIAMIMETYPE("audio/mp4")) {
     115           0 :     if (!Preferences::GetBool("media.mediasource.mp4.enabled", false)) {
     116           0 :       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     117             :     }
     118           0 :     return NS_OK;
     119             :   }
     120           0 :   if (mimeType == MEDIAMIMETYPE("video/webm")) {
     121           0 :     if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
     122           0 :           containerType->ExtendedType().Codecs().Contains(
     123           0 :             NS_LITERAL_STRING("vp8")) ||
     124             : #ifdef MOZ_AV1
     125             :           // FIXME: Temporary comparison with the full codecs attribute.
     126             :           // See bug 1377015.
     127           0 :           AOMDecoder::IsSupportedCodec(containerType->ExtendedType().Codecs().AsString()) ||
     128             : #endif
     129           0 :           IsWebMForced(aDiagnostics))) {
     130           0 :       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     131             :     }
     132           0 :     return NS_OK;
     133             :   }
     134           0 :   if (mimeType == MEDIAMIMETYPE("audio/webm")) {
     135           0 :     if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
     136           0 :           Preferences::GetBool("media.mediasource.webm.audio.enabled", true))) {
     137           0 :       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     138             :     }
     139           0 :     return NS_OK;
     140             :   }
     141             : 
     142           0 :   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     143             : }
     144             : 
     145             : /* static */ already_AddRefed<MediaSource>
     146           0 : MediaSource::Constructor(const GlobalObject& aGlobal,
     147             :                          ErrorResult& aRv)
     148             : {
     149           0 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
     150           0 :   if (!window) {
     151           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
     152           0 :     return nullptr;
     153             :   }
     154             : 
     155           0 :   RefPtr<MediaSource> mediaSource = new MediaSource(window);
     156           0 :   return mediaSource.forget();
     157             : }
     158             : 
     159           0 : MediaSource::~MediaSource()
     160             : {
     161           0 :   MOZ_ASSERT(NS_IsMainThread());
     162           0 :   MSE_API("");
     163           0 :   if (mDecoder) {
     164           0 :     mDecoder->DetachMediaSource();
     165             :   }
     166           0 : }
     167             : 
     168             : SourceBufferList*
     169           0 : MediaSource::SourceBuffers()
     170             : {
     171           0 :   MOZ_ASSERT(NS_IsMainThread());
     172           0 :   MOZ_ASSERT_IF(mReadyState == MediaSourceReadyState::Closed, mSourceBuffers->IsEmpty());
     173           0 :   return mSourceBuffers;
     174             : }
     175             : 
     176             : SourceBufferList*
     177           0 : MediaSource::ActiveSourceBuffers()
     178             : {
     179           0 :   MOZ_ASSERT(NS_IsMainThread());
     180           0 :   MOZ_ASSERT_IF(mReadyState == MediaSourceReadyState::Closed, mActiveSourceBuffers->IsEmpty());
     181           0 :   return mActiveSourceBuffers;
     182             : }
     183             : 
     184             : MediaSourceReadyState
     185           0 : MediaSource::ReadyState()
     186             : {
     187           0 :   MOZ_ASSERT(NS_IsMainThread());
     188           0 :   return mReadyState;
     189             : }
     190             : 
     191             : double
     192           0 : MediaSource::Duration()
     193             : {
     194           0 :   MOZ_ASSERT(NS_IsMainThread());
     195           0 :   if (mReadyState == MediaSourceReadyState::Closed) {
     196           0 :     return UnspecifiedNaN<double>();
     197             :   }
     198           0 :   MOZ_ASSERT(mDecoder);
     199           0 :   return mDecoder->GetDuration();
     200             : }
     201             : 
     202             : void
     203           0 : MediaSource::SetDuration(double aDuration, ErrorResult& aRv)
     204             : {
     205           0 :   MOZ_ASSERT(NS_IsMainThread());
     206           0 :   MSE_API("SetDuration(aDuration=%f, ErrorResult)", aDuration);
     207           0 :   if (aDuration < 0 || IsNaN(aDuration)) {
     208           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     209           0 :     return;
     210             :   }
     211           0 :   if (mReadyState != MediaSourceReadyState::Open ||
     212           0 :       mSourceBuffers->AnyUpdating()) {
     213           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     214           0 :     return;
     215             :   }
     216           0 :   DurationChange(aDuration, aRv);
     217             : }
     218             : 
     219             : void
     220           0 : MediaSource::SetDuration(double aDuration)
     221             : {
     222           0 :   MOZ_ASSERT(NS_IsMainThread());
     223           0 :   MSE_API("SetDuration(aDuration=%f)", aDuration);
     224           0 :   mDecoder->SetMediaSourceDuration(aDuration);
     225           0 : }
     226             : 
     227             : already_AddRefed<SourceBuffer>
     228           0 : MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
     229             : {
     230           0 :   MOZ_ASSERT(NS_IsMainThread());
     231           0 :   DecoderDoctorDiagnostics diagnostics;
     232           0 :   nsresult rv = IsTypeSupported(aType, &diagnostics);
     233           0 :   diagnostics.StoreFormatDiagnostics(GetOwner()
     234           0 :                                      ? GetOwner()->GetExtantDoc()
     235             :                                      : nullptr,
     236           0 :                                      aType, NS_SUCCEEDED(rv), __func__);
     237           0 :   MSE_API("AddSourceBuffer(aType=%s)%s",
     238             :           NS_ConvertUTF16toUTF8(aType).get(),
     239             :           rv == NS_OK ? "" : " [not supported]");
     240           0 :   if (NS_FAILED(rv)) {
     241           0 :     aRv.Throw(rv);
     242           0 :     return nullptr;
     243             :   }
     244           0 :   if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) {
     245           0 :     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     246           0 :     return nullptr;
     247             :   }
     248           0 :   if (mReadyState != MediaSourceReadyState::Open) {
     249           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     250           0 :     return nullptr;
     251             :   }
     252           0 :   Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType);
     253           0 :   if (!containerType) {
     254           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     255           0 :     return nullptr;
     256             :   }
     257           0 :   RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, *containerType);
     258           0 :   if (!sourceBuffer) {
     259           0 :     aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here
     260           0 :     return nullptr;
     261             :   }
     262           0 :   mSourceBuffers->Append(sourceBuffer);
     263           0 :   MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
     264           0 :   return sourceBuffer.forget();
     265             : }
     266             : 
     267             : RefPtr<MediaSource::ActiveCompletionPromise>
     268           0 : MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
     269             : {
     270           0 :   MOZ_ASSERT(NS_IsMainThread());
     271           0 :   mActiveSourceBuffers->ClearSimple();
     272           0 :   bool initMissing = false;
     273           0 :   bool found = false;
     274           0 :   for (uint32_t i = 0; i < mSourceBuffers->Length(); i++) {
     275           0 :     SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
     276           0 :     MOZ_ALWAYS_TRUE(found);
     277           0 :     if (sourceBuffer == aSourceBuffer) {
     278           0 :       mActiveSourceBuffers->Append(aSourceBuffer);
     279           0 :     } else if (sourceBuffer->IsActive()) {
     280           0 :       mActiveSourceBuffers->AppendSimple(sourceBuffer);
     281             :     } else {
     282             :       // Some source buffers haven't yet received an init segment.
     283             :       // There's nothing more we can do at this stage.
     284           0 :       initMissing = true;
     285             :     }
     286             :   }
     287           0 :   if (initMissing || !mDecoder) {
     288           0 :     return ActiveCompletionPromise::CreateAndResolve(true, __func__);
     289             :   }
     290             : 
     291           0 :   mDecoder->NotifyInitDataArrived();
     292             : 
     293             :   // Add our promise to the queue.
     294             :   // It will be resolved once the HTMLMediaElement modifies its readyState.
     295           0 :   MozPromiseHolder<ActiveCompletionPromise> holder;
     296           0 :   RefPtr<ActiveCompletionPromise> promise = holder.Ensure(__func__);
     297           0 :   mCompletionPromises.AppendElement(Move(holder));
     298           0 :   return promise;
     299             : }
     300             : 
     301             : void
     302           0 : MediaSource::CompletePendingTransactions()
     303             : {
     304           0 :   MOZ_ASSERT(NS_IsMainThread());
     305           0 :   MSE_DEBUG("Resolving %u promises", unsigned(mCompletionPromises.Length()));
     306           0 :   for (auto& promise : mCompletionPromises) {
     307           0 :     promise.Resolve(true, __func__);
     308             :   }
     309           0 :   mCompletionPromises.Clear();
     310           0 : }
     311             : 
     312             : void
     313           0 : MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
     314             : {
     315           0 :   MOZ_ASSERT(NS_IsMainThread());
     316           0 :   SourceBuffer* sourceBuffer = &aSourceBuffer;
     317           0 :   MSE_API("RemoveSourceBuffer(aSourceBuffer=%p)", sourceBuffer);
     318           0 :   if (!mSourceBuffers->Contains(sourceBuffer)) {
     319           0 :     aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     320           0 :     return;
     321             :   }
     322             : 
     323           0 :   sourceBuffer->AbortBufferAppend();
     324             :   // TODO:
     325             :   // abort stream append loop (if running)
     326             : 
     327             :   // TODO:
     328             :   // For all sourceBuffer audioTracks, videoTracks, textTracks:
     329             :   //     set sourceBuffer to null
     330             :   //     remove sourceBuffer video, audio, text Tracks from MediaElement tracks
     331             :   //     remove sourceBuffer video, audio, text Tracks and fire "removetrack" at affected lists
     332             :   //     fire "removetrack" at modified MediaElement track lists
     333             :   // If removed enabled/selected, fire "change" at affected MediaElement list.
     334           0 :   if (mActiveSourceBuffers->Contains(sourceBuffer)) {
     335           0 :     mActiveSourceBuffers->Remove(sourceBuffer);
     336             :   }
     337           0 :   mSourceBuffers->Remove(sourceBuffer);
     338             :   // TODO: Free all resources associated with sourceBuffer
     339             : }
     340             : 
     341             : void
     342           0 : MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv)
     343             : {
     344           0 :   MOZ_ASSERT(NS_IsMainThread());
     345           0 :   MSE_API("EndOfStream(aError=%d)",
     346             :           aError.WasPassed() ? uint32_t(aError.Value()) : 0);
     347           0 :   if (mReadyState != MediaSourceReadyState::Open ||
     348           0 :       mSourceBuffers->AnyUpdating()) {
     349           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     350           0 :     return;
     351             :   }
     352             : 
     353           0 :   SetReadyState(MediaSourceReadyState::Ended);
     354           0 :   mSourceBuffers->Ended();
     355           0 :   if (!aError.WasPassed()) {
     356           0 :     DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
     357             :     // Notify reader that all data is now available.
     358           0 :     mDecoder->Ended(true);
     359           0 :     return;
     360             :   }
     361           0 :   switch (aError.Value()) {
     362             :   case MediaSourceEndOfStreamError::Network:
     363           0 :     mDecoder->NetworkError();
     364           0 :     break;
     365             :   case MediaSourceEndOfStreamError::Decode:
     366           0 :     mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
     367           0 :     break;
     368             :   default:
     369           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     370             :   }
     371             : }
     372             : 
     373             : void
     374           0 : MediaSource::EndOfStream(const MediaResult& aError)
     375             : {
     376           0 :   MOZ_ASSERT(NS_IsMainThread());
     377           0 :   MSE_API("EndOfStream(aError=%" PRId32")", static_cast<uint32_t>(aError.Code()));
     378             : 
     379           0 :   SetReadyState(MediaSourceReadyState::Ended);
     380           0 :   mSourceBuffers->Ended();
     381           0 :   mDecoder->DecodeError(aError);
     382           0 : }
     383             : 
     384             : /* static */ bool
     385           0 : MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType)
     386             : {
     387           0 :   MOZ_ASSERT(NS_IsMainThread());
     388           0 :   DecoderDoctorDiagnostics diagnostics;
     389           0 :   nsresult rv = IsTypeSupported(aType, &diagnostics);
     390           0 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner.GetAsSupports());
     391           0 :   diagnostics.StoreFormatDiagnostics(window ? window->GetExtantDoc() : nullptr,
     392           0 :                                      aType, NS_SUCCEEDED(rv), __func__);
     393             : #define this nullptr
     394           0 :   MSE_API("IsTypeSupported(aType=%s)%s ",
     395             :           NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "OK" : "[not supported]");
     396             : #undef this // don't ever remove this line !
     397           0 :   return NS_SUCCEEDED(rv);
     398             : }
     399             : 
     400             : /* static */ bool
     401           0 : MediaSource::Enabled(JSContext* cx, JSObject* aGlobal)
     402             : {
     403           0 :   return Preferences::GetBool("media.mediasource.enabled");
     404             : }
     405             : 
     406             : void
     407           0 : MediaSource::SetLiveSeekableRange(double aStart, double aEnd, ErrorResult& aRv)
     408             : {
     409           0 :   MOZ_ASSERT(NS_IsMainThread());
     410             : 
     411             :   // 1. If the readyState attribute is not "open" then throw an InvalidStateError
     412             :   // exception and abort these steps.
     413           0 :   if (mReadyState != MediaSourceReadyState::Open) {
     414           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     415           0 :     return;
     416             :   }
     417             : 
     418             :   // 2. If start is negative or greater than end, then throw a TypeError
     419             :   // exception and abort these steps.
     420           0 :   if (aStart < 0 || aStart > aEnd) {
     421           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     422           0 :     return;
     423             :   }
     424             : 
     425             :   // 3. Set live seekable range to be a new normalized TimeRanges object
     426             :   // containing a single range whose start position is start and end position is
     427             :   // end.
     428             :   mLiveSeekableRange =
     429           0 :     Some(media::TimeInterval(media::TimeUnit::FromSeconds(aStart),
     430           0 :                              media::TimeUnit::FromSeconds(aEnd)));
     431             : }
     432             : 
     433             : void
     434           0 : MediaSource::ClearLiveSeekableRange(ErrorResult& aRv)
     435             : {
     436           0 :   MOZ_ASSERT(NS_IsMainThread());
     437             : 
     438             :   // 1. If the readyState attribute is not "open" then throw an InvalidStateError
     439             :   // exception and abort these steps.
     440           0 :   if (mReadyState != MediaSourceReadyState::Open) {
     441           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     442           0 :     return;
     443             :   }
     444             : 
     445             :   // 2. If live seekable range contains a range, then set live seekable range to
     446             :   // be a new empty TimeRanges object.
     447           0 :   mLiveSeekableRange.reset();
     448             : }
     449             : 
     450             : bool
     451           0 : MediaSource::Attach(MediaSourceDecoder* aDecoder)
     452             : {
     453           0 :   MOZ_ASSERT(NS_IsMainThread());
     454           0 :   MSE_DEBUG("Attach(aDecoder=%p) owner=%p", aDecoder, aDecoder->GetOwner());
     455           0 :   MOZ_ASSERT(aDecoder);
     456           0 :   MOZ_ASSERT(aDecoder->GetOwner());
     457           0 :   if (mReadyState != MediaSourceReadyState::Closed) {
     458           0 :     return false;
     459             :   }
     460           0 :   MOZ_ASSERT(!mMediaElement);
     461           0 :   mMediaElement = aDecoder->GetOwner()->GetMediaElement();
     462           0 :   MOZ_ASSERT(!mDecoder);
     463           0 :   mDecoder = aDecoder;
     464           0 :   mDecoder->AttachMediaSource(this);
     465           0 :   SetReadyState(MediaSourceReadyState::Open);
     466           0 :   return true;
     467             : }
     468             : 
     469             : void
     470           0 : MediaSource::Detach()
     471             : {
     472           0 :   MOZ_ASSERT(NS_IsMainThread());
     473           0 :   MOZ_RELEASE_ASSERT(mCompletionPromises.IsEmpty());
     474           0 :   MSE_DEBUG("mDecoder=%p owner=%p",
     475             :             mDecoder.get(), mDecoder ? mDecoder->GetOwner() : nullptr);
     476           0 :   if (!mDecoder) {
     477           0 :     MOZ_ASSERT(mReadyState == MediaSourceReadyState::Closed);
     478           0 :     MOZ_ASSERT(mActiveSourceBuffers->IsEmpty() && mSourceBuffers->IsEmpty());
     479           0 :     return;
     480             :   }
     481           0 :   mMediaElement = nullptr;
     482           0 :   SetReadyState(MediaSourceReadyState::Closed);
     483           0 :   if (mActiveSourceBuffers) {
     484           0 :     mActiveSourceBuffers->Clear();
     485             :   }
     486           0 :   if (mSourceBuffers) {
     487           0 :     mSourceBuffers->Clear();
     488             :   }
     489           0 :   mDecoder->DetachMediaSource();
     490           0 :   mDecoder = nullptr;
     491             : }
     492             : 
     493           0 : MediaSource::MediaSource(nsPIDOMWindowInner* aWindow)
     494             :   : DOMEventTargetHelper(aWindow)
     495             :   , mDecoder(nullptr)
     496             :   , mPrincipal(nullptr)
     497           0 :   , mAbstractMainThread(GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other))
     498           0 :   , mReadyState(MediaSourceReadyState::Closed)
     499             : {
     500           0 :   MOZ_ASSERT(NS_IsMainThread());
     501           0 :   mSourceBuffers = new SourceBufferList(this);
     502           0 :   mActiveSourceBuffers = new SourceBufferList(this);
     503             : 
     504           0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
     505           0 :   if (sop) {
     506           0 :     mPrincipal = sop->GetPrincipal();
     507             :   }
     508             : 
     509           0 :   MSE_API("MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p",
     510             :           aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get());
     511           0 : }
     512             : 
     513             : void
     514           0 : MediaSource::SetReadyState(MediaSourceReadyState aState)
     515             : {
     516           0 :   MOZ_ASSERT(NS_IsMainThread());
     517           0 :   MOZ_ASSERT(aState != mReadyState);
     518           0 :   MSE_DEBUG("SetReadyState(aState=%" PRIu32 ") mReadyState=%" PRIu32,
     519             :             static_cast<uint32_t>(aState), static_cast<uint32_t>(mReadyState));
     520             : 
     521           0 :   MediaSourceReadyState oldState = mReadyState;
     522           0 :   mReadyState = aState;
     523             : 
     524           0 :   if (mReadyState == MediaSourceReadyState::Open &&
     525           0 :       (oldState == MediaSourceReadyState::Closed ||
     526             :        oldState == MediaSourceReadyState::Ended)) {
     527           0 :     QueueAsyncSimpleEvent("sourceopen");
     528           0 :     if (oldState == MediaSourceReadyState::Ended) {
     529             :       // Notify reader that more data may come.
     530           0 :       mDecoder->Ended(false);
     531             :     }
     532           0 :     return;
     533             :   }
     534             : 
     535           0 :   if (mReadyState == MediaSourceReadyState::Ended &&
     536             :       oldState == MediaSourceReadyState::Open) {
     537           0 :     QueueAsyncSimpleEvent("sourceended");
     538           0 :     return;
     539             :   }
     540             : 
     541           0 :   if (mReadyState == MediaSourceReadyState::Closed &&
     542           0 :       (oldState == MediaSourceReadyState::Open ||
     543             :        oldState == MediaSourceReadyState::Ended)) {
     544           0 :     QueueAsyncSimpleEvent("sourceclose");
     545           0 :     return;
     546             :   }
     547             : 
     548           0 :   NS_WARNING("Invalid MediaSource readyState transition");
     549             : }
     550             : 
     551             : void
     552           0 : MediaSource::DispatchSimpleEvent(const char* aName)
     553             : {
     554           0 :   MOZ_ASSERT(NS_IsMainThread());
     555           0 :   MSE_API("Dispatch event '%s'", aName);
     556           0 :   DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName));
     557           0 : }
     558             : 
     559             : void
     560           0 : MediaSource::QueueAsyncSimpleEvent(const char* aName)
     561             : {
     562           0 :   MSE_DEBUG("Queuing event '%s'", aName);
     563           0 :   nsCOMPtr<nsIRunnable> event = new AsyncEventRunner<MediaSource>(this, aName);
     564           0 :   mAbstractMainThread->Dispatch(event.forget());
     565           0 : }
     566             : 
     567             : void
     568           0 : MediaSource::DurationChange(double aNewDuration, ErrorResult& aRv)
     569             : {
     570           0 :   MOZ_ASSERT(NS_IsMainThread());
     571           0 :   MSE_DEBUG("DurationChange(aNewDuration=%f)", aNewDuration);
     572             : 
     573             :   // 1. If the current value of duration is equal to new duration, then return.
     574           0 :   if (mDecoder->GetDuration() == aNewDuration) {
     575           0 :     return;
     576             :   }
     577             : 
     578             :   // 2. If new duration is less than the highest starting presentation timestamp
     579             :   // of any buffered coded frames for all SourceBuffer objects in sourceBuffers,
     580             :   // then throw an InvalidStateError exception and abort these steps.
     581           0 :   if (aNewDuration < mSourceBuffers->HighestStartTime()) {
     582           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     583           0 :     return;
     584             :   }
     585             : 
     586             :   // 3. Let highest end time be the largest track buffer ranges end time across
     587             :   // all the track buffers across all SourceBuffer objects in sourceBuffers.
     588           0 :   double highestEndTime = mSourceBuffers->HighestEndTime();
     589             :   // 4. If new duration is less than highest end time, then
     590             :   //    4.1 Update new duration to equal highest end time.
     591           0 :   aNewDuration =
     592           0 :     std::max(aNewDuration, highestEndTime);
     593             : 
     594             :   // 5. Update the media duration to new duration and run the HTMLMediaElement
     595             :   // duration change algorithm.
     596           0 :   mDecoder->SetMediaSourceDuration(aNewDuration);
     597             : }
     598             : 
     599             : void
     600           0 : MediaSource::GetMozDebugReaderData(nsAString& aString)
     601             : {
     602           0 :   nsAutoCString result;
     603           0 :   mDecoder->GetMozDebugReaderData(result);
     604           0 :   aString = NS_ConvertUTF8toUTF16(result);
     605           0 : }
     606             : 
     607             : nsPIDOMWindowInner*
     608           0 : MediaSource::GetParentObject() const
     609             : {
     610           0 :   return GetOwner();
     611             : }
     612             : 
     613             : JSObject*
     614           0 : MediaSource::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     615             : {
     616           0 :   return MediaSourceBinding::Wrap(aCx, this, aGivenProto);
     617             : }
     618             : 
     619           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaSource, DOMEventTargetHelper,
     620             :                                    mMediaElement,
     621             :                                    mSourceBuffers, mActiveSourceBuffers)
     622             : 
     623           0 : NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
     624           0 : NS_IMPL_RELEASE_INHERITED(MediaSource, DOMEventTargetHelper)
     625             : 
     626           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaSource)
     627           0 :   NS_INTERFACE_MAP_ENTRY(mozilla::dom::MediaSource)
     628           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
     629             : 
     630             : #undef MSE_DEBUG
     631             : #undef MSE_API
     632             : 
     633             : } // namespace dom
     634             : 
     635             : } // namespace mozilla

Generated by: LCOV version 1.13