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