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 : #ifndef MEDIASTREAMTRACK_H_
7 : #define MEDIASTREAMTRACK_H_
8 :
9 : #include "MediaTrackConstraints.h"
10 : #include "PrincipalChangeObserver.h"
11 : #include "StreamTracks.h"
12 : #include "mozilla/CORSMode.h"
13 : #include "mozilla/DOMEventTargetHelper.h"
14 : #include "mozilla/dom/MediaStreamTrackBinding.h"
15 : #include "mozilla/dom/MediaTrackSettingsBinding.h"
16 : #include "mozilla/media/MediaUtils.h"
17 : #include "nsError.h"
18 : #include "nsID.h"
19 : #include "nsIPrincipal.h"
20 :
21 : namespace mozilla {
22 :
23 : class DOMMediaStream;
24 : class MediaEnginePhotoCallback;
25 : class MediaInputPort;
26 : class MediaStream;
27 : class MediaStreamGraph;
28 : class MediaStreamGraphImpl;
29 : class MediaStreamTrackListener;
30 : class DirectMediaStreamTrackListener;
31 : class PeerConnectionImpl;
32 : class PeerConnectionMedia;
33 : class PeerIdentity;
34 : class ProcessedMediaStream;
35 : class RemoteSourceStreamInfo;
36 : class SourceStreamInfo;
37 :
38 : namespace dom {
39 :
40 : class AudioStreamTrack;
41 : class VideoStreamTrack;
42 : class MediaStreamError;
43 : enum class CallerType : uint32_t;
44 :
45 : /**
46 : * Common interface through which a MediaStreamTrack can communicate with its
47 : * producer on the main thread.
48 : *
49 : * Kept alive by a strong ref in all MediaStreamTracks (original and clones)
50 : * sharing this source.
51 : */
52 : class MediaStreamTrackSource : public nsISupports
53 : {
54 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
55 0 : NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource)
56 :
57 : public:
58 0 : class Sink
59 : {
60 : public:
61 : virtual void PrincipalChanged() = 0;
62 : };
63 :
64 0 : MediaStreamTrackSource(nsIPrincipal* aPrincipal,
65 : const nsString& aLabel)
66 0 : : mPrincipal(aPrincipal),
67 : mLabel(aLabel),
68 0 : mStopped(false)
69 : {
70 0 : }
71 :
72 : /**
73 : * Use to clean up any resources that have to be cleaned before the
74 : * destructor is called. It is often too late in the destructor because
75 : * of garbage collection having removed the members already.
76 : */
77 0 : virtual void Destroy() {}
78 :
79 : /**
80 : * Gets the source's MediaSourceEnum for usage by PeerConnections.
81 : */
82 : virtual MediaSourceEnum GetMediaSource() const = 0;
83 :
84 : /**
85 : * Get this TrackSource's principal.
86 : */
87 0 : nsIPrincipal* GetPrincipal() const { return mPrincipal; }
88 :
89 : /**
90 : * Get the source's current CORSMode. If not applicable CORS_NONE is returned.
91 : * The sink will be notified of changes to our CORSMode through
92 : * PrincipalChanged().
93 : */
94 0 : virtual CORSMode GetCORSMode() const { return CORS_NONE; }
95 :
96 : /**
97 : * This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot
98 : * be sent across the network to anything other than a peer with the provided
99 : * identity. If this is set, then GetPrincipal() should return an instance of
100 : * NullPrincipal.
101 : *
102 : * A track's PeerIdentity is immutable and will not change during the track's
103 : * lifetime.
104 : */
105 0 : virtual const PeerIdentity* GetPeerIdentity() const { return nullptr; }
106 :
107 : /**
108 : * MediaStreamTrack::GetLabel (see spec) calls through to here.
109 : */
110 0 : void GetLabel(nsAString& aLabel) { aLabel.Assign(mLabel); }
111 :
112 : /**
113 : * Forwards a photo request to backends that support it. Other backends return
114 : * NS_ERROR_NOT_IMPLEMENTED to indicate that a MediaStreamGraph-based fallback
115 : * should be used.
116 : */
117 0 : virtual nsresult TakePhoto(MediaEnginePhotoCallback*) const { return NS_ERROR_NOT_IMPLEMENTED; }
118 :
119 : typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid;
120 :
121 : /**
122 : * We provide a fallback solution to ApplyConstraints() here.
123 : * Sources that support ApplyConstraints() will have to override it.
124 : */
125 : virtual already_AddRefed<PledgeVoid>
126 : ApplyConstraints(nsPIDOMWindowInner* aWindow,
127 : const dom::MediaTrackConstraints& aConstraints,
128 : CallerType aCallerType);
129 :
130 : /**
131 : * Same for GetSettings (no-op).
132 : */
133 : virtual void
134 0 : GetSettings(dom::MediaTrackSettings& aResult) {};
135 :
136 : /**
137 : * Called by the source interface when all registered sinks have unregistered.
138 : */
139 : virtual void Stop() = 0;
140 :
141 : /**
142 : * Called by each MediaStreamTrack clone on initialization.
143 : */
144 0 : void RegisterSink(Sink* aSink)
145 : {
146 0 : MOZ_ASSERT(NS_IsMainThread());
147 0 : if (mStopped) {
148 0 : return;
149 : }
150 0 : mSinks.AppendElement(aSink);
151 : }
152 :
153 : /**
154 : * Called by each MediaStreamTrack clone on Stop() if supported by the
155 : * source (us) or destruction.
156 : */
157 0 : void UnregisterSink(Sink* aSink)
158 : {
159 0 : MOZ_ASSERT(NS_IsMainThread());
160 0 : if (mSinks.RemoveElement(aSink) && mSinks.IsEmpty()) {
161 0 : MOZ_ASSERT(!mStopped);
162 0 : Stop();
163 0 : mStopped = true;
164 : }
165 0 : }
166 :
167 : protected:
168 0 : virtual ~MediaStreamTrackSource()
169 0 : {
170 0 : }
171 :
172 : /**
173 : * Called by a sub class when the principal has changed.
174 : * Notifies all sinks.
175 : */
176 0 : void PrincipalChanged()
177 : {
178 0 : for (Sink* sink : mSinks) {
179 0 : sink->PrincipalChanged();
180 : }
181 0 : }
182 :
183 : // Principal identifying who may access the contents of this source.
184 : nsCOMPtr<nsIPrincipal> mPrincipal;
185 :
186 : // Currently registered sinks.
187 : nsTArray<Sink*> mSinks;
188 :
189 : // The label of the track we are the source of per the MediaStreamTrack spec.
190 : const nsString mLabel;
191 :
192 : // True if all MediaStreamTrack users have unregistered from this source and
193 : // Stop() has been called.
194 : bool mStopped;
195 : };
196 :
197 : /**
198 : * Basic implementation of MediaStreamTrackSource that doesn't forward Stop().
199 : */
200 : class BasicTrackSource : public MediaStreamTrackSource
201 : {
202 : public:
203 0 : explicit BasicTrackSource(nsIPrincipal* aPrincipal,
204 : const MediaSourceEnum aMediaSource =
205 : MediaSourceEnum::Other)
206 0 : : MediaStreamTrackSource(aPrincipal, nsString())
207 0 : , mMediaSource(aMediaSource)
208 0 : {}
209 :
210 0 : MediaSourceEnum GetMediaSource() const override { return mMediaSource; }
211 :
212 0 : void Stop() override {}
213 :
214 : protected:
215 0 : ~BasicTrackSource() {}
216 :
217 : const MediaSourceEnum mMediaSource;
218 : };
219 :
220 : /**
221 : * Base class that consumers of a MediaStreamTrack can use to get notifications
222 : * about state changes in the track.
223 : */
224 0 : class MediaStreamTrackConsumer : public nsISupports
225 : {
226 : public:
227 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
228 0 : NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackConsumer)
229 :
230 : /**
231 : * Called when the track's readyState transitions to "ended".
232 : * Unlike the "ended" event exposed to script this is called for any reason,
233 : * including MediaStreamTrack::Stop().
234 : */
235 0 : virtual void NotifyEnded(MediaStreamTrack* aTrack) {};
236 :
237 : protected:
238 0 : virtual ~MediaStreamTrackConsumer() {}
239 : };
240 :
241 : /**
242 : * Class representing a track in a DOMMediaStream.
243 : */
244 : class MediaStreamTrack : public DOMEventTargetHelper,
245 : public MediaStreamTrackSource::Sink
246 : {
247 : // DOMMediaStream owns MediaStreamTrack instances, and requires access to
248 : // some internal state, e.g., GetInputStream(), GetOwnedStream().
249 : friend class mozilla::DOMMediaStream;
250 :
251 : // PeerConnection and friends need to know our owning DOMStream and track id.
252 : friend class mozilla::PeerConnectionImpl;
253 : friend class mozilla::PeerConnectionMedia;
254 : friend class mozilla::SourceStreamInfo;
255 : friend class mozilla::RemoteSourceStreamInfo;
256 :
257 : class PrincipalHandleListener;
258 :
259 : public:
260 : /**
261 : * aTrackID is the MediaStreamGraph track ID for the track in the
262 : * MediaStream owned by aStream.
263 : */
264 : MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
265 : TrackID aInputTrackID,
266 : MediaStreamTrackSource* aSource,
267 : const MediaTrackConstraints& aConstraints = MediaTrackConstraints());
268 :
269 : NS_DECL_ISUPPORTS_INHERITED
270 0 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrack,
271 : DOMEventTargetHelper)
272 :
273 : nsPIDOMWindowInner* GetParentObject() const;
274 : virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override = 0;
275 :
276 0 : virtual AudioStreamTrack* AsAudioStreamTrack() { return nullptr; }
277 0 : virtual VideoStreamTrack* AsVideoStreamTrack() { return nullptr; }
278 :
279 0 : virtual const AudioStreamTrack* AsAudioStreamTrack() const { return nullptr; }
280 0 : virtual const VideoStreamTrack* AsVideoStreamTrack() const { return nullptr; }
281 :
282 : // WebIDL
283 : virtual void GetKind(nsAString& aKind) = 0;
284 : void GetId(nsAString& aID) const;
285 0 : void GetLabel(nsAString& aLabel) { GetSource().GetLabel(aLabel); }
286 0 : bool Enabled() { return mEnabled; }
287 : void SetEnabled(bool aEnabled);
288 : void Stop();
289 : void GetConstraints(dom::MediaTrackConstraints& aResult);
290 : void GetSettings(dom::MediaTrackSettings& aResult);
291 :
292 : already_AddRefed<Promise>
293 : ApplyConstraints(const dom::MediaTrackConstraints& aConstraints,
294 : CallerType aCallerType, ErrorResult &aRv);
295 : already_AddRefed<MediaStreamTrack> Clone();
296 0 : MediaStreamTrackState ReadyState() { return mReadyState; }
297 :
298 0 : IMPL_EVENT_HANDLER(ended)
299 :
300 : /**
301 : * Convenience (and legacy) method for when ready state is "ended".
302 : */
303 0 : bool Ended() const { return mReadyState == MediaStreamTrackState::Ended; }
304 :
305 : /**
306 : * Forces the ready state to a particular value, for instance when we're
307 : * cloning an already ended track.
308 : */
309 : void SetReadyState(MediaStreamTrackState aState);
310 :
311 : /**
312 : * Notified by the MediaStreamGraph, through our owning MediaStream on the
313 : * main thread.
314 : *
315 : * Note that this sets the track to ended and raises the "ended" event
316 : * synchronously.
317 : */
318 : void OverrideEnded();
319 :
320 : /**
321 : * Get this track's principal.
322 : */
323 0 : nsIPrincipal* GetPrincipal() const { return mPrincipal; }
324 :
325 : /**
326 : * Called by the PrincipalHandleListener when this track's PrincipalHandle changes on
327 : * the MediaStreamGraph thread. When the PrincipalHandle matches the pending
328 : * principal we know that the principal change has propagated to consumers.
329 : */
330 : void NotifyPrincipalHandleChanged(const PrincipalHandle& aPrincipalHandle);
331 :
332 : /**
333 : * Called when this track's readyState transitions to "ended".
334 : * Notifies all MediaStreamTrackConsumers that this track ended.
335 : */
336 : void NotifyEnded();
337 :
338 : /**
339 : * Get this track's CORS mode.
340 : */
341 0 : CORSMode GetCORSMode() const { return GetSource().GetCORSMode(); }
342 :
343 : /**
344 : * Get this track's PeerIdentity.
345 : */
346 0 : const PeerIdentity* GetPeerIdentity() const { return GetSource().GetPeerIdentity(); }
347 :
348 : MediaStreamGraph* Graph();
349 : MediaStreamGraphImpl* GraphImpl();
350 :
351 0 : MediaStreamTrackSource& GetSource() const
352 : {
353 0 : MOZ_RELEASE_ASSERT(mSource, "The track source is only removed on destruction");
354 0 : return *mSource;
355 : }
356 :
357 : // Webrtc allows the remote side to name tracks whatever it wants, and we
358 : // need to surface this to content.
359 0 : void AssignId(const nsAString& aID) { mID = aID; }
360 :
361 : // Implementation of MediaStreamTrackSource::Sink
362 : void PrincipalChanged() override;
363 :
364 : /**
365 : * Add a PrincipalChangeObserver to this track.
366 : *
367 : * Returns true if it was successfully added.
368 : *
369 : * Ownership of the PrincipalChangeObserver remains with the caller, and it's
370 : * the caller's responsibility to remove the observer before it dies.
371 : */
372 : bool AddPrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver);
373 :
374 : /**
375 : * Remove an added PrincipalChangeObserver from this track.
376 : *
377 : * Returns true if it was successfully removed.
378 : */
379 : bool RemovePrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver);
380 :
381 : /**
382 : * Add a MediaStreamTrackConsumer to this track.
383 : *
384 : * Adding the same consumer multiple times is prohibited.
385 : */
386 : void AddConsumer(MediaStreamTrackConsumer* aConsumer);
387 :
388 : /**
389 : * Remove an added MediaStreamTrackConsumer from this track.
390 : */
391 : void RemoveConsumer(MediaStreamTrackConsumer* aConsumer);
392 :
393 : /**
394 : * Adds a MediaStreamTrackListener to the MediaStreamGraph representation of
395 : * this track.
396 : */
397 : virtual void AddListener(MediaStreamTrackListener* aListener);
398 :
399 : /**
400 : * Removes a MediaStreamTrackListener from the MediaStreamGraph representation
401 : * of this track.
402 : */
403 : void RemoveListener(MediaStreamTrackListener* aListener);
404 :
405 : /**
406 : * Attempts to add a direct track listener to this track.
407 : * Callers must listen to the NotifyInstalled event to know if installing
408 : * the listener succeeded (tracks originating from SourceMediaStreams) or
409 : * failed (e.g., WebAudio originated tracks).
410 : */
411 : virtual void AddDirectListener(DirectMediaStreamTrackListener *aListener);
412 : void RemoveDirectListener(DirectMediaStreamTrackListener *aListener);
413 :
414 : /**
415 : * Sets up a MediaInputPort from the underlying track that this
416 : * MediaStreamTrack represents, to aStream, and returns it.
417 : */
418 : already_AddRefed<MediaInputPort> ForwardTrackContentsTo(ProcessedMediaStream* aStream,
419 : TrackID aDestinationTrackID = TRACK_ANY);
420 :
421 : /**
422 : * Returns true if this track is connected to aPort and forwarded to aPort's
423 : * output stream.
424 : */
425 : bool IsForwardedThrough(MediaInputPort* aPort);
426 :
427 : void SetMediaStreamSizeListener(DirectMediaStreamTrackListener* aListener);
428 :
429 : protected:
430 : virtual ~MediaStreamTrack();
431 :
432 : void Destroy();
433 :
434 : // Returns the original DOMMediaStream's underlying input stream.
435 : MediaStream* GetInputStream();
436 :
437 : // Returns the owning DOMMediaStream's underlying owned stream.
438 : ProcessedMediaStream* GetOwnedStream();
439 :
440 : // Returns the original DOMMediaStream. If this track is a clone,
441 : // the original track's owning DOMMediaStream is returned.
442 : DOMMediaStream* GetInputDOMStream();
443 :
444 : /**
445 : * Sets the principal and notifies PrincipalChangeObservers if it changes.
446 : */
447 : void SetPrincipal(nsIPrincipal* aPrincipal);
448 :
449 : /**
450 : * Creates a new MediaStreamTrack with the same type, input track ID and
451 : * source as this MediaStreamTrack.
452 : * aTrackID is the TrackID the new track will have in its owned stream.
453 : */
454 : virtual already_AddRefed<MediaStreamTrack> CloneInternal(DOMMediaStream* aOwningStream,
455 : TrackID aTrackID) = 0;
456 :
457 : nsTArray<PrincipalChangeObserver<MediaStreamTrack>*> mPrincipalChangeObservers;
458 :
459 : nsTArray<RefPtr<MediaStreamTrackConsumer>> mConsumers;
460 :
461 : RefPtr<DOMMediaStream> mOwningStream;
462 : TrackID mTrackID;
463 : TrackID mInputTrackID;
464 : RefPtr<MediaStreamTrackSource> mSource;
465 : RefPtr<MediaStreamTrack> mOriginalTrack;
466 : nsCOMPtr<nsIPrincipal> mPrincipal;
467 : nsCOMPtr<nsIPrincipal> mPendingPrincipal;
468 : RefPtr<PrincipalHandleListener> mPrincipalHandleListener;
469 : // Keep tracking MediaStreamTrackListener and DirectMediaStreamTrackListener,
470 : // so we can remove them in |Destory|.
471 : nsTArray<RefPtr<MediaStreamTrackListener>> mTrackListeners;
472 : nsTArray<RefPtr<DirectMediaStreamTrackListener>> mDirectTrackListeners;
473 : nsString mID;
474 : MediaStreamTrackState mReadyState;
475 : bool mEnabled;
476 : dom::MediaTrackConstraints mConstraints;
477 : };
478 :
479 : } // namespace dom
480 : } // namespace mozilla
481 :
482 : #endif /* MEDIASTREAMTRACK_H_ */
|