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 "mozilla/DOMEventTargetHelper.h" 10 #include "nsError.h" 11 #include "nsID.h" 12 #include "nsIPrincipal.h" 13 #include "StreamTracks.h" 14 #include "MediaTrackConstraints.h" 15 #include "mozilla/CORSMode.h" 16 #include "PrincipalChangeObserver.h" 17 #include "mozilla/dom/MediaStreamTrackBinding.h" 18 #include "mozilla/dom/MediaTrackSettingsBinding.h" 19 #include "mozilla/media/MediaUtils.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 44 /** 45 * Common interface through which a MediaStreamTrack can communicate with its 46 * producer on the main thread. 47 * 48 * Kept alive by a strong ref in all MediaStreamTracks (original and clones) 49 * sharing this source. 50 */ 51 class MediaStreamTrackSource : public nsISupports 52 { 53 NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource)54 NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource) 55 56 public: 57 class Sink 58 { 59 public: 60 virtual void PrincipalChanged() = 0; 61 }; 62 MediaStreamTrackSource(nsIPrincipal * aPrincipal,const nsString & aLabel)63 MediaStreamTrackSource(nsIPrincipal* aPrincipal, 64 const nsString& aLabel) 65 : mPrincipal(aPrincipal), 66 mLabel(aLabel), 67 mStopped(false) 68 { 69 MOZ_COUNT_CTOR(MediaStreamTrackSource); 70 } 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 */ Destroy()77 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 */ GetPrincipal()87 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 */ GetCORSMode()94 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 * nsNullPrincipal. 101 * 102 * A track's PeerIdentity is immutable and will not change during the track's 103 * lifetime. 104 */ GetPeerIdentity()105 virtual const PeerIdentity* GetPeerIdentity() const { return nullptr; } 106 107 /** 108 * MediaStreamTrack::GetLabel (see spec) calls through to here. 109 */ GetLabel(nsAString & aLabel)110 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 */ TakePhoto(MediaEnginePhotoCallback *)117 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 129 /** 130 * Same for GetSettings (no-op). 131 */ 132 virtual void GetSettings(dom::MediaTrackSettings & aResult)133 GetSettings(dom::MediaTrackSettings& aResult) {}; 134 135 /** 136 * Called by the source interface when all registered sinks have unregistered. 137 */ 138 virtual void Stop() = 0; 139 140 /** 141 * Called by each MediaStreamTrack clone on initialization. 142 */ RegisterSink(Sink * aSink)143 void RegisterSink(Sink* aSink) 144 { 145 MOZ_ASSERT(NS_IsMainThread()); 146 if (mStopped) { 147 return; 148 } 149 mSinks.AppendElement(aSink); 150 } 151 152 /** 153 * Called by each MediaStreamTrack clone on Stop() if supported by the 154 * source (us) or destruction. 155 */ UnregisterSink(Sink * aSink)156 void UnregisterSink(Sink* aSink) 157 { 158 MOZ_ASSERT(NS_IsMainThread()); 159 if (mSinks.RemoveElement(aSink) && mSinks.IsEmpty()) { 160 MOZ_ASSERT(!mStopped); 161 Stop(); 162 mStopped = true; 163 } 164 } 165 166 protected: ~MediaStreamTrackSource()167 virtual ~MediaStreamTrackSource() 168 { 169 MOZ_COUNT_DTOR(MediaStreamTrackSource); 170 } 171 172 /** 173 * Called by a sub class when the principal has changed. 174 * Notifies all sinks. 175 */ PrincipalChanged()176 void PrincipalChanged() 177 { 178 for (Sink* sink : mSinks) { 179 sink->PrincipalChanged(); 180 } 181 } 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 explicit BasicTrackSource(nsIPrincipal* aPrincipal, 204 const MediaSourceEnum aMediaSource = 205 MediaSourceEnum::Other) MediaStreamTrackSource(aPrincipal,nsString ())206 : MediaStreamTrackSource(aPrincipal, nsString()) 207 , mMediaSource(aMediaSource) 208 {} 209 GetMediaSource()210 MediaSourceEnum GetMediaSource() const override { return mMediaSource; } 211 Stop()212 void Stop() override {} 213 214 protected: ~BasicTrackSource()215 ~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 class MediaStreamTrackConsumer : public nsISupports 225 { 226 public: 227 NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackConsumer)228 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 virtual void NotifyEnded(MediaStreamTrack* aTrack) {}; 236 237 protected: ~MediaStreamTrackConsumer()238 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 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 AsAudioStreamTrack()276 virtual AudioStreamTrack* AsAudioStreamTrack() { return nullptr; } AsVideoStreamTrack()277 virtual VideoStreamTrack* AsVideoStreamTrack() { return nullptr; } 278 AsAudioStreamTrack()279 virtual const AudioStreamTrack* AsAudioStreamTrack() const { return nullptr; } AsVideoStreamTrack()280 virtual const VideoStreamTrack* AsVideoStreamTrack() const { return nullptr; } 281 282 // WebIDL 283 virtual void GetKind(nsAString& aKind) = 0; 284 void GetId(nsAString& aID) const; GetLabel(nsAString & aLabel)285 void GetLabel(nsAString& aLabel) { GetSource().GetLabel(aLabel); } Enabled()286 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, ErrorResult &aRv); 294 already_AddRefed<MediaStreamTrack> Clone(); ReadyState()295 MediaStreamTrackState ReadyState() { return mReadyState; } 296 IMPL_EVENT_HANDLER(ended)297 IMPL_EVENT_HANDLER(ended) 298 299 /** 300 * Convenience (and legacy) method for when ready state is "ended". 301 */ 302 bool Ended() const { return mReadyState == MediaStreamTrackState::Ended; } 303 304 /** 305 * Forces the ready state to a particular value, for instance when we're 306 * cloning an already ended track. 307 */ 308 void SetReadyState(MediaStreamTrackState aState); 309 310 /** 311 * Notified by the MediaStreamGraph, through our owning MediaStream on the 312 * main thread. 313 * 314 * Note that this sets the track to ended and raises the "ended" event 315 * synchronously. 316 */ 317 void OverrideEnded(); 318 319 /** 320 * Get this track's principal. 321 */ GetPrincipal()322 nsIPrincipal* GetPrincipal() const { return mPrincipal; } 323 324 /** 325 * Called by the PrincipalHandleListener when this track's PrincipalHandle changes on 326 * the MediaStreamGraph thread. When the PrincipalHandle matches the pending 327 * principal we know that the principal change has propagated to consumers. 328 */ 329 void NotifyPrincipalHandleChanged(const PrincipalHandle& aPrincipalHandle); 330 331 /** 332 * Called when this track's readyState transitions to "ended". 333 * Notifies all MediaStreamTrackConsumers that this track ended. 334 */ 335 void NotifyEnded(); 336 337 /** 338 * Get this track's CORS mode. 339 */ GetCORSMode()340 CORSMode GetCORSMode() const { return GetSource().GetCORSMode(); } 341 342 /** 343 * Get this track's PeerIdentity. 344 */ GetPeerIdentity()345 const PeerIdentity* GetPeerIdentity() const { return GetSource().GetPeerIdentity(); } 346 347 MediaStreamGraph* Graph(); 348 MediaStreamGraphImpl* GraphImpl(); 349 GetSource()350 MediaStreamTrackSource& GetSource() const 351 { 352 MOZ_RELEASE_ASSERT(mSource, "The track source is only removed on destruction"); 353 return *mSource; 354 } 355 356 // Webrtc allows the remote side to name tracks whatever it wants, and we 357 // need to surface this to content. AssignId(const nsAString & aID)358 void AssignId(const nsAString& aID) { mID = aID; } 359 360 // Implementation of MediaStreamTrackSource::Sink 361 void PrincipalChanged() override; 362 363 /** 364 * Add a PrincipalChangeObserver to this track. 365 * 366 * Returns true if it was successfully added. 367 * 368 * Ownership of the PrincipalChangeObserver remains with the caller, and it's 369 * the caller's responsibility to remove the observer before it dies. 370 */ 371 bool AddPrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver); 372 373 /** 374 * Remove an added PrincipalChangeObserver from this track. 375 * 376 * Returns true if it was successfully removed. 377 */ 378 bool RemovePrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver); 379 380 /** 381 * Add a MediaStreamTrackConsumer to this track. 382 * 383 * Adding the same consumer multiple times is prohibited. 384 */ 385 void AddConsumer(MediaStreamTrackConsumer* aConsumer); 386 387 /** 388 * Remove an added MediaStreamTrackConsumer from this track. 389 */ 390 void RemoveConsumer(MediaStreamTrackConsumer* aConsumer); 391 392 /** 393 * Adds a MediaStreamTrackListener to the MediaStreamGraph representation of 394 * this track. 395 */ 396 void AddListener(MediaStreamTrackListener* aListener); 397 398 /** 399 * Removes a MediaStreamTrackListener from the MediaStreamGraph representation 400 * of this track. 401 */ 402 void RemoveListener(MediaStreamTrackListener* aListener); 403 404 /** 405 * Attempts to add a direct track listener to this track. 406 * Callers must listen to the NotifyInstalled event to know if installing 407 * the listener succeeded (tracks originating from SourceMediaStreams) or 408 * failed (e.g., WebAudio originated tracks). 409 */ 410 void AddDirectListener(DirectMediaStreamTrackListener *aListener); 411 void RemoveDirectListener(DirectMediaStreamTrackListener *aListener); 412 413 /** 414 * Sets up a MediaInputPort from the underlying track that this 415 * MediaStreamTrack represents, to aStream, and returns it. 416 */ 417 already_AddRefed<MediaInputPort> ForwardTrackContentsTo(ProcessedMediaStream* aStream, 418 TrackID aDestinationTrackID = TRACK_ANY); 419 420 /** 421 * Returns true if this track is connected to aPort and forwarded to aPort's 422 * output stream. 423 */ 424 bool IsForwardedThrough(MediaInputPort* aPort); 425 426 void SetMediaStreamSizeListener(DirectMediaStreamTrackListener* aListener); 427 428 protected: 429 virtual ~MediaStreamTrack(); 430 431 void Destroy(); 432 433 // Returns the original DOMMediaStream's underlying input stream. 434 MediaStream* GetInputStream(); 435 436 // Returns the owning DOMMediaStream's underlying owned stream. 437 ProcessedMediaStream* GetOwnedStream(); 438 439 // Returns the original DOMMediaStream. If this track is a clone, 440 // the original track's owning DOMMediaStream is returned. 441 DOMMediaStream* GetInputDOMStream(); 442 443 /** 444 * Sets the principal and notifies PrincipalChangeObservers if it changes. 445 */ 446 void SetPrincipal(nsIPrincipal* aPrincipal); 447 448 /** 449 * Creates a new MediaStreamTrack with the same type, input track ID and 450 * source as this MediaStreamTrack. 451 * aTrackID is the TrackID the new track will have in its owned stream. 452 */ 453 virtual already_AddRefed<MediaStreamTrack> CloneInternal(DOMMediaStream* aOwningStream, 454 TrackID aTrackID) = 0; 455 456 nsTArray<PrincipalChangeObserver<MediaStreamTrack>*> mPrincipalChangeObservers; 457 458 nsTArray<RefPtr<MediaStreamTrackConsumer>> mConsumers; 459 460 RefPtr<DOMMediaStream> mOwningStream; 461 TrackID mTrackID; 462 TrackID mInputTrackID; 463 RefPtr<MediaStreamTrackSource> mSource; 464 RefPtr<MediaStreamTrack> mOriginalTrack; 465 nsCOMPtr<nsIPrincipal> mPrincipal; 466 nsCOMPtr<nsIPrincipal> mPendingPrincipal; 467 RefPtr<PrincipalHandleListener> mPrincipalHandleListener; 468 // Keep tracking MediaStreamTrackListener and DirectMediaStreamTrackListener, 469 // so we can remove them in |Destory|. 470 nsTArray<RefPtr<MediaStreamTrackListener>> mTrackListeners; 471 nsTArray<RefPtr<DirectMediaStreamTrackListener>> mDirectTrackListeners; 472 nsString mID; 473 MediaStreamTrackState mReadyState; 474 bool mEnabled; 475 dom::MediaTrackConstraints mConstraints; 476 }; 477 478 } // namespace dom 479 } // namespace mozilla 480 481 #endif /* MEDIASTREAMTRACK_H_ */ 482