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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       4             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "DOMMediaStream.h"
       7             : 
       8             : #include "AudioCaptureStream.h"
       9             : #include "AudioChannelAgent.h"
      10             : #include "AudioStreamTrack.h"
      11             : #include "Layers.h"
      12             : #include "MediaStreamGraph.h"
      13             : #include "MediaStreamListener.h"
      14             : #include "VideoStreamTrack.h"
      15             : #include "mozilla/dom/AudioNode.h"
      16             : #include "mozilla/dom/AudioTrack.h"
      17             : #include "mozilla/dom/AudioTrackList.h"
      18             : #include "mozilla/dom/DocGroup.h"
      19             : #include "mozilla/dom/HTMLCanvasElement.h"
      20             : #include "mozilla/dom/LocalMediaStreamBinding.h"
      21             : #include "mozilla/dom/MediaStreamBinding.h"
      22             : #include "mozilla/dom/MediaStreamTrackEvent.h"
      23             : #include "mozilla/dom/VideoTrack.h"
      24             : #include "mozilla/dom/VideoTrackList.h"
      25             : #include "mozilla/media/MediaUtils.h"
      26             : #include "nsContentUtils.h"
      27             : #include "nsIScriptError.h"
      28             : #include "nsIUUIDGenerator.h"
      29             : #include "nsPIDOMWindow.h"
      30             : #include "nsRFPService.h"
      31             : #include "nsServiceManagerUtils.h"
      32             : 
      33             : // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
      34             : // GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing
      35             : // currentTime getter.
      36             : #ifdef GetCurrentTime
      37             : #undef GetCurrentTime
      38             : #endif
      39             : 
      40             : #ifdef LOG
      41             : #undef LOG
      42             : #endif
      43             : 
      44             : // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
      45             : // GetTickCount() and conflicts with MediaStream::GetCurrentTime.
      46             : #ifdef GetCurrentTime
      47             : #undef GetCurrentTime
      48             : #endif
      49             : 
      50             : using namespace mozilla;
      51             : using namespace mozilla::dom;
      52             : using namespace mozilla::layers;
      53             : using namespace mozilla::media;
      54             : 
      55             : static LazyLogModule gMediaStreamLog("MediaStream");
      56             : #define LOG(type, msg) MOZ_LOG(gMediaStreamLog, type, msg)
      57             : 
      58             : const TrackID TRACK_VIDEO_PRIMARY = 1;
      59             : 
      60             : static bool
      61           0 : ContainsLiveTracks(nsTArray<RefPtr<DOMMediaStream::TrackPort>>& aTracks)
      62             : {
      63           0 :   for (auto& port : aTracks) {
      64           0 :     if (port->GetTrack()->ReadyState() == MediaStreamTrackState::Live) {
      65           0 :       return true;
      66             :     }
      67             :   }
      68             : 
      69           0 :   return false;
      70             : }
      71             : 
      72           0 : DOMMediaStream::TrackPort::TrackPort(MediaInputPort* aInputPort,
      73             :                                      MediaStreamTrack* aTrack,
      74           0 :                                      const InputPortOwnership aOwnership)
      75             :   : mInputPort(aInputPort)
      76             :   , mTrack(aTrack)
      77           0 :   , mOwnership(aOwnership)
      78             : {
      79           0 :   MOZ_ASSERT(mInputPort);
      80           0 :   MOZ_ASSERT(mTrack);
      81             : 
      82           0 :   MOZ_COUNT_CTOR(TrackPort);
      83           0 : }
      84             : 
      85           0 : DOMMediaStream::TrackPort::~TrackPort()
      86             : {
      87           0 :   MOZ_COUNT_DTOR(TrackPort);
      88             : 
      89           0 :   if (mOwnership == InputPortOwnership::OWNED) {
      90           0 :     DestroyInputPort();
      91             :   }
      92           0 : }
      93             : 
      94             : void
      95           0 : DOMMediaStream::TrackPort::DestroyInputPort()
      96             : {
      97           0 :   if (mInputPort) {
      98           0 :     mInputPort->Destroy();
      99           0 :     mInputPort = nullptr;
     100             :   }
     101           0 : }
     102             : 
     103             : MediaStream*
     104           0 : DOMMediaStream::TrackPort::GetSource() const
     105             : {
     106           0 :   return mInputPort ? mInputPort->GetSource() : nullptr;
     107             : }
     108             : 
     109             : TrackID
     110           0 : DOMMediaStream::TrackPort::GetSourceTrackId() const
     111             : {
     112           0 :   return mInputPort ? mInputPort->GetSourceTrackId() : TRACK_INVALID;
     113             : }
     114             : 
     115             : already_AddRefed<Pledge<bool>>
     116           0 : DOMMediaStream::TrackPort::BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode)
     117             : {
     118           0 :   if (mInputPort) {
     119           0 :     return mInputPort->BlockSourceTrackId(aTrackId, aBlockingMode);
     120             :   }
     121           0 :   auto rejected = MakeRefPtr<Pledge<bool>>();
     122           0 :   rejected->Reject(NS_ERROR_FAILURE);
     123           0 :   return rejected.forget();
     124             : }
     125             : 
     126           0 : NS_IMPL_CYCLE_COLLECTION(DOMMediaStream::TrackPort, mTrack)
     127           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMediaStream::TrackPort, AddRef)
     128           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMediaStream::TrackPort, Release)
     129             : 
     130           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackSourceGetter)
     131           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackSourceGetter)
     132           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackSourceGetter)
     133           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     134           0 : NS_INTERFACE_MAP_END
     135           0 : NS_IMPL_CYCLE_COLLECTION_0(MediaStreamTrackSourceGetter)
     136             : 
     137             : /**
     138             :  * Listener registered on the Owned stream to detect added and ended owned
     139             :  * tracks for keeping the list of MediaStreamTracks in sync with the tracks
     140             :  * added and ended directly at the source.
     141             :  */
     142           0 : class DOMMediaStream::OwnedStreamListener : public MediaStreamListener {
     143             : public:
     144           0 :   explicit OwnedStreamListener(DOMMediaStream* aStream)
     145           0 :     : mStream(aStream)
     146           0 :   {}
     147             : 
     148           0 :   void Forget() { mStream = nullptr; }
     149             : 
     150           0 :   void DoNotifyTrackCreated(TrackID aTrackID, MediaSegment::Type aType,
     151             :                             MediaStream* aInputStream, TrackID aInputTrackID)
     152             :   {
     153           0 :     MOZ_ASSERT(NS_IsMainThread());
     154             : 
     155           0 :     if (!mStream) {
     156           0 :       return;
     157             :     }
     158             : 
     159             :     MediaStreamTrack* track =
     160           0 :       mStream->FindOwnedDOMTrack(aInputStream, aInputTrackID, aTrackID);
     161             : 
     162           0 :     if (track) {
     163           0 :       LOG(LogLevel::Debug, ("DOMMediaStream %p Track %d from owned stream %p "
     164             :                             "bound to MediaStreamTrack %p.",
     165             :                             mStream, aTrackID, aInputStream, track));
     166           0 :       return;
     167             :     }
     168             : 
     169             :     // Track had not been created on main thread before, create it now.
     170           0 :     NS_WARNING_ASSERTION(
     171             :       !mStream->mTracks.IsEmpty(),
     172             :       "A new track was detected on the input stream; creating a corresponding "
     173             :       "MediaStreamTrack. Initial tracks should be added manually to "
     174             :       "immediately and synchronously be available to JS.");
     175           0 :     RefPtr<MediaStreamTrackSource> source;
     176           0 :     if (mStream->mTrackSourceGetter) {
     177           0 :       source = mStream->mTrackSourceGetter->GetMediaStreamTrackSource(aTrackID);
     178             :     }
     179           0 :     if (!source) {
     180           0 :       NS_ASSERTION(false, "Dynamic track created without an explicit TrackSource");
     181           0 :       nsPIDOMWindowInner* window = mStream->GetParentObject();
     182           0 :       nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
     183           0 :       nsIPrincipal* principal = doc ? doc->NodePrincipal() : nullptr;
     184           0 :       source = new BasicTrackSource(principal);
     185             :     }
     186             : 
     187             :     RefPtr<MediaStreamTrack> newTrack =
     188           0 :       mStream->CreateDOMTrack(aTrackID, aType, source);
     189           0 :     NS_DispatchToMainThread(NewRunnableMethod<RefPtr<MediaStreamTrack>>(
     190             :       "DOMMediaStream::AddTrackInternal",
     191             :       mStream,
     192             :       &DOMMediaStream::AddTrackInternal,
     193           0 :       newTrack));
     194             :   }
     195             : 
     196           0 :   void DoNotifyTrackEnded(MediaStream* aInputStream, TrackID aInputTrackID,
     197             :                           TrackID aTrackID)
     198             :   {
     199           0 :     MOZ_ASSERT(NS_IsMainThread());
     200             : 
     201           0 :     if (!mStream) {
     202           0 :       return;
     203             :     }
     204             : 
     205             :     RefPtr<MediaStreamTrack> track =
     206           0 :       mStream->FindOwnedDOMTrack(aInputStream, aInputTrackID, aTrackID);
     207           0 :     NS_ASSERTION(track, "Owned MediaStreamTracks must be known by the DOMMediaStream");
     208           0 :     if (track) {
     209           0 :       LOG(LogLevel::Debug, ("DOMMediaStream %p MediaStreamTrack %p ended at the source. Marking it ended.",
     210             :                             mStream, track.get()));
     211           0 :       NS_DispatchToMainThread(
     212           0 :         NewRunnableMethod("dom::MediaStreamTrack::OverrideEnded",
     213             :                           track,
     214           0 :                           &MediaStreamTrack::OverrideEnded));
     215             :     }
     216             :   }
     217             : 
     218           0 :   void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
     219             :                                 StreamTime aTrackOffset, TrackEventCommand aTrackEvents,
     220             :                                 const MediaSegment& aQueuedMedia,
     221             :                                 MediaStream* aInputStream,
     222             :                                 TrackID aInputTrackID) override
     223             :   {
     224           0 :     if (aTrackEvents & TrackEventCommand::TRACK_EVENT_CREATED) {
     225           0 :       aGraph->DispatchToMainThreadAfterStreamStateUpdate(
     226             :         NewRunnableMethod<TrackID,
     227             :                           MediaSegment::Type,
     228             :                           RefPtr<MediaStream>,
     229           0 :                           TrackID>(
     230             :           "DOMMediaStream::OwnedStreamListener::DoNotifyTrackCreated",
     231             :           this,
     232             :           &OwnedStreamListener::DoNotifyTrackCreated,
     233             :           aID,
     234           0 :           aQueuedMedia.GetType(),
     235             :           aInputStream,
     236           0 :           aInputTrackID));
     237           0 :     } else if (aTrackEvents & TrackEventCommand::TRACK_EVENT_ENDED) {
     238           0 :       aGraph->DispatchToMainThreadAfterStreamStateUpdate(
     239           0 :         NewRunnableMethod<RefPtr<MediaStream>, TrackID, TrackID>(
     240             :           "DOMMediaStream::OwnedStreamListener::DoNotifyTrackEnded",
     241             :           this,
     242             :           &OwnedStreamListener::DoNotifyTrackEnded,
     243             :           aInputStream,
     244             :           aInputTrackID,
     245           0 :           aID));
     246             :     }
     247           0 :   }
     248             : 
     249             : private:
     250             :   // These fields may only be accessed on the main thread
     251             :   DOMMediaStream* mStream;
     252             : };
     253             : 
     254             : /**
     255             :  * Listener registered on the Playback stream to detect when tracks end and when
     256             :  * all new tracks this iteration have been created - for when several tracks are
     257             :  * queued by the source and committed all at once.
     258             :  */
     259           0 : class DOMMediaStream::PlaybackStreamListener : public MediaStreamListener {
     260             : public:
     261           0 :   explicit PlaybackStreamListener(DOMMediaStream* aStream)
     262           0 :     : mStream(aStream)
     263           0 :   {}
     264             : 
     265           0 :   void Forget()
     266             :   {
     267           0 :     MOZ_ASSERT(NS_IsMainThread());
     268           0 :     mStream = nullptr;
     269           0 :   }
     270             : 
     271           0 :   void DoNotifyFinishedTrackCreation()
     272             :   {
     273           0 :     MOZ_ASSERT(NS_IsMainThread());
     274             : 
     275           0 :     if (!mStream) {
     276           0 :       return;
     277             :     }
     278             : 
     279             :     // The owned stream listener adds its tracks after another main thread
     280             :     // dispatch. We have to do the same to notify of created tracks to stay
     281             :     // in sync. (Or NotifyTracksCreated is called before tracks are added).
     282           0 :     NS_DispatchToMainThread(
     283           0 :       NewRunnableMethod("DOMMediaStream::NotifyTracksCreated",
     284             :                         mStream,
     285           0 :                         &DOMMediaStream::NotifyTracksCreated));
     286             :   }
     287             : 
     288           0 :   void DoNotifyFinished()
     289             :   {
     290           0 :     MOZ_ASSERT(NS_IsMainThread());
     291             : 
     292           0 :     if (!mStream) {
     293           0 :       return;
     294             :     }
     295             : 
     296           0 :     NS_DispatchToMainThread(NewRunnableMethod("DOMMediaStream::NotifyFinished",
     297             :                                               mStream,
     298           0 :                                               &DOMMediaStream::NotifyFinished));
     299             :   }
     300             : 
     301             :   // The methods below are called on the MediaStreamGraph thread.
     302             : 
     303           0 :   void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) override
     304             :   {
     305           0 :     aGraph->DispatchToMainThreadAfterStreamStateUpdate(
     306           0 :       NewRunnableMethod(
     307             :         "DOMMediaStream::PlaybackStreamListener::DoNotifyFinishedTrackCreation",
     308             :         this,
     309           0 :         &PlaybackStreamListener::DoNotifyFinishedTrackCreation));
     310           0 :   }
     311             : 
     312             : 
     313           0 :   void NotifyEvent(MediaStreamGraph* aGraph,
     314             :                    MediaStreamGraphEvent event) override
     315             :   {
     316           0 :     if (event == MediaStreamGraphEvent::EVENT_FINISHED) {
     317           0 :       aGraph->DispatchToMainThreadAfterStreamStateUpdate(
     318           0 :         NewRunnableMethod(
     319             :           "DOMMediaStream::PlaybackStreamListener::DoNotifyFinished",
     320             :           this,
     321           0 :           &PlaybackStreamListener::DoNotifyFinished));
     322             :     }
     323           0 :   }
     324             : 
     325             : private:
     326             :   // These fields may only be accessed on the main thread
     327             :   DOMMediaStream* mStream;
     328             : };
     329             : 
     330             : class DOMMediaStream::PlaybackTrackListener : public MediaStreamTrackConsumer
     331             : {
     332             : public:
     333           0 :   explicit PlaybackTrackListener(DOMMediaStream* aStream) :
     334           0 :     mStream(aStream) {}
     335             : 
     336             :   NS_DECL_ISUPPORTS_INHERITED
     337           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PlaybackTrackListener,
     338             :                                            MediaStreamTrackConsumer)
     339             : 
     340           0 :   void NotifyEnded(MediaStreamTrack* aTrack) override
     341             :   {
     342           0 :     if (!mStream) {
     343           0 :       MOZ_ASSERT(false);
     344             :       return;
     345             :     }
     346             : 
     347           0 :     if (!aTrack) {
     348           0 :       MOZ_ASSERT(false);
     349             :       return;
     350             :     }
     351             : 
     352           0 :     MOZ_ASSERT(mStream->HasTrack(*aTrack));
     353           0 :     mStream->NotifyTrackRemoved(aTrack);
     354           0 :   }
     355             : 
     356             : protected:
     357           0 :   virtual ~PlaybackTrackListener() {}
     358             : 
     359             :   RefPtr<DOMMediaStream> mStream;
     360             : };
     361             : 
     362           0 : NS_IMPL_ADDREF_INHERITED(DOMMediaStream::PlaybackTrackListener,
     363             :                          MediaStreamTrackConsumer)
     364           0 : NS_IMPL_RELEASE_INHERITED(DOMMediaStream::PlaybackTrackListener,
     365             :                           MediaStreamTrackConsumer)
     366           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMMediaStream::PlaybackTrackListener)
     367           0 : NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackConsumer)
     368           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMMediaStream::PlaybackTrackListener,
     369             :                                    MediaStreamTrackConsumer,
     370             :                                    mStream)
     371             : 
     372             : NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMediaStream)
     373             : 
     374           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMediaStream,
     375             :                                                 DOMEventTargetHelper)
     376           0 :   tmp->Destroy();
     377           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
     378           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwnedTracks)
     379           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTracks)
     380           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumersToKeepAlive)
     381           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrackSourceGetter)
     382           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaybackTrackListener)
     383           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
     384           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoPrincipal)
     385           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     386             : 
     387           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMMediaStream,
     388             :                                                   DOMEventTargetHelper)
     389           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
     390           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwnedTracks)
     391           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTracks)
     392           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumersToKeepAlive)
     393           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrackSourceGetter)
     394           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaybackTrackListener)
     395           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
     396           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoPrincipal)
     397           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     398             : 
     399           0 : NS_IMPL_ADDREF_INHERITED(DOMMediaStream, DOMEventTargetHelper)
     400           0 : NS_IMPL_RELEASE_INHERITED(DOMMediaStream, DOMEventTargetHelper)
     401             : 
     402           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMMediaStream)
     403           0 :   NS_INTERFACE_MAP_ENTRY(DOMMediaStream)
     404           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
     405             : 
     406           0 : NS_IMPL_ADDREF_INHERITED(DOMLocalMediaStream, DOMMediaStream)
     407           0 : NS_IMPL_RELEASE_INHERITED(DOMLocalMediaStream, DOMMediaStream)
     408             : 
     409           0 : NS_INTERFACE_MAP_BEGIN(DOMLocalMediaStream)
     410           0 :   NS_INTERFACE_MAP_ENTRY(DOMLocalMediaStream)
     411           0 : NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
     412             : 
     413           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream,
     414             :                                    mStreamNode)
     415             : 
     416           0 : NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
     417           0 : NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
     418             : 
     419           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream)
     420           0 : NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
     421             : 
     422           0 : DOMMediaStream::DOMMediaStream(nsPIDOMWindowInner* aWindow,
     423           0 :                                MediaStreamTrackSourceGetter* aTrackSourceGetter)
     424             :   : mLogicalStreamStartTime(0), mWindow(aWindow),
     425             :     mInputStream(nullptr), mOwnedStream(nullptr), mPlaybackStream(nullptr),
     426             :     mTracksPendingRemoval(0), mTrackSourceGetter(aTrackSourceGetter),
     427           0 :     mPlaybackTrackListener(MakeAndAddRef<PlaybackTrackListener>(this)),
     428             :     mTracksCreated(false), mNotifiedOfMediaStreamGraphShutdown(false),
     429           0 :     mActive(false), mSetInactiveOnFinish(false)
     430             : {
     431             :   nsresult rv;
     432             :   nsCOMPtr<nsIUUIDGenerator> uuidgen =
     433           0 :     do_GetService("@mozilla.org/uuid-generator;1", &rv);
     434             : 
     435           0 :   if (NS_SUCCEEDED(rv) && uuidgen) {
     436             :     nsID uuid;
     437           0 :     memset(&uuid, 0, sizeof(uuid));
     438           0 :     rv = uuidgen->GenerateUUIDInPlace(&uuid);
     439           0 :     if (NS_SUCCEEDED(rv)) {
     440             :       char buffer[NSID_LENGTH];
     441           0 :       uuid.ToProvidedString(buffer);
     442           0 :       mID = NS_ConvertASCIItoUTF16(buffer);
     443             :     }
     444             :   }
     445           0 : }
     446             : 
     447           0 : DOMMediaStream::~DOMMediaStream()
     448             : {
     449           0 :   Destroy();
     450           0 : }
     451             : 
     452             : void
     453           0 : DOMMediaStream::Destroy()
     454             : {
     455           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Being destroyed.", this));
     456           0 :   if (mOwnedListener) {
     457           0 :     mOwnedListener->Forget();
     458           0 :     mOwnedListener = nullptr;
     459             :   }
     460           0 :   if (mPlaybackListener) {
     461           0 :     mPlaybackListener->Forget();
     462           0 :     mPlaybackListener = nullptr;
     463             :   }
     464           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
     465             :     // We must remove ourselves from each track's principal change observer list
     466             :     // before we die. CC may have cleared info->mTrack so guard against it.
     467           0 :     MediaStreamTrack* track = info->GetTrack();
     468           0 :     if (track) {
     469           0 :       track->RemovePrincipalChangeObserver(this);
     470           0 :       if (!track->Ended()) {
     471           0 :         track->RemoveConsumer(mPlaybackTrackListener);
     472             :       }
     473             :     }
     474             :   }
     475           0 :   if (mPlaybackPort) {
     476           0 :     mPlaybackPort->Destroy();
     477           0 :     mPlaybackPort = nullptr;
     478             :   }
     479           0 :   if (mOwnedPort) {
     480           0 :     mOwnedPort->Destroy();
     481           0 :     mOwnedPort = nullptr;
     482             :   }
     483           0 :   if (mPlaybackStream) {
     484           0 :     mPlaybackStream->UnregisterUser();
     485           0 :     mPlaybackStream = nullptr;
     486             :   }
     487           0 :   if (mOwnedStream) {
     488           0 :     mOwnedStream->UnregisterUser();
     489           0 :     mOwnedStream = nullptr;
     490             :   }
     491           0 :   if (mInputStream) {
     492           0 :     mInputStream->UnregisterUser();
     493           0 :     mInputStream = nullptr;
     494             :   }
     495           0 :   mRunOnTracksAvailable.Clear();
     496           0 :   mTrackListeners.Clear();
     497           0 : }
     498             : 
     499             : JSObject*
     500           0 : DOMMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     501             : {
     502           0 :   return dom::MediaStreamBinding::Wrap(aCx, this, aGivenProto);
     503             : }
     504             : 
     505             : /* static */ already_AddRefed<DOMMediaStream>
     506           0 : DOMMediaStream::Constructor(const GlobalObject& aGlobal,
     507             :                             ErrorResult& aRv)
     508             : {
     509           0 :   Sequence<OwningNonNull<MediaStreamTrack>> emptyTrackSeq;
     510           0 :   return Constructor(aGlobal, emptyTrackSeq, aRv);
     511             : }
     512             : 
     513             : /* static */ already_AddRefed<DOMMediaStream>
     514           0 : DOMMediaStream::Constructor(const GlobalObject& aGlobal,
     515             :                             const DOMMediaStream& aStream,
     516             :                             ErrorResult& aRv)
     517             : {
     518           0 :   nsTArray<RefPtr<MediaStreamTrack>> tracks;
     519           0 :   aStream.GetTracks(tracks);
     520             : 
     521           0 :   Sequence<OwningNonNull<MediaStreamTrack>> nonNullTrackSeq;
     522           0 :   if (!nonNullTrackSeq.SetLength(tracks.Length(), fallible)) {
     523           0 :     MOZ_ASSERT(false);
     524             :     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     525             :     return nullptr;
     526             :   }
     527             : 
     528           0 :   for (size_t i = 0; i < tracks.Length(); ++i) {
     529           0 :     nonNullTrackSeq[i] = tracks[i];
     530             :   }
     531             : 
     532           0 :   return Constructor(aGlobal, nonNullTrackSeq, aRv);
     533             : }
     534             : 
     535             : /* static */ already_AddRefed<DOMMediaStream>
     536           0 : DOMMediaStream::Constructor(const GlobalObject& aGlobal,
     537             :                             const Sequence<OwningNonNull<MediaStreamTrack>>& aTracks,
     538             :                             ErrorResult& aRv)
     539             : {
     540           0 :   nsCOMPtr<nsPIDOMWindowInner> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
     541           0 :   if (!ownerWindow) {
     542           0 :     aRv.Throw(NS_ERROR_FAILURE);
     543           0 :     return nullptr;
     544             :   }
     545             : 
     546             :   // Streams created from JS cannot have dynamically created tracks.
     547           0 :   MediaStreamTrackSourceGetter* getter = nullptr;
     548           0 :   RefPtr<DOMMediaStream> newStream = new DOMMediaStream(ownerWindow, getter);
     549             : 
     550           0 :   for (MediaStreamTrack& track : aTracks) {
     551           0 :     if (!newStream->GetPlaybackStream()) {
     552           0 :       MOZ_RELEASE_ASSERT(track.Graph());
     553           0 :       newStream->InitPlaybackStreamCommon(track.Graph());
     554             :     }
     555           0 :     newStream->AddTrack(track);
     556             :   }
     557             : 
     558           0 :   if (!newStream->GetPlaybackStream()) {
     559           0 :     MOZ_ASSERT(aTracks.IsEmpty());
     560             :     MediaStreamGraph* graph =
     561           0 :       MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
     562           0 :                                     AudioChannel::Normal, ownerWindow);
     563           0 :     newStream->InitPlaybackStreamCommon(graph);
     564             :   }
     565             : 
     566           0 :   return newStream.forget();
     567             : }
     568             : 
     569             : double
     570           0 : DOMMediaStream::CurrentTime()
     571             : {
     572           0 :   if (!mPlaybackStream) {
     573           0 :     return 0.0;
     574             :   }
     575           0 :   return nsRFPService::ReduceTimePrecisionAsSecs(mPlaybackStream->
     576           0 :     StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime));
     577             : }
     578             : 
     579             : void
     580           0 : DOMMediaStream::GetId(nsAString& aID) const
     581             : {
     582           0 :   aID = mID;
     583           0 : }
     584             : 
     585             : void
     586           0 : DOMMediaStream::GetAudioTracks(nsTArray<RefPtr<AudioStreamTrack> >& aTracks) const
     587             : {
     588           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
     589           0 :     AudioStreamTrack* t = info->GetTrack()->AsAudioStreamTrack();
     590           0 :     if (t) {
     591           0 :       aTracks.AppendElement(t);
     592             :     }
     593             :   }
     594           0 : }
     595             : 
     596             : void
     597           0 : DOMMediaStream::GetVideoTracks(nsTArray<RefPtr<VideoStreamTrack> >& aTracks) const
     598             : {
     599           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
     600           0 :     VideoStreamTrack* t = info->GetTrack()->AsVideoStreamTrack();
     601           0 :     if (t) {
     602           0 :       aTracks.AppendElement(t);
     603             :     }
     604             :   }
     605           0 : }
     606             : 
     607             : void
     608           0 : DOMMediaStream::GetTracks(nsTArray<RefPtr<MediaStreamTrack> >& aTracks) const
     609             : {
     610           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
     611           0 :     aTracks.AppendElement(info->GetTrack());
     612             :   }
     613           0 : }
     614             : 
     615             : void
     616           0 : DOMMediaStream::AddTrack(MediaStreamTrack& aTrack)
     617             : {
     618           0 :   MOZ_RELEASE_ASSERT(mPlaybackStream);
     619             : 
     620           0 :   RefPtr<ProcessedMediaStream> dest = mPlaybackStream->AsProcessedStream();
     621           0 :   MOZ_ASSERT(dest);
     622           0 :   if (!dest) {
     623           0 :     return;
     624             :   }
     625             : 
     626           0 :   LOG(LogLevel::Info, ("DOMMediaStream %p Adding track %p (from stream %p with ID %d)",
     627             :                        this, &aTrack, aTrack.mOwningStream.get(), aTrack.mTrackID));
     628             : 
     629           0 :   if (mPlaybackStream->Graph() != aTrack.Graph()) {
     630           0 :     NS_ASSERTION(false, "Cannot combine tracks from different MediaStreamGraphs");
     631           0 :     LOG(LogLevel::Error, ("DOMMediaStream %p Own MSG %p != aTrack's MSG %p",
     632             :                          this, mPlaybackStream->Graph(), aTrack.Graph()));
     633             : 
     634           0 :     nsAutoString trackId;
     635           0 :     aTrack.GetId(trackId);
     636           0 :     const char16_t* params[] = { trackId.get() };
     637           0 :     nsCOMPtr<nsPIDOMWindowInner> pWindow = GetParentObject();
     638           0 :     nsIDocument* document = pWindow ? pWindow->GetExtantDoc() : nullptr;
     639           0 :     nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
     640           0 :                                     NS_LITERAL_CSTRING("Media"),
     641             :                                     document,
     642             :                                     nsContentUtils::eDOM_PROPERTIES,
     643             :                                     "MediaStreamAddTrackDifferentAudioChannel",
     644           0 :                                     params, ArrayLength(params));
     645           0 :     return;
     646             :   }
     647             : 
     648           0 :   if (HasTrack(aTrack)) {
     649           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p already contains track %p", this, &aTrack));
     650           0 :     return;
     651             :   }
     652             : 
     653             :   // Hook up the underlying track with our underlying playback stream.
     654             :   RefPtr<MediaInputPort> inputPort =
     655           0 :     GetPlaybackStream()->AllocateInputPort(aTrack.GetOwnedStream(),
     656           0 :                                            aTrack.mTrackID);
     657             :   RefPtr<TrackPort> trackPort =
     658           0 :     new TrackPort(inputPort, &aTrack, TrackPort::InputPortOwnership::OWNED);
     659           0 :   mTracks.AppendElement(trackPort.forget());
     660           0 :   NotifyTrackAdded(&aTrack);
     661             : 
     662           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Added track %p", this, &aTrack));
     663             : }
     664             : 
     665             : void
     666           0 : DOMMediaStream::RemoveTrack(MediaStreamTrack& aTrack)
     667             : {
     668           0 :   LOG(LogLevel::Info, ("DOMMediaStream %p Removing track %p (from stream %p with ID %d)",
     669             :                        this, &aTrack, aTrack.mOwningStream.get(), aTrack.mTrackID));
     670             : 
     671           0 :   RefPtr<TrackPort> toRemove = FindPlaybackTrackPort(aTrack);
     672           0 :   if (!toRemove) {
     673           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p does not contain track %p", this, &aTrack));
     674           0 :     return;
     675             :   }
     676             : 
     677           0 :   DebugOnly<bool> removed = mTracks.RemoveElement(toRemove);
     678           0 :   NS_ASSERTION(removed, "If there's a track port we should be able to remove it");
     679             : 
     680             :   // If the track comes from a TRACK_ANY input port (i.e., mOwnedPort), we need
     681             :   // to block it in the port. Doing this for a locked track is still OK as it
     682             :   // will first block the track, then destroy the port. Both cause the track to
     683             :   // end.
     684             :   // If the track has already ended, it's input port might be gone, so in those
     685             :   // cases blocking the underlying track should be avoided.
     686           0 :   if (!aTrack.Ended()) {
     687           0 :     BlockPlaybackTrack(toRemove);
     688           0 :     NotifyTrackRemoved(&aTrack);
     689             :   }
     690             : 
     691           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Removed track %p", this, &aTrack));
     692             : }
     693             : 
     694             : class ClonedStreamSourceGetter :
     695             :   public MediaStreamTrackSourceGetter
     696             : {
     697             : public:
     698             :   NS_DECL_ISUPPORTS_INHERITED
     699           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ClonedStreamSourceGetter,
     700             :                                            MediaStreamTrackSourceGetter)
     701             : 
     702           0 :   explicit ClonedStreamSourceGetter(DOMMediaStream* aStream)
     703           0 :     : mStream(aStream) {}
     704             : 
     705             :   already_AddRefed<MediaStreamTrackSource>
     706           0 :   GetMediaStreamTrackSource(TrackID aInputTrackID) override
     707             :   {
     708             :     MediaStreamTrack* sourceTrack =
     709           0 :       mStream->FindOwnedDOMTrack(mStream->GetOwnedStream(), aInputTrackID);
     710           0 :     MOZ_RELEASE_ASSERT(sourceTrack);
     711             : 
     712           0 :     return do_AddRef(&sourceTrack->GetSource());
     713             :   }
     714             : 
     715             : protected:
     716           0 :   virtual ~ClonedStreamSourceGetter() {}
     717             : 
     718             :   RefPtr<DOMMediaStream> mStream;
     719             : };
     720             : 
     721           0 : NS_IMPL_ADDREF_INHERITED(ClonedStreamSourceGetter,
     722             :                          MediaStreamTrackSourceGetter)
     723           0 : NS_IMPL_RELEASE_INHERITED(ClonedStreamSourceGetter,
     724             :                           MediaStreamTrackSourceGetter)
     725           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ClonedStreamSourceGetter)
     726           0 : NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSourceGetter)
     727           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(ClonedStreamSourceGetter,
     728             :                                    MediaStreamTrackSourceGetter,
     729             :                                    mStream)
     730             : 
     731             : already_AddRefed<DOMMediaStream>
     732           0 : DOMMediaStream::Clone()
     733             : {
     734           0 :   return CloneInternal(TrackForwardingOption::CURRENT);
     735             : }
     736             : 
     737             : already_AddRefed<DOMMediaStream>
     738           0 : DOMMediaStream::CloneInternal(TrackForwardingOption aForwarding)
     739             : {
     740             :   RefPtr<DOMMediaStream> newStream =
     741           0 :     new DOMMediaStream(GetParentObject(), new ClonedStreamSourceGetter(this));
     742             : 
     743           0 :   LOG(LogLevel::Info, ("DOMMediaStream %p created clone %p, forwarding %s tracks",
     744             :                        this, newStream.get(),
     745             :                        aForwarding == TrackForwardingOption::ALL
     746             :                        ? "all" : "current"));
     747             : 
     748           0 :   MOZ_RELEASE_ASSERT(mPlaybackStream);
     749           0 :   MOZ_RELEASE_ASSERT(mPlaybackStream->Graph());
     750           0 :   MediaStreamGraph* graph = mPlaybackStream->Graph();
     751             : 
     752             :   // We initiate the owned and playback streams first, since we need to create
     753             :   // all existing DOM tracks before we add the generic input port from
     754             :   // mInputStream to mOwnedStream (see AllocateInputPort wrt. destination
     755             :   // TrackID as to why).
     756           0 :   newStream->InitOwnedStreamCommon(graph);
     757           0 :   newStream->InitPlaybackStreamCommon(graph);
     758             : 
     759             :   // Set up existing DOM tracks.
     760           0 :   TrackID allocatedTrackID = 1;
     761           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
     762           0 :     MediaStreamTrack& track = *info->GetTrack();
     763             : 
     764           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p forwarding external track %p to clone %p",
     765             :                           this, &track, newStream.get()));
     766             :     RefPtr<MediaStreamTrack> trackClone =
     767           0 :       newStream->CloneDOMTrack(track, allocatedTrackID++);
     768             :   }
     769             : 
     770           0 :   if (aForwarding == TrackForwardingOption::ALL) {
     771             :     // Set up an input port from our input stream to the new DOM stream's owned
     772             :     // stream, to allow for dynamically added tracks at the source to appear in
     773             :     // the clone. The clone may treat mInputStream as its own mInputStream but
     774             :     // ownership remains with us.
     775           0 :     newStream->mInputStream = mInputStream;
     776           0 :     if (mInputStream) {
     777             :       // We have already set up track-locked input ports for all existing DOM
     778             :       // tracks, so now we need to block those in the generic input port to
     779             :       // avoid ending up with double instances of them.
     780           0 :       nsTArray<TrackID> tracksToBlock;
     781           0 :       for (const RefPtr<TrackPort>& info : mOwnedTracks) {
     782           0 :         tracksToBlock.AppendElement(info->GetTrack()->mTrackID);
     783             :       }
     784             : 
     785           0 :       newStream->mInputStream->RegisterUser();
     786           0 :       newStream->mOwnedPort =
     787           0 :         newStream->mOwnedStream->AllocateInputPort(mInputStream,
     788             :                                                    TRACK_ANY, TRACK_ANY, 0, 0,
     789           0 :                                                    &tracksToBlock);
     790             :     }
     791             :   }
     792             : 
     793           0 :   return newStream.forget();
     794             : }
     795             : 
     796             : bool
     797           0 : DOMMediaStream::Active() const
     798             : {
     799           0 :   return mActive;
     800             : }
     801             : 
     802             : MediaStreamTrack*
     803           0 : DOMMediaStream::GetTrackById(const nsAString& aId) const
     804             : {
     805           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
     806           0 :     nsString id;
     807           0 :     info->GetTrack()->GetId(id);
     808           0 :     if (id == aId) {
     809           0 :       return info->GetTrack();
     810             :     }
     811             :   }
     812           0 :   return nullptr;
     813             : }
     814             : 
     815             : MediaStreamTrack*
     816           0 : DOMMediaStream::GetOwnedTrackById(const nsAString& aId)
     817             : {
     818           0 :   for (const RefPtr<TrackPort>& info : mOwnedTracks) {
     819           0 :     nsString id;
     820           0 :     info->GetTrack()->GetId(id);
     821           0 :     if (id == aId) {
     822           0 :       return info->GetTrack();
     823             :     }
     824             :   }
     825           0 :   return nullptr;
     826             : }
     827             : 
     828             : bool
     829           0 : DOMMediaStream::HasTrack(const MediaStreamTrack& aTrack) const
     830             : {
     831           0 :   return !!FindPlaybackTrackPort(aTrack);
     832             : }
     833             : 
     834             : bool
     835           0 : DOMMediaStream::OwnsTrack(const MediaStreamTrack& aTrack) const
     836             : {
     837           0 :   return !!FindOwnedTrackPort(aTrack);
     838             : }
     839             : 
     840             : bool
     841           0 : DOMMediaStream::AddDirectListener(DirectMediaStreamListener* aListener)
     842             : {
     843           0 :   if (GetInputStream() && GetInputStream()->AsSourceStream()) {
     844           0 :     GetInputStream()->AsSourceStream()->AddDirectListener(aListener);
     845           0 :     return true; // application should ignore NotifyQueuedTrackData
     846             :   }
     847           0 :   return false;
     848             : }
     849             : 
     850             : void
     851           0 : DOMMediaStream::RemoveDirectListener(DirectMediaStreamListener* aListener)
     852             : {
     853           0 :   if (GetInputStream() && GetInputStream()->AsSourceStream()) {
     854           0 :     GetInputStream()->AsSourceStream()->RemoveDirectListener(aListener);
     855             :   }
     856           0 : }
     857             : 
     858             : bool
     859           0 : DOMMediaStream::IsFinished() const
     860             : {
     861           0 :   return !mPlaybackStream || mPlaybackStream->IsFinished();
     862             : }
     863             : 
     864             : void
     865           0 : DOMMediaStream::SetInactiveOnFinish()
     866             : {
     867           0 :   mSetInactiveOnFinish = true;
     868           0 : }
     869             : 
     870             : void
     871           0 : DOMMediaStream::InitSourceStream(MediaStreamGraph* aGraph)
     872             : {
     873           0 :   InitInputStreamCommon(aGraph->CreateSourceStream(), aGraph);
     874           0 :   InitOwnedStreamCommon(aGraph);
     875           0 :   InitPlaybackStreamCommon(aGraph);
     876           0 : }
     877             : 
     878             : void
     879           0 : DOMMediaStream::InitTrackUnionStream(MediaStreamGraph* aGraph)
     880             : {
     881           0 :   InitInputStreamCommon(aGraph->CreateTrackUnionStream(), aGraph);
     882           0 :   InitOwnedStreamCommon(aGraph);
     883           0 :   InitPlaybackStreamCommon(aGraph);
     884           0 : }
     885             : 
     886             : void
     887           0 : DOMMediaStream::InitAudioCaptureStream(nsIPrincipal* aPrincipal, MediaStreamGraph* aGraph)
     888             : {
     889           0 :   const TrackID AUDIO_TRACK = 1;
     890             : 
     891             :   RefPtr<BasicTrackSource> audioCaptureSource =
     892           0 :     new BasicTrackSource(aPrincipal, MediaSourceEnum::AudioCapture);
     893             : 
     894             :   AudioCaptureStream* audioCaptureStream =
     895           0 :     static_cast<AudioCaptureStream*>(aGraph->CreateAudioCaptureStream(AUDIO_TRACK));
     896           0 :   InitInputStreamCommon(audioCaptureStream, aGraph);
     897           0 :   InitOwnedStreamCommon(aGraph);
     898           0 :   InitPlaybackStreamCommon(aGraph);
     899             :   RefPtr<MediaStreamTrack> track =
     900           0 :     CreateDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO, audioCaptureSource);
     901           0 :   AddTrackInternal(track);
     902             : 
     903           0 :   audioCaptureStream->Start();
     904           0 : }
     905             : 
     906             : void
     907           0 : DOMMediaStream::InitInputStreamCommon(MediaStream* aStream,
     908             :                                       MediaStreamGraph* aGraph)
     909             : {
     910           0 :   MOZ_ASSERT(!mOwnedStream, "Input stream must be initialized before owned stream");
     911             : 
     912           0 :   mInputStream = aStream;
     913           0 :   mInputStream->RegisterUser();
     914           0 : }
     915             : 
     916             : void
     917           0 : DOMMediaStream::InitOwnedStreamCommon(MediaStreamGraph* aGraph)
     918             : {
     919           0 :   MOZ_ASSERT(!mPlaybackStream, "Owned stream must be initialized before playback stream");
     920             : 
     921           0 :   mOwnedStream = aGraph->CreateTrackUnionStream();
     922           0 :   mOwnedStream->SetAutofinish(true);
     923           0 :   mOwnedStream->RegisterUser();
     924           0 :   if (mInputStream) {
     925           0 :     mOwnedPort = mOwnedStream->AllocateInputPort(mInputStream);
     926             :   }
     927             : 
     928             :   // Setup track listeners
     929           0 :   mOwnedListener = new OwnedStreamListener(this);
     930           0 :   mOwnedStream->AddListener(mOwnedListener);
     931           0 : }
     932             : 
     933             : void
     934           0 : DOMMediaStream::InitPlaybackStreamCommon(MediaStreamGraph* aGraph)
     935             : {
     936           0 :   mPlaybackStream = aGraph->CreateTrackUnionStream();
     937           0 :   mPlaybackStream->SetAutofinish(true);
     938           0 :   mPlaybackStream->RegisterUser();
     939           0 :   if (mOwnedStream) {
     940           0 :     mPlaybackPort = mPlaybackStream->AllocateInputPort(mOwnedStream);
     941             :   }
     942             : 
     943           0 :   mPlaybackListener = new PlaybackStreamListener(this);
     944           0 :   mPlaybackStream->AddListener(mPlaybackListener);
     945             : 
     946           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Initiated with mInputStream=%p, mOwnedStream=%p, mPlaybackStream=%p",
     947             :                         this, mInputStream, mOwnedStream, mPlaybackStream));
     948           0 : }
     949             : 
     950             : already_AddRefed<DOMMediaStream>
     951           0 : DOMMediaStream::CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
     952             :                                           MediaStreamGraph* aGraph,
     953             :                                           MediaStreamTrackSourceGetter* aTrackSourceGetter)
     954             : {
     955           0 :   RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, aTrackSourceGetter);
     956           0 :   stream->InitSourceStream(aGraph);
     957           0 :   return stream.forget();
     958             : }
     959             : 
     960             : already_AddRefed<DOMMediaStream>
     961           0 : DOMMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
     962             :                                               MediaStreamGraph* aGraph,
     963             :                                               MediaStreamTrackSourceGetter* aTrackSourceGetter)
     964             : {
     965           0 :   RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, aTrackSourceGetter);
     966           0 :   stream->InitTrackUnionStream(aGraph);
     967           0 :   return stream.forget();
     968             : }
     969             : 
     970             : already_AddRefed<DOMMediaStream>
     971           0 : DOMMediaStream::CreateAudioCaptureStreamAsInput(nsPIDOMWindowInner* aWindow,
     972             :                                                 nsIPrincipal* aPrincipal,
     973             :                                                 MediaStreamGraph* aGraph)
     974             : {
     975             :   // Audio capture doesn't create tracks dynamically
     976           0 :   MediaStreamTrackSourceGetter* getter = nullptr;
     977           0 :   RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, getter);
     978           0 :   stream->InitAudioCaptureStream(aPrincipal, aGraph);
     979           0 :   return stream.forget();
     980             : }
     981             : 
     982             : void
     983           0 : DOMMediaStream::PrincipalChanged(MediaStreamTrack* aTrack)
     984             : {
     985           0 :   MOZ_ASSERT(aTrack);
     986           0 :   NS_ASSERTION(HasTrack(*aTrack), "Principal changed for an unknown track");
     987           0 :   LOG(LogLevel::Info, ("DOMMediaStream %p Principal changed for track %p",
     988             :                        this, aTrack));
     989           0 :   RecomputePrincipal();
     990           0 : }
     991             : 
     992             : void
     993           0 : DOMMediaStream::RecomputePrincipal()
     994             : {
     995           0 :   nsCOMPtr<nsIPrincipal> previousPrincipal = mPrincipal.forget();
     996           0 :   nsCOMPtr<nsIPrincipal> previousVideoPrincipal = mVideoPrincipal.forget();
     997             : 
     998           0 :   if (mTracksPendingRemoval > 0) {
     999           0 :     LOG(LogLevel::Info, ("DOMMediaStream %p RecomputePrincipal() Cannot "
    1000             :                          "recompute stream principal with tracks pending "
    1001             :                          "removal.", this));
    1002           0 :     return;
    1003             :   }
    1004             : 
    1005           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Recomputing principal. "
    1006             :                         "Old principal was %p.", this, previousPrincipal.get()));
    1007             : 
    1008             :   // mPrincipal is recomputed based on all current tracks, and tracks that have
    1009             :   // not ended in our playback stream.
    1010           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
    1011           0 :     if (info->GetTrack()->Ended()) {
    1012           0 :       continue;
    1013             :     }
    1014           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p Taking live track %p with "
    1015             :                           "principal %p into account.", this,
    1016             :                           info->GetTrack(), info->GetTrack()->GetPrincipal()));
    1017           0 :     nsContentUtils::CombineResourcePrincipals(&mPrincipal,
    1018           0 :                                               info->GetTrack()->GetPrincipal());
    1019           0 :     if (info->GetTrack()->AsVideoStreamTrack()) {
    1020           0 :       nsContentUtils::CombineResourcePrincipals(&mVideoPrincipal,
    1021           0 :                                                 info->GetTrack()->GetPrincipal());
    1022             :     }
    1023             :   }
    1024             : 
    1025           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p new principal is %p.",
    1026             :                         this, mPrincipal.get()));
    1027             : 
    1028           0 :   if (previousPrincipal != mPrincipal ||
    1029           0 :       previousVideoPrincipal != mVideoPrincipal) {
    1030           0 :     NotifyPrincipalChanged();
    1031             :   }
    1032             : }
    1033             : 
    1034             : void
    1035           0 : DOMMediaStream::NotifyPrincipalChanged()
    1036             : {
    1037           0 :   if (!mPrincipal) {
    1038             :     // When all tracks are removed, mPrincipal will change to nullptr.
    1039           0 :     LOG(LogLevel::Info, ("DOMMediaStream %p Principal changed to nothing.",
    1040             :                          this));
    1041             :   } else {
    1042           0 :     LOG(LogLevel::Info, ("DOMMediaStream %p Principal changed. Now: "
    1043             :                          "null=%d, codebase=%d, expanded=%d, system=%d", this,
    1044             :                           mPrincipal->GetIsNullPrincipal(),
    1045             :                           mPrincipal->GetIsCodebasePrincipal(),
    1046             :                           mPrincipal->GetIsExpandedPrincipal(),
    1047             :                           mPrincipal->GetIsSystemPrincipal()));
    1048             :   }
    1049             : 
    1050           0 :   for (uint32_t i = 0; i < mPrincipalChangeObservers.Length(); ++i) {
    1051           0 :     mPrincipalChangeObservers[i]->PrincipalChanged(this);
    1052             :   }
    1053           0 : }
    1054             : 
    1055             : 
    1056             : bool
    1057           0 : DOMMediaStream::AddPrincipalChangeObserver(
    1058             :   PrincipalChangeObserver<DOMMediaStream>* aObserver)
    1059             : {
    1060           0 :   return mPrincipalChangeObservers.AppendElement(aObserver) != nullptr;
    1061             : }
    1062             : 
    1063             : bool
    1064           0 : DOMMediaStream::RemovePrincipalChangeObserver(
    1065             :   PrincipalChangeObserver<DOMMediaStream>* aObserver)
    1066             : {
    1067           0 :   return mPrincipalChangeObservers.RemoveElement(aObserver);
    1068             : }
    1069             : 
    1070             : void
    1071           0 : DOMMediaStream::AddTrackInternal(MediaStreamTrack* aTrack)
    1072             : {
    1073           0 :   MOZ_ASSERT(aTrack->mOwningStream == this);
    1074           0 :   MOZ_ASSERT(FindOwnedDOMTrack(aTrack->GetInputStream(),
    1075             :                                aTrack->mInputTrackID,
    1076             :                                aTrack->mTrackID));
    1077           0 :   MOZ_ASSERT(!FindPlaybackDOMTrack(aTrack->GetOwnedStream(),
    1078             :                                    aTrack->mTrackID));
    1079             : 
    1080           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Adding owned track %p", this, aTrack));
    1081             : 
    1082           0 :   mTracks.AppendElement(
    1083           0 :     new TrackPort(mPlaybackPort, aTrack, TrackPort::InputPortOwnership::EXTERNAL));
    1084             : 
    1085           0 :   NotifyTrackAdded(aTrack);
    1086             : 
    1087           0 :   DispatchTrackEvent(NS_LITERAL_STRING("addtrack"), aTrack);
    1088           0 : }
    1089             : 
    1090             : already_AddRefed<MediaStreamTrack>
    1091           0 : DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType,
    1092             :                                MediaStreamTrackSource* aSource,
    1093             :                                const MediaTrackConstraints& aConstraints)
    1094             : {
    1095           0 :   MOZ_RELEASE_ASSERT(mInputStream);
    1096           0 :   MOZ_RELEASE_ASSERT(mOwnedStream);
    1097             : 
    1098           0 :   MOZ_ASSERT(FindOwnedDOMTrack(GetInputStream(), aTrackID) == nullptr);
    1099             : 
    1100           0 :   RefPtr<MediaStreamTrack> track;
    1101           0 :   switch (aType) {
    1102             :   case MediaSegment::AUDIO:
    1103           0 :     track = new AudioStreamTrack(this, aTrackID, aTrackID, aSource, aConstraints);
    1104           0 :     break;
    1105             :   case MediaSegment::VIDEO:
    1106           0 :     track = new VideoStreamTrack(this, aTrackID, aTrackID, aSource, aConstraints);
    1107           0 :     break;
    1108             :   default:
    1109           0 :     MOZ_CRASH("Unhandled track type");
    1110             :   }
    1111             : 
    1112           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Created new track %p with ID %u",
    1113             :                         this, track.get(), aTrackID));
    1114             : 
    1115           0 :   mOwnedTracks.AppendElement(
    1116           0 :     new TrackPort(mOwnedPort, track, TrackPort::InputPortOwnership::EXTERNAL));
    1117             : 
    1118           0 :   return track.forget();
    1119             : }
    1120             : 
    1121             : already_AddRefed<MediaStreamTrack>
    1122           0 : DOMMediaStream::CloneDOMTrack(MediaStreamTrack& aTrack,
    1123             :                               TrackID aCloneTrackID)
    1124             : {
    1125           0 :   MOZ_RELEASE_ASSERT(mOwnedStream);
    1126           0 :   MOZ_RELEASE_ASSERT(mPlaybackStream);
    1127           0 :   MOZ_RELEASE_ASSERT(IsTrackIDExplicit(aCloneTrackID));
    1128             : 
    1129           0 :   TrackID inputTrackID = aTrack.mInputTrackID;
    1130           0 :   MediaStream* inputStream = aTrack.GetInputStream();
    1131             : 
    1132           0 :   RefPtr<MediaStreamTrack> newTrack = aTrack.CloneInternal(this, aCloneTrackID);
    1133             : 
    1134           0 :   newTrack->mOriginalTrack =
    1135           0 :     aTrack.mOriginalTrack ? aTrack.mOriginalTrack.get() : &aTrack;
    1136             : 
    1137           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Created new track %p cloned from stream %p track %d",
    1138             :                         this, newTrack.get(), inputStream, inputTrackID));
    1139             : 
    1140             :   RefPtr<MediaInputPort> inputPort =
    1141           0 :     mOwnedStream->AllocateInputPort(inputStream, inputTrackID, aCloneTrackID);
    1142             : 
    1143           0 :   mOwnedTracks.AppendElement(
    1144           0 :     new TrackPort(inputPort, newTrack, TrackPort::InputPortOwnership::OWNED));
    1145             : 
    1146           0 :   mTracks.AppendElement(
    1147           0 :     new TrackPort(mPlaybackPort, newTrack, TrackPort::InputPortOwnership::EXTERNAL));
    1148             : 
    1149           0 :   NotifyTrackAdded(newTrack);
    1150             : 
    1151           0 :   newTrack->SetEnabled(aTrack.Enabled());
    1152           0 :   newTrack->SetReadyState(aTrack.ReadyState());
    1153             : 
    1154           0 :   if (aTrack.Ended()) {
    1155             :     // For extra suspenders, make sure that we don't forward data by mistake
    1156             :     // to the clone when the original has already ended.
    1157             :     // We only block END_EXISTING to allow any pending clones to end.
    1158             :     RefPtr<Pledge<bool, nsresult>> blockingPledge =
    1159           0 :       inputPort->BlockSourceTrackId(inputTrackID,
    1160           0 :                                     BlockingMode::END_EXISTING);
    1161             :     Unused << blockingPledge;
    1162             :   }
    1163             : 
    1164           0 :   return newTrack.forget();
    1165             : }
    1166             : 
    1167             : static DOMMediaStream::TrackPort*
    1168           0 : FindTrackPortAmongTracks(const MediaStreamTrack& aTrack,
    1169             :                          const nsTArray<RefPtr<DOMMediaStream::TrackPort>>& aTracks)
    1170             : {
    1171           0 :   for (const RefPtr<DOMMediaStream::TrackPort>& info : aTracks) {
    1172           0 :     if (info->GetTrack() == &aTrack) {
    1173           0 :       return info;
    1174             :     }
    1175             :   }
    1176           0 :   return nullptr;
    1177             : }
    1178             : 
    1179             : MediaStreamTrack*
    1180           0 : DOMMediaStream::FindOwnedDOMTrack(MediaStream* aInputStream,
    1181             :                                   TrackID aInputTrackID,
    1182             :                                   TrackID aTrackID) const
    1183             : {
    1184           0 :   MOZ_RELEASE_ASSERT(mOwnedStream);
    1185             : 
    1186           0 :   for (const RefPtr<TrackPort>& info : mOwnedTracks) {
    1187           0 :     if (info->GetInputPort() &&
    1188           0 :         info->GetInputPort()->GetSource() == aInputStream &&
    1189           0 :         info->GetTrack()->mInputTrackID == aInputTrackID &&
    1190           0 :         (aTrackID == TRACK_ANY || info->GetTrack()->mTrackID == aTrackID)) {
    1191             :       // This track is owned externally but in our playback stream.
    1192           0 :       return info->GetTrack();
    1193             :     }
    1194             :   }
    1195           0 :   return nullptr;
    1196             : }
    1197             : 
    1198             : DOMMediaStream::TrackPort*
    1199           0 : DOMMediaStream::FindOwnedTrackPort(const MediaStreamTrack& aTrack) const
    1200             : {
    1201           0 :   return FindTrackPortAmongTracks(aTrack, mOwnedTracks);
    1202             : }
    1203             : 
    1204             : 
    1205             : MediaStreamTrack*
    1206           0 : DOMMediaStream::FindPlaybackDOMTrack(MediaStream* aInputStream, TrackID aInputTrackID) const
    1207             : {
    1208           0 :   if (!mPlaybackStream) {
    1209             :     // One would think we can assert mPlaybackStream here, but track clones have
    1210             :     // a dummy DOMMediaStream that doesn't have a playback stream, so we can't.
    1211           0 :     return nullptr;
    1212             :   }
    1213             : 
    1214           0 :   for (const RefPtr<TrackPort>& info : mTracks) {
    1215           0 :     if (info->GetInputPort() == mPlaybackPort &&
    1216           0 :         aInputStream == mOwnedStream &&
    1217           0 :         info->GetTrack()->mInputTrackID == aInputTrackID) {
    1218             :       // This track is in our owned and playback streams.
    1219           0 :       return info->GetTrack();
    1220             :     }
    1221           0 :     if (info->GetInputPort() &&
    1222           0 :         info->GetInputPort()->GetSource() == aInputStream &&
    1223           0 :         info->GetSourceTrackId() == aInputTrackID) {
    1224             :       // This track is owned externally but in our playback stream.
    1225           0 :       MOZ_ASSERT(IsTrackIDExplicit(aInputTrackID));
    1226           0 :       return info->GetTrack();
    1227             :     }
    1228             :   }
    1229           0 :   return nullptr;
    1230             : }
    1231             : 
    1232             : DOMMediaStream::TrackPort*
    1233           0 : DOMMediaStream::FindPlaybackTrackPort(const MediaStreamTrack& aTrack) const
    1234             : {
    1235           0 :   return FindTrackPortAmongTracks(aTrack, mTracks);
    1236             : }
    1237             : 
    1238             : void
    1239           0 : DOMMediaStream::OnTracksAvailable(OnTracksAvailableCallback* aRunnable)
    1240             : {
    1241           0 :   if (mNotifiedOfMediaStreamGraphShutdown) {
    1242             :     // No more tracks will ever be added, so just delete the callback now.
    1243           0 :     delete aRunnable;
    1244           0 :     return;
    1245             :   }
    1246           0 :   mRunOnTracksAvailable.AppendElement(aRunnable);
    1247           0 :   CheckTracksAvailable();
    1248             : }
    1249             : 
    1250             : void
    1251           0 : DOMMediaStream::NotifyTracksCreated()
    1252             : {
    1253           0 :   mTracksCreated = true;
    1254           0 :   CheckTracksAvailable();
    1255           0 : }
    1256             : 
    1257             : void
    1258           0 : DOMMediaStream::NotifyFinished()
    1259             : {
    1260           0 :   if (!mSetInactiveOnFinish) {
    1261           0 :     return;
    1262             :   }
    1263             : 
    1264           0 :   if (!mActive) {
    1265             :     // This can happen if the stream never became active.
    1266           0 :     return;
    1267             :   }
    1268             : 
    1269           0 :   MOZ_ASSERT(!ContainsLiveTracks(mTracks));
    1270           0 :   mActive = false;
    1271           0 :   NotifyInactive();
    1272             : }
    1273             : 
    1274             : void
    1275           0 : DOMMediaStream::NotifyActive()
    1276             : {
    1277           0 :   LOG(LogLevel::Info, ("DOMMediaStream %p NotifyActive(). ", this));
    1278             : 
    1279           0 :   MOZ_ASSERT(mActive);
    1280           0 :   for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
    1281           0 :     mTrackListeners[i]->NotifyActive();
    1282             :   }
    1283           0 : }
    1284             : 
    1285             : void
    1286           0 : DOMMediaStream::NotifyInactive()
    1287             : {
    1288           0 :   LOG(LogLevel::Info, ("DOMMediaStream %p NotifyInactive(). ", this));
    1289             : 
    1290           0 :   MOZ_ASSERT(!mActive);
    1291           0 :   for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
    1292           0 :     mTrackListeners[i]->NotifyInactive();
    1293             :   }
    1294           0 : }
    1295             : 
    1296             : void
    1297           0 : DOMMediaStream::CheckTracksAvailable()
    1298             : {
    1299           0 :   if (!mTracksCreated) {
    1300           0 :     return;
    1301             :   }
    1302           0 :   nsTArray<nsAutoPtr<OnTracksAvailableCallback> > callbacks;
    1303           0 :   callbacks.SwapElements(mRunOnTracksAvailable);
    1304             : 
    1305           0 :   for (uint32_t i = 0; i < callbacks.Length(); ++i) {
    1306           0 :     callbacks[i]->NotifyTracksAvailable(this);
    1307             :   }
    1308             : }
    1309             : 
    1310             : void
    1311           0 : DOMMediaStream::RegisterTrackListener(TrackListener* aListener)
    1312             : {
    1313           0 :   MOZ_ASSERT(NS_IsMainThread());
    1314             : 
    1315           0 :   if (mNotifiedOfMediaStreamGraphShutdown) {
    1316             :     // No more tracks will ever be added, so just do nothing.
    1317           0 :     return;
    1318             :   }
    1319           0 :   mTrackListeners.AppendElement(aListener);
    1320             : }
    1321             : 
    1322             : void
    1323           0 : DOMMediaStream::UnregisterTrackListener(TrackListener* aListener)
    1324             : {
    1325           0 :   MOZ_ASSERT(NS_IsMainThread());
    1326           0 :   mTrackListeners.RemoveElement(aListener);
    1327           0 : }
    1328             : 
    1329             : void
    1330           0 : DOMMediaStream::NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack)
    1331             : {
    1332           0 :   MOZ_ASSERT(NS_IsMainThread());
    1333             : 
    1334           0 :   if (mTracksPendingRemoval > 0) {
    1335             :     // If there are tracks pending removal we may not degrade the current
    1336             :     // principals until those tracks have been confirmed removed from the
    1337             :     // playback stream. Instead combine with the new track and the (potentially)
    1338             :     // degraded principal will be calculated when it's safe.
    1339           0 :     nsContentUtils::CombineResourcePrincipals(&mPrincipal,
    1340           0 :                                               aTrack->GetPrincipal());
    1341           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p saw a track get added. Combining "
    1342             :                           "its principal %p into our while waiting for pending "
    1343             :                           "tracks to be removed. New principal is %p.",
    1344             :                           this, aTrack->GetPrincipal(), mPrincipal.get()));
    1345           0 :     if (aTrack->AsVideoStreamTrack()) {
    1346           0 :       nsContentUtils::CombineResourcePrincipals(&mVideoPrincipal,
    1347           0 :                                                 aTrack->GetPrincipal());
    1348             :     }
    1349             :   } else {
    1350           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p saw a track get added. "
    1351             :                           "Recomputing principal.", this));
    1352           0 :     RecomputePrincipal();
    1353             :   }
    1354             : 
    1355           0 :   aTrack->AddPrincipalChangeObserver(this);
    1356           0 :   aTrack->AddConsumer(mPlaybackTrackListener);
    1357             : 
    1358           0 :   for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
    1359           0 :     mTrackListeners[i]->NotifyTrackAdded(aTrack);
    1360             :   }
    1361             : 
    1362           0 :   if (mActive) {
    1363           0 :     return;
    1364             :   }
    1365             : 
    1366             :   // Check if we became active.
    1367           0 :   if (ContainsLiveTracks(mTracks)) {
    1368           0 :     mActive = true;
    1369           0 :     NotifyActive();
    1370             :   }
    1371             : }
    1372             : 
    1373             : void
    1374           0 : DOMMediaStream::NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack)
    1375             : {
    1376           0 :   MOZ_ASSERT(NS_IsMainThread());
    1377             : 
    1378           0 :   aTrack->RemoveConsumer(mPlaybackTrackListener);
    1379           0 :   aTrack->RemovePrincipalChangeObserver(this);
    1380             : 
    1381           0 :   for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
    1382           0 :     mTrackListeners[i]->NotifyTrackRemoved(aTrack);
    1383             : 
    1384             :   }
    1385             : 
    1386             :   // Don't call RecomputePrincipal here as the track may still exist in the
    1387             :   // playback stream in the MediaStreamGraph. It will instead be called when the
    1388             :   // track has been confirmed removed by the graph. See BlockPlaybackTrack().
    1389             : 
    1390           0 :   if (!mActive) {
    1391           0 :     NS_ASSERTION(false, "Shouldn't remove a live track if already inactive");
    1392           0 :     return;
    1393             :   }
    1394             : 
    1395           0 :   if (mSetInactiveOnFinish) {
    1396             :     // For compatibility with mozCaptureStream we in some cases do not go
    1397             :     // inactive until the playback stream finishes.
    1398           0 :     return;
    1399             :   }
    1400             : 
    1401             :   // Check if we became inactive.
    1402           0 :   if (!ContainsLiveTracks(mTracks)) {
    1403           0 :     mActive = false;
    1404           0 :     NotifyInactive();
    1405             :   }
    1406             : }
    1407             : 
    1408             : nsresult
    1409           0 : DOMMediaStream::DispatchTrackEvent(const nsAString& aName,
    1410             :                                    const RefPtr<MediaStreamTrack>& aTrack)
    1411             : {
    1412           0 :   MOZ_ASSERT(aName == NS_LITERAL_STRING("addtrack"),
    1413             :              "Only 'addtrack' is supported at this time");
    1414             : 
    1415           0 :   MediaStreamTrackEventInit init;
    1416           0 :   init.mTrack = aTrack;
    1417             : 
    1418             :   RefPtr<MediaStreamTrackEvent> event =
    1419           0 :     MediaStreamTrackEvent::Constructor(this, aName, init);
    1420             : 
    1421           0 :   return DispatchTrustedEvent(event);
    1422             : }
    1423             : 
    1424             : void
    1425           0 : DOMMediaStream::BlockPlaybackTrack(TrackPort* aTrack)
    1426             : {
    1427           0 :   MOZ_ASSERT(aTrack);
    1428           0 :   ++mTracksPendingRemoval;
    1429             :   RefPtr<Pledge<bool>> p =
    1430           0 :     aTrack->BlockSourceTrackId(aTrack->GetTrack()->mTrackID,
    1431           0 :                                BlockingMode::CREATION);
    1432           0 :   RefPtr<DOMMediaStream> self = this;
    1433           0 :   p->Then([self] (const bool& aIgnore) { self->NotifyPlaybackTrackBlocked(); },
    1434           0 :           [] (const nsresult& aIgnore) { NS_ERROR("Could not remove track from MSG"); }
    1435           0 :   );
    1436           0 : }
    1437             : 
    1438             : void
    1439           0 : DOMMediaStream::NotifyPlaybackTrackBlocked()
    1440             : {
    1441           0 :   MOZ_ASSERT(mTracksPendingRemoval > 0,
    1442             :              "A track reported finished blocking more times than we asked for");
    1443           0 :   if (--mTracksPendingRemoval == 0) {
    1444             :     // The MediaStreamGraph has reported a track was blocked and we are not
    1445             :     // waiting for any further tracks to get blocked. It is now safe to
    1446             :     // recompute the principal based on our main thread track set state.
    1447           0 :     LOG(LogLevel::Debug, ("DOMMediaStream %p saw all tracks pending removal "
    1448             :                           "finish. Recomputing principal.", this));
    1449           0 :     RecomputePrincipal();
    1450             :   }
    1451           0 : }
    1452             : 
    1453           0 : DOMLocalMediaStream::~DOMLocalMediaStream()
    1454             : {
    1455           0 :   if (mInputStream) {
    1456             :     // Make sure Listeners of this stream know it's going away
    1457           0 :     StopImpl();
    1458             :   }
    1459           0 : }
    1460             : 
    1461             : JSObject*
    1462           0 : DOMLocalMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
    1463             : {
    1464           0 :   return dom::LocalMediaStreamBinding::Wrap(aCx, this, aGivenProto);
    1465             : }
    1466             : 
    1467             : void
    1468           0 : DOMLocalMediaStream::Stop()
    1469             : {
    1470           0 :   LOG(LogLevel::Debug, ("DOMMediaStream %p Stop()", this));
    1471           0 :   nsCOMPtr<nsPIDOMWindowInner> pWindow = GetParentObject();
    1472           0 :   nsIDocument* document = pWindow ? pWindow->GetExtantDoc() : nullptr;
    1473           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    1474           0 :                                   NS_LITERAL_CSTRING("Media"),
    1475             :                                   document,
    1476             :                                   nsContentUtils::eDOM_PROPERTIES,
    1477           0 :                                   "MediaStreamStopDeprecatedWarning");
    1478             : 
    1479           0 :   StopImpl();
    1480           0 : }
    1481             : 
    1482             : void
    1483           0 : DOMLocalMediaStream::StopImpl()
    1484             : {
    1485           0 :   if (mInputStream && mInputStream->AsSourceStream()) {
    1486           0 :     mInputStream->AsSourceStream()->EndAllTrackAndFinish();
    1487             :   }
    1488           0 : }
    1489             : 
    1490             : already_AddRefed<DOMLocalMediaStream>
    1491           0 : DOMLocalMediaStream::CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
    1492             :                                                MediaStreamGraph* aGraph,
    1493             :                                                MediaStreamTrackSourceGetter* aTrackSourceGetter)
    1494             : {
    1495             :   RefPtr<DOMLocalMediaStream> stream =
    1496           0 :     new DOMLocalMediaStream(aWindow, aTrackSourceGetter);
    1497           0 :   stream->InitSourceStream(aGraph);
    1498           0 :   return stream.forget();
    1499             : }
    1500             : 
    1501             : already_AddRefed<DOMLocalMediaStream>
    1502           0 : DOMLocalMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
    1503             :                                                    MediaStreamGraph* aGraph,
    1504             :                                                    MediaStreamTrackSourceGetter* aTrackSourceGetter)
    1505             : {
    1506             :   RefPtr<DOMLocalMediaStream> stream =
    1507           0 :     new DOMLocalMediaStream(aWindow, aTrackSourceGetter);
    1508           0 :   stream->InitTrackUnionStream(aGraph);
    1509           0 :   return stream.forget();
    1510             : }
    1511             : 
    1512           0 : DOMAudioNodeMediaStream::DOMAudioNodeMediaStream(nsPIDOMWindowInner* aWindow, AudioNode* aNode)
    1513             :   : DOMMediaStream(aWindow, nullptr),
    1514           0 :     mStreamNode(aNode)
    1515             : {
    1516           0 : }
    1517             : 
    1518           0 : DOMAudioNodeMediaStream::~DOMAudioNodeMediaStream()
    1519             : {
    1520           0 : }
    1521             : 
    1522             : already_AddRefed<DOMAudioNodeMediaStream>
    1523           0 : DOMAudioNodeMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
    1524             :                                                        AudioNode* aNode,
    1525             :                                                        MediaStreamGraph* aGraph)
    1526             : {
    1527           0 :   RefPtr<DOMAudioNodeMediaStream> stream = new DOMAudioNodeMediaStream(aWindow, aNode);
    1528           0 :   stream->InitTrackUnionStream(aGraph);
    1529           0 :   return stream.forget();
    1530             : }
    1531             : 
    1532           0 : DOMHwMediaStream::DOMHwMediaStream(nsPIDOMWindowInner* aWindow)
    1533           0 :   : DOMLocalMediaStream(aWindow, nullptr)
    1534             : {
    1535             : #ifdef MOZ_WIDGET_GONK
    1536             :   if (!mWindow) {
    1537             :     NS_ERROR("Expected window here.");
    1538             :     mPrincipalHandle = PRINCIPAL_HANDLE_NONE;
    1539             :     return;
    1540             :   }
    1541             :   nsIDocument* doc = mWindow->GetExtantDoc();
    1542             :   if (!doc) {
    1543             :     NS_ERROR("Expected document here.");
    1544             :     mPrincipalHandle = PRINCIPAL_HANDLE_NONE;
    1545             :     return;
    1546             :   }
    1547             :   mPrincipalHandle = MakePrincipalHandle(doc->NodePrincipal());
    1548             : #endif
    1549           0 : }
    1550             : 
    1551           0 : DOMHwMediaStream::~DOMHwMediaStream()
    1552             : {
    1553           0 : }
    1554             : 
    1555             : already_AddRefed<DOMHwMediaStream>
    1556           0 : DOMHwMediaStream::CreateHwStream(nsPIDOMWindowInner* aWindow,
    1557             :                                  OverlayImage* aImage)
    1558             : {
    1559           0 :   RefPtr<DOMHwMediaStream> stream = new DOMHwMediaStream(aWindow);
    1560             : 
    1561             :   MediaStreamGraph* graph =
    1562             :     MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
    1563           0 :                                   AudioChannel::Normal, aWindow);
    1564           0 :   stream->InitSourceStream(graph);
    1565           0 :   stream->Init(stream->GetInputStream(), aImage);
    1566             : 
    1567           0 :   return stream.forget();
    1568             : }
    1569             : 
    1570             : void
    1571           0 : DOMHwMediaStream::Init(MediaStream* stream, OverlayImage* aImage)
    1572             : {
    1573           0 :   SourceMediaStream* srcStream = stream->AsSourceStream();
    1574             : 
    1575             : #ifdef MOZ_WIDGET_GONK
    1576             :   if (aImage) {
    1577             :     mOverlayImage = aImage;
    1578             :   } else {
    1579             :     Data imageData;
    1580             :     imageData.mOverlayId = DEFAULT_IMAGE_ID;
    1581             :     imageData.mSize.width = DEFAULT_IMAGE_WIDTH;
    1582             :     imageData.mSize.height = DEFAULT_IMAGE_HEIGHT;
    1583             : 
    1584             :     mOverlayImage = new OverlayImage();
    1585             :     mOverlayImage->SetData(imageData);
    1586             :   }
    1587             : #endif
    1588             : 
    1589           0 :   if (srcStream) {
    1590           0 :     VideoSegment segment;
    1591             : #ifdef MOZ_WIDGET_GONK
    1592             :     const StreamTime delta = STREAM_TIME_MAX; // Because MediaStreamGraph will run out frames in non-autoplay mode,
    1593             :                                               // we must give it bigger frame length to cover this situation.
    1594             : 
    1595             :     RefPtr<Image> image = static_cast<Image*>(mOverlayImage.get());
    1596             :     mozilla::gfx::IntSize size = image->GetSize();
    1597             : 
    1598             :     segment.AppendFrame(image.forget(), delta, size, mPrincipalHandle);
    1599             : #endif
    1600           0 :     srcStream->AddTrack(TRACK_VIDEO_PRIMARY, 0, new VideoSegment());
    1601           0 :     srcStream->AppendToTrack(TRACK_VIDEO_PRIMARY, &segment);
    1602           0 :     srcStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
    1603             :   }
    1604           0 : }
    1605             : 
    1606             : int32_t
    1607           0 : DOMHwMediaStream::RequestOverlayId()
    1608             : {
    1609             : #ifdef MOZ_WIDGET_GONK
    1610             :   return mOverlayImage->GetOverlayId();
    1611             : #else
    1612           0 :   return -1;
    1613             : #endif
    1614             : }
    1615             : 
    1616             : void
    1617           0 : DOMHwMediaStream::SetImageSize(uint32_t width, uint32_t height)
    1618             : {
    1619             : #ifdef MOZ_WIDGET_GONK
    1620             :   if (mOverlayImage->GetSidebandStream().IsValid()) {
    1621             :     OverlayImage::SidebandStreamData imgData;
    1622             :     imgData.mStream = mOverlayImage->GetSidebandStream();
    1623             :     imgData.mSize = IntSize(width, height);
    1624             :     mOverlayImage->SetData(imgData);
    1625             :   } else {
    1626             :     OverlayImage::Data imgData;
    1627             :     imgData.mOverlayId = mOverlayImage->GetOverlayId();
    1628             :     imgData.mSize = IntSize(width, height);
    1629             :     mOverlayImage->SetData(imgData);
    1630             :   }
    1631             : #endif
    1632             : 
    1633           0 :   SourceMediaStream* srcStream = GetInputStream()->AsSourceStream();
    1634           0 :   StreamTracks::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
    1635             : 
    1636           0 :   if (!track || !track->GetSegment()) {
    1637           0 :     return;
    1638             :   }
    1639             : 
    1640             : #ifdef MOZ_WIDGET_GONK
    1641             :   // Clear the old segment.
    1642             :   // Changing the existing content of segment is a Very BAD thing, and this way will
    1643             :   // confuse consumers of MediaStreams.
    1644             :   // It is only acceptable for DOMHwMediaStream
    1645             :   // because DOMHwMediaStream doesn't have consumers of TV streams currently.
    1646             :   track->GetSegment()->Clear();
    1647             : 
    1648             :   // Change the image size.
    1649             :   const StreamTime delta = STREAM_TIME_MAX;
    1650             :   RefPtr<Image> image = static_cast<Image*>(mOverlayImage.get());
    1651             :   mozilla::gfx::IntSize size = image->GetSize();
    1652             :   VideoSegment segment;
    1653             : 
    1654             :   segment.AppendFrame(image.forget(), delta, size, mPrincipalHandle);
    1655             :   srcStream->AppendToTrack(TRACK_VIDEO_PRIMARY, &segment);
    1656             : #endif
    1657             : }
    1658             : 
    1659             : void
    1660           0 : DOMHwMediaStream::SetOverlayImage(OverlayImage* aImage)
    1661             : {
    1662           0 :   if (!aImage) {
    1663           0 :     return;
    1664             :   }
    1665             : #ifdef MOZ_WIDGET_GONK
    1666             :   mOverlayImage = aImage;
    1667             : #endif
    1668             : 
    1669           0 :   SourceMediaStream* srcStream = GetInputStream()->AsSourceStream();
    1670           0 :   StreamTracks::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
    1671             : 
    1672           0 :   if (!track || !track->GetSegment()) {
    1673           0 :     return;
    1674             :   }
    1675             : 
    1676             : #ifdef MOZ_WIDGET_GONK
    1677             :   // Clear the old segment.
    1678             :   // Changing the existing content of segment is a Very BAD thing, and this way will
    1679             :   // confuse consumers of MediaStreams.
    1680             :   // It is only acceptable for DOMHwMediaStream
    1681             :   // because DOMHwMediaStream doesn't have consumers of TV streams currently.
    1682             :   track->GetSegment()->Clear();
    1683             : 
    1684             :   // Change the image size.
    1685             :   const StreamTime delta = STREAM_TIME_MAX;
    1686             :   RefPtr<Image> image = static_cast<Image*>(mOverlayImage.get());
    1687             :   mozilla::gfx::IntSize size = image->GetSize();
    1688             :   VideoSegment segment;
    1689             : 
    1690             :   segment.AppendFrame(image.forget(), delta, size, mPrincipalHandle);
    1691             :   srcStream->AppendToTrack(TRACK_VIDEO_PRIMARY, &segment);
    1692             : #endif
    1693             : }
    1694             : 
    1695             : void
    1696           0 : DOMHwMediaStream::SetOverlayId(int32_t aOverlayId)
    1697             : {
    1698             : #ifdef MOZ_WIDGET_GONK
    1699             :   OverlayImage::Data imgData;
    1700             : 
    1701             :   imgData.mOverlayId = aOverlayId;
    1702             :   imgData.mSize = mOverlayImage->GetSize();
    1703             : 
    1704             :   mOverlayImage->SetData(imgData);
    1705             : #endif
    1706           0 : }

Generated by: LCOV version 1.13