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 #ifndef NSDOMMEDIASTREAM_H_
7 #define NSDOMMEDIASTREAM_H_
8 
9 #include "ImageContainer.h"
10 
11 #include "nsAutoPtr.h"
12 #include "nsCycleCollectionParticipant.h"
13 #include "nsWrapperCache.h"
14 #include "StreamTracks.h"
15 #include "nsIDOMWindow.h"
16 #include "nsIPrincipal.h"
17 #include "MediaTrackConstraints.h"
18 #include "mozilla/DOMEventTargetHelper.h"
19 #include "mozilla/RelativeTimeline.h"
20 #include "PrincipalChangeObserver.h"
21 
22 // X11 has a #define for CurrentTime. Unbelievable :-(.
23 // See dom/media/webaudio/AudioContext.h for more fun!
24 #ifdef CurrentTime
25 #undef CurrentTime
26 #endif
27 
28 namespace mozilla {
29 
30 class AbstractThread;
31 class DOMLocalMediaStream;
32 class DOMMediaStream;
33 class MediaStream;
34 class MediaInputPort;
35 class MediaStreamGraph;
36 class ProcessedMediaStream;
37 
38 enum class BlockingMode;
39 
40 namespace dom {
41 class AudioNode;
42 class HTMLCanvasElement;
43 class MediaStreamTrack;
44 class MediaStreamTrackSource;
45 class AudioStreamTrack;
46 class VideoStreamTrack;
47 class AudioTrack;
48 class VideoTrack;
49 class AudioTrackList;
50 class VideoTrackList;
51 class MediaTrackListListener;
52 }  // namespace dom
53 
54 namespace layers {
55 class ImageContainer;
56 class OverlayImage;
57 }  // namespace layers
58 
59 namespace media {
60 template <typename V, typename E>
61 class Pledge;
62 }  // namespace media
63 
64 #define NS_DOMMEDIASTREAM_IID                        \
65   {                                                  \
66     0x8cb65468, 0x66c0, 0x444e, {                    \
67       0x89, 0x9f, 0x89, 0x1d, 0x9e, 0xd2, 0xbe, 0x7c \
68     }                                                \
69   }
70 
71 class OnTracksAvailableCallback {
72  public:
~OnTracksAvailableCallback()73   virtual ~OnTracksAvailableCallback() {}
74   virtual void NotifyTracksAvailable(DOMMediaStream* aStream) = 0;
75 };
76 
77 /**
78  * Interface through which a DOMMediaStream can query its producer for a
79  * MediaStreamTrackSource. This will be used whenever a track occurs in the
80  * DOMMediaStream's owned stream that has not yet been created on the main
81  * thread (see DOMMediaStream::CreateOwnDOMTrack).
82  */
83 class MediaStreamTrackSourceGetter : public nsISupports {
84   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSourceGetter)85   NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSourceGetter)
86 
87  public:
88   MediaStreamTrackSourceGetter() {}
89 
90   virtual already_AddRefed<dom::MediaStreamTrackSource>
91   GetMediaStreamTrackSource(TrackID aInputTrackID) = 0;
92 
93  protected:
~MediaStreamTrackSourceGetter()94   virtual ~MediaStreamTrackSourceGetter() {}
95 };
96 
97 /**
98  * DOM wrapper for MediaStreams.
99  *
100  * To account for track operations such as clone(), addTrack() and
101  * removeTrack(), a DOMMediaStream wraps three internal (and chained)
102  * MediaStreams:
103  *   1. mInputStream
104  *      - Controlled by the owner/source of the DOMMediaStream.
105  *        It's a stream of the type indicated by
106  *      - DOMMediaStream::CreateSourceStream/CreateTrackUnionStream. A source
107  *        typically creates its DOMMediaStream, creates the MediaStreamTracks
108  *        owned by said stream, then gets the internal input stream to which it
109  *        feeds data for the previously created tracks.
110  *      - When necessary it can create tracks on the internal stream only and
111  *        their corresponding MediaStreamTracks will be asynchronously created.
112  *   2. mOwnedStream
113  *      - A TrackUnionStream containing tracks owned by this stream.
114  *      - The internal model of a MediaStreamTrack consists of its owning
115  *        DOMMediaStream and the TrackID of the corresponding internal track in
116  *        the owning DOMMediaStream's mOwnedStream.
117  *      - The owned stream is different from the input stream since a cloned
118  *        DOMMediaStream is also the owner of its (cloned) MediaStreamTracks.
119  *      - Stopping an original track shall not stop its clone. This is
120  *        solved by stopping it at the owned stream, while the clone's owned
121  *        stream gets data directly from the original input stream.
122  *      - A DOMMediaStream (original or clone) gets all tracks dynamically
123  *        added by the source automatically forwarded by having a TRACK_ANY
124  *        MediaInputPort set up from the owning DOMMediaStream's input stream
125  *        to this DOMMediaStream's owned stream.
126  *   3. mPlaybackStream
127  *      - A TrackUnionStream containing the tracks corresponding to the
128  *        MediaStreamTracks currently in this DOMMediaStream (per getTracks()).
129  *      - Similarly as for mOwnedStream, there's a TRACK_ANY MediaInputPort set
130  *        up from the owned stream to the playback stream to allow tracks
131  *        dynamically added by the source to be automatically forwarded to any
132  *        audio or video sinks.
133  *      - MediaStreamTracks added by addTrack() are set up with a MediaInputPort
134  *        locked to their internal TrackID, from their owning DOMMediaStream's
135  *        owned stream to this playback stream.
136  *
137  *
138  * A graphical representation of how tracks are connected in various cases as
139  * follows:
140  *
141  *                     addTrack()ed case:
142  * DOMStream A
143  *           Input        Owned          Playback
144  *            t1 ---------> t1 ------------> t1     <- MediaStreamTrack X
145  *                                                     (pointing to t1 in A)
146  *                                 --------> t2     <- MediaStreamTrack Y
147  *                                /                    (pointing to t1 in B)
148  * DOMStream B                   /
149  *           Input        Owned /        Playback
150  *            t1 ---------> t1 ------------> t1     <- MediaStreamTrack Y
151  *                                                     (pointing to t1 in B)
152  *
153  *                     removeTrack()ed case:
154  * DOMStream A
155  *           Input        Owned          Playback
156  *            t1 ---------> t1                      <- No tracks
157  *
158  *
159  *                     clone()d case:
160  * DOMStream A
161  *           Input        Owned          Playback
162  *            t1 ---------> t1 ------------> t1     <- MediaStreamTrack X
163  *               \                                     (pointing to t1 in A)
164  *                -----
165  * DOMStream B         \
166  *           Input      \ Owned          Playback
167  *                       -> t1 ------------> t1     <- MediaStreamTrack Y
168  *                                                     (pointing to t1 in B)
169  *
170  *
171  *            addTrack()ed, removeTrack()ed and clone()d case:
172  *
173  *  Here we have done the following:
174  *    var A = someStreamWithTwoTracks;
175  *    var B = someStreamWithOneTrack;
176  *    var X = A.getTracks()[0];
177  *    var Y = A.getTracks()[1];
178  *    var Z = B.getTracks()[0];
179  *    A.addTrack(Z);
180  *    A.removeTrack(X);
181  *    B.removeTrack(Z);
182  *    var A' = A.clone();
183  *
184  * DOMStream A
185  *           Input        Owned          Playback
186  *            t1 ---------> t1                      <- MediaStreamTrack X
187  *                                                     (removed)
188  *                                                     (pointing to t1 in A)
189  *            t2 ---------> t2 ------------> t2     <- MediaStreamTrack Y
190  *             \                                       (pointing to t2 in A)
191  *              \                    ------> t3     <- MediaStreamTrack Z
192  *               \                  /                  (pointing to t1 in B)
193  * DOMStream B    \                /
194  *           Input \      Owned   /      Playback
195  *            t1 ---^-----> t1 ---                  <- MediaStreamTrack Z
196  *                                                     (removed)
197  *              \    \                                 (pointing to t1 in B)
198  *               \    \
199  * DOMStream A'   \    \
200  *           Input \    \ Owned          Playback
201  *                  \    -> t1 ------------> t1     <- MediaStreamTrack Y'
202  *                   \                                 (pointing to t1 in A')
203  *                    ----> t2 ------------> t2     <- MediaStreamTrack Z'
204  *                                                     (pointing to t2 in A')
205  */
206 class DOMMediaStream
207     : public DOMEventTargetHelper,
208       public dom::PrincipalChangeObserver<dom::MediaStreamTrack>,
209       public RelativeTimeline {
210   friend class DOMLocalMediaStream;
211   friend class dom::MediaStreamTrack;
212   typedef dom::MediaStreamTrack MediaStreamTrack;
213   typedef dom::AudioStreamTrack AudioStreamTrack;
214   typedef dom::VideoStreamTrack VideoStreamTrack;
215   typedef dom::MediaStreamTrackSource MediaStreamTrackSource;
216   typedef dom::AudioTrack AudioTrack;
217   typedef dom::VideoTrack VideoTrack;
218   typedef dom::AudioTrackList AudioTrackList;
219   typedef dom::VideoTrackList VideoTrackList;
220 
221  public:
222   typedef dom::MediaTrackConstraints MediaTrackConstraints;
223 
224   class TrackListener {
225    public:
~TrackListener()226     virtual ~TrackListener() {}
227 
228     /**
229      * Called when the DOMMediaStream has a live track added, either by
230      * script (addTrack()) or the source creating one.
231      */
NotifyTrackAdded(const RefPtr<MediaStreamTrack> & aTrack)232     virtual void NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack){};
233 
234     /**
235      * Called when the DOMMediaStream removes a live track from playback, either
236      * by script (removeTrack(), track.stop()) or the source ending it.
237      */
NotifyTrackRemoved(const RefPtr<MediaStreamTrack> & aTrack)238     virtual void NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack){};
239 
240     /**
241      * Called when the DOMMediaStream has become active.
242      */
NotifyActive()243     virtual void NotifyActive(){};
244 
245     /**
246      * Called when the DOMMediaStream has become inactive.
247      */
NotifyInactive()248     virtual void NotifyInactive(){};
249   };
250 
251   /**
252    * TrackPort is a representation of a MediaStreamTrack-MediaInputPort pair
253    * that make up a link between the Owned stream and the Playback stream.
254    *
255    * Semantically, the track is the identifier/key and the port the value of
256    * this connection.
257    *
258    * The input port can be shared between several TrackPorts. This is the case
259    * for DOMMediaStream's mPlaybackPort which forwards all tracks in its
260    * mOwnedStream automatically.
261    *
262    * If the MediaStreamTrack is owned by another DOMMediaStream (called A) than
263    * the one owning the TrackPort (called B), the input port (locked to the
264    * MediaStreamTrack's TrackID) connects A's mOwnedStream to B's
265    * mPlaybackStream.
266    *
267    * A TrackPort may never leave the DOMMediaStream it was created in. Internal
268    * use only.
269    */
270   class TrackPort {
271    public:
272     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TrackPort)
273     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(TrackPort)
274 
275     /**
276      * Indicates MediaInputPort ownership to the TrackPort.
277      *
278      * OWNED    - Owned by the TrackPort itself. TrackPort must destroy the
279      *            input port when it's destructed.
280      * EXTERNAL - Owned by another entity. It's the caller's responsibility to
281      *            ensure the the MediaInputPort outlives the TrackPort.
282      */
283     enum class InputPortOwnership { OWNED = 1, EXTERNAL };
284 
285     TrackPort(MediaInputPort* aInputPort, MediaStreamTrack* aTrack,
286               const InputPortOwnership aOwnership);
287 
288    protected:
289     virtual ~TrackPort();
290 
291    public:
292     void DestroyInputPort();
293 
294     /**
295      * Returns the source stream of the input port.
296      */
297     MediaStream* GetSource() const;
298 
299     /**
300      * Returns the track ID this track is locked to in the source stream of the
301      * input port.
302      */
303     TrackID GetSourceTrackId() const;
304 
GetInputPort()305     MediaInputPort* GetInputPort() const { return mInputPort; }
GetTrack()306     MediaStreamTrack* GetTrack() const { return mTrack; }
307 
308     /**
309      * Blocks aTrackId from going into mInputPort unless the port has been
310      * destroyed. Returns a pledge that gets resolved when the MediaStreamGraph
311      * has applied the block in the playback stream.
312      */
313     already_AddRefed<media::Pledge<bool, nsresult>> BlockSourceTrackId(
314         TrackID aTrackId, BlockingMode aBlockingMode);
315 
316    private:
317     RefPtr<MediaInputPort> mInputPort;
318     RefPtr<MediaStreamTrack> mTrack;
319 
320     // Defines if we've been given ownership of the input port or if it's owned
321     // externally. The owner is responsible for destroying the port.
322     const InputPortOwnership mOwnership;
323   };
324 
325   DOMMediaStream(nsPIDOMWindowInner* aWindow,
326                  MediaStreamTrackSourceGetter* aTrackSourceGetter);
327 
328   NS_DECL_ISUPPORTS_INHERITED
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)329   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
330   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMMediaStream, DOMEventTargetHelper)
331   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMMEDIASTREAM_IID)
332 
333   nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
334   virtual JSObject* WrapObject(JSContext* aCx,
335                                JS::Handle<JSObject*> aGivenProto) override;
336 
337   // WebIDL
338 
339   static already_AddRefed<DOMMediaStream> Constructor(
340       const dom::GlobalObject& aGlobal, ErrorResult& aRv);
341 
342   static already_AddRefed<DOMMediaStream> Constructor(
343       const dom::GlobalObject& aGlobal, const DOMMediaStream& aStream,
344       ErrorResult& aRv);
345 
346   static already_AddRefed<DOMMediaStream> Constructor(
347       const dom::GlobalObject& aGlobal,
348       const dom::Sequence<OwningNonNull<MediaStreamTrack>>& aTracks,
349       ErrorResult& aRv);
350 
351   double CurrentTime();
352 
353   static already_AddRefed<dom::Promise> CountUnderlyingStreams(
354       const dom::GlobalObject& aGlobal, ErrorResult& aRv);
355 
356   void GetId(nsAString& aID) const;
357 
358   void GetAudioTracks(nsTArray<RefPtr<AudioStreamTrack>>& aTracks) const;
359   void GetVideoTracks(nsTArray<RefPtr<VideoStreamTrack>>& aTracks) const;
360   void GetTracks(nsTArray<RefPtr<MediaStreamTrack>>& aTracks) const;
361   MediaStreamTrack* GetTrackById(const nsAString& aId) const;
362   void AddTrack(MediaStreamTrack& aTrack);
363   void RemoveTrack(MediaStreamTrack& aTrack);
364 
365   /** Identical to CloneInternal(TrackForwardingOption::EXPLICIT) */
366   already_AddRefed<DOMMediaStream> Clone();
367 
368   bool Active() const;
369 
370   IMPL_EVENT_HANDLER(addtrack)
371   IMPL_EVENT_HANDLER(removetrack)
372 
373   // NON-WebIDL
374 
375   /**
376    * Option to provide to CloneInternal() of which tracks should be forwarded
377    * from the source stream (`this`) to the returned stream clone.
378    *
379    * CURRENT forwards the tracks currently in the source stream's track set.
380    * ALL     forwards like EXPLICIT plus any and all future tracks originating
381    *         from the same input stream as the source DOMMediaStream (`this`).
382    */
383   enum class TrackForwardingOption { CURRENT, ALL };
384   already_AddRefed<DOMMediaStream> CloneInternal(
385       TrackForwardingOption aForwarding);
386 
387   MediaStreamTrack* GetOwnedTrackById(const nsAString& aId);
388 
389   /**
390    * Returns true if this DOMMediaStream has aTrack in its mPlaybackStream.
391    */
392   bool HasTrack(const MediaStreamTrack& aTrack) const;
393 
394   /**
395    * Returns true if this DOMMediaStream owns aTrack.
396    */
397   bool OwnsTrack(const MediaStreamTrack& aTrack) const;
398 
399   /**
400    * Returns the corresponding MediaStreamTrack if it's in our mOwnedStream.
401    * aInputTrackID should match the track's TrackID in its input stream,
402    * and aTrackID the TrackID in mOwnedStream.
403    *
404    * When aTrackID is not supplied or set to TRACK_ANY, we return the first
405    * MediaStreamTrack that matches the given input track. Note that there may
406    * be multiple MediaStreamTracks matching the same input track, but that they
407    * in that case all share the same MediaStreamTrackSource.
408    */
409   MediaStreamTrack* FindOwnedDOMTrack(MediaStream* aInputStream,
410                                       TrackID aInputTrackID,
411                                       TrackID aTrackID = TRACK_ANY) const;
412 
413   /**
414    * Returns the TrackPort connecting aTrack's input stream to mOwnedStream,
415    * or nullptr if aTrack is not owned by this DOMMediaStream.
416    */
417   TrackPort* FindOwnedTrackPort(const MediaStreamTrack& aTrack) const;
418 
419   /**
420    * Returns the corresponding MediaStreamTrack if it's in our mPlaybackStream.
421    * aInputTrackID should match the track's TrackID in its owned stream.
422    */
423   MediaStreamTrack* FindPlaybackDOMTrack(MediaStream* aInputStream,
424                                          TrackID aInputTrackID) const;
425 
426   /**
427    * Returns the TrackPort connecting mOwnedStream to mPlaybackStream for
428    * aTrack.
429    */
430   TrackPort* FindPlaybackTrackPort(const MediaStreamTrack& aTrack) const;
431 
GetInputStream()432   MediaStream* GetInputStream() const { return mInputStream; }
GetOwnedStream()433   ProcessedMediaStream* GetOwnedStream() const { return mOwnedStream; }
GetPlaybackStream()434   ProcessedMediaStream* GetPlaybackStream() const { return mPlaybackStream; }
435 
436   /**
437    * Allows a video element to identify this stream as a camera stream, which
438    * needs special treatment.
439    */
GetCameraStream()440   virtual MediaStream* GetCameraStream() const { return nullptr; }
441 
442   /**
443    * Legacy method that returns true when the playback stream has finished.
444    */
445   bool IsFinished() const;
446 
447   /**
448    * Becomes inactive only when the playback stream has finished.
449    */
450   void SetInactiveOnFinish();
451 
452   TrackRate GraphRate();
453 
454   /**
455    * Returns a principal indicating who may access this stream. The stream
456    * contents can only be accessed by principals subsuming this principal.
457    */
GetPrincipal()458   nsIPrincipal* GetPrincipal() { return mPrincipal; }
459 
460   /**
461    * Returns a principal indicating who may access video data of this stream.
462    * The video principal will be a combination of all live video tracks.
463    */
GetVideoPrincipal()464   nsIPrincipal* GetVideoPrincipal() { return mVideoPrincipal; }
465 
466   // From PrincipalChangeObserver<MediaStreamTrack>.
467   void PrincipalChanged(MediaStreamTrack* aTrack) override;
468 
469   /**
470    * Add a PrincipalChangeObserver to this stream.
471    *
472    * Returns true if it was successfully added.
473    *
474    * Ownership of the PrincipalChangeObserver remains with the caller, and it's
475    * the caller's responsibility to remove the observer before it dies.
476    */
477   bool AddPrincipalChangeObserver(
478       dom::PrincipalChangeObserver<DOMMediaStream>* aObserver);
479 
480   /**
481    * Remove an added PrincipalChangeObserver from this stream.
482    *
483    * Returns true if it was successfully removed.
484    */
485   bool RemovePrincipalChangeObserver(
486       dom::PrincipalChangeObserver<DOMMediaStream>* aObserver);
487 
488   // Webrtc allows the remote side to name a stream whatever it wants, and we
489   // need to surface this to content.
AssignId(const nsAString & aID)490   void AssignId(const nsAString& aID) { mID = aID; }
491 
492   /**
493    * Create a DOMMediaStream whose underlying input stream is a
494    * SourceMediaStream.
495    */
496   static already_AddRefed<DOMMediaStream> CreateSourceStreamAsInput(
497       nsPIDOMWindowInner* aWindow, MediaStreamGraph* aGraph,
498       MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
499 
500   /**
501    * Create a DOMMediaStream whose underlying input stream is a
502    * TrackUnionStream.
503    */
504   static already_AddRefed<DOMMediaStream> CreateTrackUnionStreamAsInput(
505       nsPIDOMWindowInner* aWindow, MediaStreamGraph* aGraph,
506       MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
507 
508   /**
509    * Create an DOMMediaStream whose underlying input stream is an
510    * AudioCaptureStream.
511    */
512   static already_AddRefed<DOMMediaStream> CreateAudioCaptureStreamAsInput(
513       nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
514       MediaStreamGraph* aGraph);
515 
SetLogicalStreamStartTime(StreamTime aTime)516   void SetLogicalStreamStartTime(StreamTime aTime) {
517     mLogicalStreamStartTime = aTime;
518   }
519 
520   /**
521    * Adds a MediaStreamTrack to mTracks and raises "addtrack".
522    *
523    * Note that "addtrack" is raised synchronously and only has an effect if
524    * this MediaStream is already exposed to script. For spec compliance this is
525    * to be called from an async task.
526    */
527   void AddTrackInternal(MediaStreamTrack* aTrack);
528 
529   /**
530    * Called for each track in our owned stream to indicate to JS that we
531    * are carrying that track.
532    *
533    * Pre-creates a MediaStreamTrack and returns it.
534    * It is up to the caller to make sure it is added through AddTrackInternal.
535    */
536   already_AddRefed<MediaStreamTrack> CreateDOMTrack(
537       TrackID aTrackID, MediaSegment::Type aType,
538       MediaStreamTrackSource* aSource,
539       const MediaTrackConstraints& aConstraints = MediaTrackConstraints());
540 
541   /**
542    * Creates a MediaStreamTrack cloned from aTrack, adds it to mTracks and
543    * returns it.
544    * aCloneTrackID is the TrackID the new track will get in mOwnedStream.
545    */
546   already_AddRefed<MediaStreamTrack> CloneDOMTrack(MediaStreamTrack& aTrack,
547                                                    TrackID aCloneTrackID);
548 
549   // When the initial set of tracks has been added, run
550   // aCallback->NotifyTracksAvailable.
551   // It is allowed to do anything, including run script.
552   // aCallback may run immediately during this call if tracks are already
553   // available!
554   // We only care about track additions, we'll fire the notification even if
555   // some of the tracks have been removed.
556   // Takes ownership of aCallback.
557   void OnTracksAvailable(OnTracksAvailableCallback* aCallback);
558 
559   /**
560    * Add an nsISupports object that this stream will keep alive as long as
561    * the stream itself is alive.
562    */
AddConsumerToKeepAlive(nsISupports * aConsumer)563   void AddConsumerToKeepAlive(nsISupports* aConsumer) {
564     mConsumersToKeepAlive.AppendElement(aConsumer);
565   }
566 
567   // Registers a track listener to this MediaStream, for listening to changes
568   // to our track set. The caller must call UnregisterTrackListener before
569   // being destroyed, so we don't hold on to a dead pointer. Main thread only.
570   void RegisterTrackListener(TrackListener* aListener);
571 
572   // Unregisters a track listener from this MediaStream. The caller must call
573   // UnregisterTrackListener before being destroyed, so we don't hold on to
574   // a dead pointer. Main thread only.
575   void UnregisterTrackListener(TrackListener* aListener);
576 
577  protected:
578   virtual ~DOMMediaStream();
579 
580   void Destroy();
581   void InitSourceStream(MediaStreamGraph* aGraph);
582   void InitTrackUnionStream(MediaStreamGraph* aGraph);
583   void InitAudioCaptureStream(nsIPrincipal* aPrincipal,
584                               MediaStreamGraph* aGraph);
585 
586   // Sets up aStream as mInputStream. A producer may append data to a
587   // SourceMediaStream input stream, or connect another stream to a
588   // TrackUnionStream input stream.
589   void InitInputStreamCommon(MediaStream* aStream, MediaStreamGraph* aGraph);
590 
591   // Sets up a new TrackUnionStream as mOwnedStream and connects it to
592   // mInputStream with a TRACK_ANY MediaInputPort if available.
593   // If this DOMMediaStream should have an input stream (producing data),
594   // it has to be initiated before the owned stream.
595   void InitOwnedStreamCommon(MediaStreamGraph* aGraph);
596 
597   // Sets up a new TrackUnionStream as mPlaybackStream and connects it to
598   // mOwnedStream with a TRACK_ANY MediaInputPort if available.
599   // If this DOMMediaStream should have an owned stream (producer or clone),
600   // it has to be initiated before the playback stream.
601   void InitPlaybackStreamCommon(MediaStreamGraph* aGraph);
602 
603   void CheckTracksAvailable();
604 
605   // Called when MediaStreamGraph has finished an iteration where tracks were
606   // created.
607   void NotifyTracksCreated();
608 
609   // Called when our playback stream has finished in the MediaStreamGraph.
610   void NotifyFinished();
611 
612   // Dispatches NotifyActive() to all registered track listeners.
613   void NotifyActive();
614 
615   // Dispatches NotifyInactive() to all registered track listeners.
616   void NotifyInactive();
617 
618   // Dispatches NotifyTrackAdded() to all registered track listeners.
619   void NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack);
620 
621   // Dispatches NotifyTrackRemoved() to all registered track listeners.
622   void NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack);
623 
624   // Dispatches "addtrack" or "removetrack".
625   nsresult DispatchTrackEvent(const nsAString& aName,
626                               const RefPtr<MediaStreamTrack>& aTrack);
627 
628   class OwnedStreamListener;
629   friend class OwnedStreamListener;
630 
631   class PlaybackStreamListener;
632   friend class PlaybackStreamListener;
633 
634   class PlaybackTrackListener;
635   friend class PlaybackTrackListener;
636 
637   /**
638    * Block a track in our playback stream. Calls NotifyPlaybackTrackBlocked()
639    * after the MediaStreamGraph has applied the block and the track is no longer
640    * live.
641    */
642   void BlockPlaybackTrack(TrackPort* aTrack);
643 
644   /**
645    * Called on main thread after MediaStreamGraph has applied a track block in
646    * our playback stream.
647    */
648   void NotifyPlaybackTrackBlocked();
649 
650   // Recomputes the current principal of this stream based on the set of tracks
651   // it currently contains. PrincipalChangeObservers will be notified only if
652   // the principal changes.
653   void RecomputePrincipal();
654 
655   // StreamTime at which the currentTime attribute would return 0.
656   StreamTime mLogicalStreamStartTime;
657 
658   // We need this to track our parent object.
659   nsCOMPtr<nsPIDOMWindowInner> mWindow;
660 
661   // MediaStreams are owned by the graph, but we tell them when to die,
662   // and they won't die until we let them.
663 
664   // This stream contains tracks used as input by us. Cloning happens from this
665   // stream. Tracks may exist in these stream but not in |mOwnedStream| if they
666   // have been stopped.
667   MediaStream* mInputStream;
668 
669   // This stream contains tracks owned by us (if we were created directly from
670   // source, or cloned from some other stream). Tracks map to |mOwnedTracks|.
671   ProcessedMediaStream* mOwnedStream;
672 
673   // This stream contains tracks currently played by us, despite of owner.
674   // Tracks map to |mTracks|.
675   ProcessedMediaStream* mPlaybackStream;
676 
677   // This port connects mInputStream to mOwnedStream. All tracks forwarded.
678   RefPtr<MediaInputPort> mOwnedPort;
679 
680   // This port connects mOwnedStream to mPlaybackStream. All tracks not
681   // explicitly blocked due to removal are forwarded.
682   RefPtr<MediaInputPort> mPlaybackPort;
683 
684   // MediaStreamTracks corresponding to tracks in our mOwnedStream.
685   AutoTArray<RefPtr<TrackPort>, 2> mOwnedTracks;
686 
687   // MediaStreamTracks corresponding to tracks in our mPlaybackStream.
688   AutoTArray<RefPtr<TrackPort>, 2> mTracks;
689 
690   // Number of MediaStreamTracks that have been removed on main thread but are
691   // waiting to be removed on MediaStreamGraph thread.
692   size_t mTracksPendingRemoval;
693 
694   // The interface through which we can query the stream producer for
695   // track sources.
696   RefPtr<MediaStreamTrackSourceGetter> mTrackSourceGetter;
697 
698   // Listener tracking changes to mOwnedStream. We use this to notify the
699   // MediaStreamTracks we own about state changes.
700   RefPtr<OwnedStreamListener> mOwnedListener;
701 
702   // Listener tracking changes to mPlaybackStream. This drives state changes
703   // in this DOMMediaStream and notifications to mTrackListeners.
704   RefPtr<PlaybackStreamListener> mPlaybackListener;
705 
706   // Listener tracking when live MediaStreamTracks in mTracks end.
707   RefPtr<PlaybackTrackListener> mPlaybackTrackListener;
708 
709   nsTArray<nsAutoPtr<OnTracksAvailableCallback>> mRunOnTracksAvailable;
710 
711   // Set to true after MediaStreamGraph has created tracks for mPlaybackStream.
712   bool mTracksCreated;
713 
714   nsString mID;
715 
716   // Keep these alive while the stream is alive.
717   nsTArray<nsCOMPtr<nsISupports>> mConsumersToKeepAlive;
718 
719   bool mNotifiedOfMediaStreamGraphShutdown;
720 
721   // The track listeners subscribe to changes in this stream's track set.
722   nsTArray<TrackListener*> mTrackListeners;
723 
724   // True if this stream has live tracks.
725   bool mActive;
726 
727   // True if this stream only sets mActive to false when its playback stream
728   // finishes. This is a hack to maintain legacy functionality for playing a
729   // HTMLMediaElement::MozCaptureStream(). See bug 1302379.
730   bool mSetInactiveOnFinish;
731 
732  private:
733   void NotifyPrincipalChanged();
734   // Principal identifying who may access the collected contents of this stream.
735   // If null, this stream can be used by anyone because it has no content yet.
736   nsCOMPtr<nsIPrincipal> mPrincipal;
737   // Video principal is used by video element as access is requested to its
738   // image data.
739   nsCOMPtr<nsIPrincipal> mVideoPrincipal;
740   nsTArray<dom::PrincipalChangeObserver<DOMMediaStream>*>
741       mPrincipalChangeObservers;
742   CORSMode mCORSMode;
743 };
744 
NS_DEFINE_STATIC_IID_ACCESSOR(DOMMediaStream,NS_DOMMEDIASTREAM_IID)745 NS_DEFINE_STATIC_IID_ACCESSOR(DOMMediaStream, NS_DOMMEDIASTREAM_IID)
746 
747 #define NS_DOMLOCALMEDIASTREAM_IID                   \
748   {                                                  \
749     0xb1437260, 0xec61, 0x4dfa, {                    \
750       0x92, 0x54, 0x04, 0x44, 0xe2, 0xb5, 0x94, 0x9c \
751     }                                                \
752   }
753 
754 class DOMLocalMediaStream : public DOMMediaStream {
755  public:
756   explicit DOMLocalMediaStream(nsPIDOMWindowInner* aWindow,
757                                MediaStreamTrackSourceGetter* aTrackSourceGetter)
758       : DOMMediaStream(aWindow, aTrackSourceGetter) {}
759 
760   NS_DECL_ISUPPORTS_INHERITED
761   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMLOCALMEDIASTREAM_IID)
762 
763   virtual JSObject* WrapObject(JSContext* aCx,
764                                JS::Handle<JSObject*> aGivenProto) override;
765 
766   void Stop();
767 
768   /**
769    * Create an nsDOMLocalMediaStream whose underlying stream is a
770    * SourceMediaStream.
771    */
772   static already_AddRefed<DOMLocalMediaStream> CreateSourceStreamAsInput(
773       nsPIDOMWindowInner* aWindow, MediaStreamGraph* aGraph,
774       MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
775 
776   /**
777    * Create an nsDOMLocalMediaStream whose underlying stream is a
778    * TrackUnionStream.
779    */
780   static already_AddRefed<DOMLocalMediaStream> CreateTrackUnionStreamAsInput(
781       nsPIDOMWindowInner* aWindow, MediaStreamGraph* aGraph,
782       MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
783 
784  protected:
785   virtual ~DOMLocalMediaStream();
786 
787   void StopImpl();
788 };
789 
NS_DEFINE_STATIC_IID_ACCESSOR(DOMLocalMediaStream,NS_DOMLOCALMEDIASTREAM_IID)790 NS_DEFINE_STATIC_IID_ACCESSOR(DOMLocalMediaStream, NS_DOMLOCALMEDIASTREAM_IID)
791 
792 class DOMAudioNodeMediaStream : public DOMMediaStream {
793   typedef dom::AudioNode AudioNode;
794 
795  public:
796   DOMAudioNodeMediaStream(nsPIDOMWindowInner* aWindow, AudioNode* aNode);
797 
798   NS_DECL_ISUPPORTS_INHERITED
799   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMAudioNodeMediaStream,
800                                            DOMMediaStream)
801 
802   /**
803    * Create a DOMAudioNodeMediaStream whose underlying stream is a
804    * TrackUnionStream.
805    */
806   static already_AddRefed<DOMAudioNodeMediaStream>
807   CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow, AudioNode* aNode,
808                                 MediaStreamGraph* aGraph);
809 
810  protected:
811   ~DOMAudioNodeMediaStream();
812 
813  private:
814   // If this object wraps a stream owned by an AudioNode, we need to ensure that
815   // the node isn't cycle-collected too early.
816   RefPtr<AudioNode> mStreamNode;
817 };
818 
819 }  // namespace mozilla
820 
821 #endif /* NSDOMMEDIASTREAM_H_ */
822