Bug 1259788 - Break out AddTrackInternal() from DOMMediaStream::CreateDOMTrack. r?jesup draft
authorAndreas Pehrson <pehrsons@gmail.com>
Fri, 12 Aug 2016 13:50:41 +0200
changeset 404928 40450f70fd199c4d685653e3d16262d9ec46bb9b
parent 404927 ed99246365be8357f17db9c485d61bfebbfcf042
child 404929 ceb24561f996b3712f7d76ab4a1493b27714e92b
push id27359
push userpehrsons@gmail.com
push dateWed, 24 Aug 2016 14:53:56 +0000
reviewersjesup
bugs1259788
milestone51.0a1
Bug 1259788 - Break out AddTrackInternal() from DOMMediaStream::CreateDOMTrack. r?jesup Sometimes a track is added to a stream synchronously (before the stream is exposed to script), and sometimes asynchronously (see the mediacapture-main spec on the "addtrack" event). In the latter case we might still need to create the MediaStreamTrack object synchronously for tracking purposes. CaptureStream of Media element playing a MediaStream wants this. MozReview-Commit-ID: 7me8xzN7rwj
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLMediaElement.cpp
dom/media/DOMMediaStream.cpp
dom/media/DOMMediaStream.h
dom/media/MediaManager.cpp
dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/test/FakeMediaStreams.h
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -681,18 +681,20 @@ HTMLCanvasElement::CaptureStream(const O
   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
   nsresult rv =
     stream->Init(aFrameRate, videoTrackId, principal);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
+  RefPtr<MediaStreamTrack> track =
   stream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
                          new BasicUnstoppableTrackSource(principal));
+  stream->AddTrackInternal(track);
 
   rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return stream.forget();
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2282,25 +2282,29 @@ HTMLMediaElement::CaptureStreamInternal(
     mDecoder->AddOutputStream(out->mStream->GetInputStream()->AsProcessedStream(),
                               aFinishWhenEnded);
     if (mReadyState >= HAVE_METADATA) {
       // Expose the tracks to JS directly.
       if (HasAudio()) {
         TrackID audioTrackId = mMediaInfo.mAudio.mTrackId;
         RefPtr<MediaStreamTrackSource> trackSource =
           getter->GetMediaStreamTrackSource(audioTrackId);
-        out->mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO,
-                                     trackSource);
+        RefPtr<MediaStreamTrack> track =
+          out->mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO,
+                                       trackSource);
+        out->mStream->AddTrackInternal(track);
       }
       if (HasVideo()) {
         TrackID videoTrackId = mMediaInfo.mVideo.mTrackId;
         RefPtr<MediaStreamTrackSource> trackSource =
           getter->GetMediaStreamTrackSource(videoTrackId);
-        out->mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
-                                     trackSource);
+        RefPtr<MediaStreamTrack> track =
+          out->mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
+                                       trackSource);
+        out->mStream->AddTrackInternal(track);
       }
     }
   }
   RefPtr<DOMMediaStream> result = out->mStream;
   return result.forget();
 }
 
 already_AddRefed<DOMMediaStream>
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -157,17 +157,19 @@ public:
       }
       if (!source) {
         NS_ASSERTION(false, "Dynamic track created without an explicit TrackSource");
         nsPIDOMWindowInner* window = mStream->GetParentObject();
         nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
         nsIPrincipal* principal = doc ? doc->NodePrincipal() : nullptr;
         source = new BasicUnstoppableTrackSource(principal);
       }
-      track = mStream->CreateDOMTrack(aTrackID, aType, source);
+      RefPtr<MediaStreamTrack> newTrack =
+        mStream->CreateDOMTrack(aTrackID, aType, source);
+      mStream->AddTrackInternal(newTrack);
     }
   }
 
   void DoNotifyTrackEnded(MediaStream* aInputStream, TrackID aInputTrackID,
                           TrackID aTrackID)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
@@ -804,17 +806,20 @@ DOMMediaStream::InitAudioCaptureStream(n
   RefPtr<BasicUnstoppableTrackSource> audioCaptureSource =
     new BasicUnstoppableTrackSource(aPrincipal, MediaSourceEnum::AudioCapture);
 
   AudioCaptureStream* audioCaptureStream =
     static_cast<AudioCaptureStream*>(aGraph->CreateAudioCaptureStream(AUDIO_TRACK));
   InitInputStreamCommon(audioCaptureStream, aGraph);
   InitOwnedStreamCommon(aGraph);
   InitPlaybackStreamCommon(aGraph);
-  CreateDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO, audioCaptureSource);
+  RefPtr<MediaStreamTrack> track =
+    CreateDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO, audioCaptureSource);
+  AddTrackInternal(track);
+
   audioCaptureStream->Start();
 }
 
 void
 DOMMediaStream::InitInputStreamCommon(MediaStream* aStream,
                                       MediaStreamGraph* aGraph)
 {
   MOZ_ASSERT(!mOwnedStream, "Input stream must be initialized before owned stream");
@@ -972,51 +977,65 @@ DOMMediaStream::AddPrincipalChangeObserv
 
 bool
 DOMMediaStream::RemovePrincipalChangeObserver(
   PrincipalChangeObserver<DOMMediaStream>* aObserver)
 {
   return mPrincipalChangeObservers.RemoveElement(aObserver);
 }
 
-MediaStreamTrack*
+void
+DOMMediaStream::AddTrackInternal(MediaStreamTrack* aTrack)
+{
+  MOZ_ASSERT(aTrack->mOwningStream == this);
+  MOZ_ASSERT(FindOwnedDOMTrack(aTrack->GetInputStream(),
+                               aTrack->mInputTrackID,
+                               aTrack->mTrackID));
+  MOZ_ASSERT(!FindPlaybackDOMTrack(aTrack->GetOwnedStream(),
+                                   aTrack->mTrackID));
+
+  LOG(LogLevel::Debug, ("DOMMediaStream %p Adding owned track %p", this, aTrack));
+
+  mTracks.AppendElement(
+    new TrackPort(mPlaybackPort, aTrack, TrackPort::InputPortOwnership::EXTERNAL));
+
+  NotifyTrackAdded(aTrack);
+
+  DispatchTrackEvent(NS_LITERAL_STRING("addtrack"), aTrack);
+}
+
+already_AddRefed<MediaStreamTrack>
 DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType,
                                MediaStreamTrackSource* aSource,
                                const MediaTrackConstraints& aConstraints)
 {
   MOZ_RELEASE_ASSERT(mInputStream);
   MOZ_RELEASE_ASSERT(mOwnedStream);
 
   MOZ_ASSERT(FindOwnedDOMTrack(GetInputStream(), aTrackID) == nullptr);
 
-  MediaStreamTrack* track;
+  RefPtr<MediaStreamTrack> track;
   switch (aType) {
   case MediaSegment::AUDIO:
     track = new AudioStreamTrack(this, aTrackID, aTrackID, aSource, aConstraints);
     break;
   case MediaSegment::VIDEO:
     track = new VideoStreamTrack(this, aTrackID, aTrackID, aSource, aConstraints);
     break;
   default:
     MOZ_CRASH("Unhandled track type");
   }
 
-  LOG(LogLevel::Debug, ("DOMMediaStream %p Created new track %p with ID %u", this, track, aTrackID));
+  LOG(LogLevel::Debug, ("DOMMediaStream %p Created new track %p with ID %u",
+                        this, track.get(), aTrackID));
 
   mOwnedTracks.AppendElement(
     new TrackPort(mOwnedPort, track, TrackPort::InputPortOwnership::EXTERNAL));
 
-  mTracks.AppendElement(
-    new TrackPort(mPlaybackPort, track, TrackPort::InputPortOwnership::EXTERNAL));
-
-  NotifyTrackAdded(track);
-
-  DispatchTrackEvent(NS_LITERAL_STRING("addtrack"), track);
-
-  return track;
+  return track.forget();
 }
 
 already_AddRefed<MediaStreamTrack>
 DOMMediaStream::CloneDOMTrack(MediaStreamTrack& aTrack,
                               TrackID aCloneTrackID)
 {
   MOZ_RELEASE_ASSERT(mOwnedStream);
   MOZ_RELEASE_ASSERT(mPlaybackStream);
--- a/dom/media/DOMMediaStream.h
+++ b/dom/media/DOMMediaStream.h
@@ -506,29 +506,35 @@ public:
                                   MediaStreamGraph* aGraph);
 
   void SetLogicalStreamStartTime(StreamTime aTime)
   {
     mLogicalStreamStartTime = aTime;
   }
 
   /**
-   * Called for each track in our owned stream to indicate to JS that we
-   * are carrying that track.
-   *
-   * Creates a MediaStreamTrack, adds it to mTracks, raises "addtrack" and
-   * returns it.
+   * Adds a MediaStreamTrack to mTracks and raises "addtrack".
    *
    * Note that "addtrack" is raised synchronously and only has an effect if
    * this MediaStream is already exposed to script. For spec compliance this is
    * to be called from an async task.
    */
-  MediaStreamTrack* CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType,
-      MediaStreamTrackSource* aSource,
-      const MediaTrackConstraints& aConstraints = MediaTrackConstraints());
+  void AddTrackInternal(MediaStreamTrack* aTrack);
+
+  /**
+   * Called for each track in our owned stream to indicate to JS that we
+   * are carrying that track.
+   *
+   * Pre-creates a MediaStreamTrack and returns it.
+   * It is up to the caller to make sure it is added through AddTrackInternal.
+   */
+  already_AddRefed<MediaStreamTrack> CreateDOMTrack(TrackID aTrackID,
+                                                    MediaSegment::Type aType,
+                                                    MediaStreamTrackSource* aSource,
+                                                    const MediaTrackConstraints& aConstraints = MediaTrackConstraints());
 
   /**
    * Creates a MediaStreamTrack cloned from aTrack, adds it to mTracks and
    * returns it.
    * aCloneTrackID is the TrackID the new track will get in mOwnedStream.
    */
   already_AddRefed<MediaStreamTrack> CloneDOMTrack(MediaStreamTrack& aTrack,
                                                    TrackID aCloneTrackID);
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1189,30 +1189,34 @@ public:
         nsString audioDeviceName;
         mAudioDevice->GetName(audioDeviceName);
         const MediaSourceEnum source =
           mAudioDevice->GetSource()->GetMediaSource();
         RefPtr<MediaStreamTrackSource> audioSource =
           new LocalTrackSource(principal, audioDeviceName, mListener, source,
                                kAudioTrack, mPeerIdentity);
         MOZ_ASSERT(IsOn(mConstraints.mAudio));
-        domStream->CreateDOMTrack(kAudioTrack, MediaSegment::AUDIO, audioSource,
-                                  GetInvariant(mConstraints.mAudio));
+        RefPtr<MediaStreamTrack> track =
+          domStream->CreateDOMTrack(kAudioTrack, MediaSegment::AUDIO, audioSource,
+                                    GetInvariant(mConstraints.mAudio));
+        domStream->AddTrackInternal(track);
       }
       if (mVideoDevice) {
         nsString videoDeviceName;
         mVideoDevice->GetName(videoDeviceName);
         const MediaSourceEnum source =
           mVideoDevice->GetSource()->GetMediaSource();
         RefPtr<MediaStreamTrackSource> videoSource =
           new LocalTrackSource(principal, videoDeviceName, mListener, source,
                                kVideoTrack, mPeerIdentity);
         MOZ_ASSERT(IsOn(mConstraints.mVideo));
-        domStream->CreateDOMTrack(kVideoTrack, MediaSegment::VIDEO, videoSource,
-                                  GetInvariant(mConstraints.mVideo));
+        RefPtr<MediaStreamTrack> track =
+          domStream->CreateDOMTrack(kVideoTrack, MediaSegment::VIDEO, videoSource,
+                                    GetInvariant(mConstraints.mVideo));
+        domStream->AddTrackInternal(track);
       }
       stream = domStream->GetInputStream()->AsSourceStream();
     }
 
     if (!domStream || sInShutdown) {
       nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
       LOG(("Returning error for getUserMedia() - no stream"));
 
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -34,19 +34,21 @@ MediaStreamAudioDestinationNode::MediaSt
                                                              this,
                                                              aContext->Graph()))
 {
   // Ensure an audio track with the correct ID is exposed to JS
   nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc();
   RefPtr<MediaStreamTrackSource> source =
     new BasicUnstoppableTrackSource(doc->NodePrincipal(),
                                     MediaSourceEnum::AudioCapture);
-  mDOMStream->CreateDOMTrack(AudioNodeStream::AUDIO_TRACK,
-                             MediaSegment::AUDIO, source,
-                             MediaTrackConstraints());
+  RefPtr<MediaStreamTrack> track =
+    mDOMStream->CreateDOMTrack(AudioNodeStream::AUDIO_TRACK,
+                               MediaSegment::AUDIO, source,
+                               MediaTrackConstraints());
+  mDOMStream->AddTrackInternal(track);
 
   ProcessedMediaStream* outputStream = mDOMStream->GetInputStream()->AsProcessedStream();
   MOZ_ASSERT(!!outputStream);
   AudioNodeEngine* engine = new AudioNodeEngine(this);
   mStream = AudioNodeStream::Create(aContext, engine,
                                     AudioNodeStream::EXTERNAL_OUTPUT);
   mPort = outputStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK);
 }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1987,22 +1987,24 @@ PeerConnectionImpl::CreateNewRemoteTrack
         TrackID trackID = ++maxTrackId;
         RefPtr<MediaStreamTrack> domTrack;
         nsAutoPtr<MediaSegment> segment;
         if (track->GetMediaType() == SdpMediaSection::kAudio) {
           domTrack =
             info->GetMediaStream()->CreateDOMTrack(trackID,
                                                    MediaSegment::AUDIO,
                                                    source);
+          info->GetMediaStream()->AddTrackInternal(domTrack);
           segment = new AudioSegment;
         } else {
           domTrack =
             info->GetMediaStream()->CreateDOMTrack(trackID,
                                                    MediaSegment::VIDEO,
                                                    source);
+          info->GetMediaStream()->AddTrackInternal(domTrack);
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
           segment = new VideoSegment;
 #endif
         }
 
         StartTrack(info->GetMediaStream()->GetInputStream()->AsSourceStream(),
                    trackID, Move(segment));
         info->AddTrack(webrtcTrackId, domTrack);
--- a/media/webrtc/signaling/test/FakeMediaStreams.h
+++ b/media/webrtc/signaling/test/FakeMediaStreams.h
@@ -560,26 +560,28 @@ public:
   bool
   OwnsTrack(const Fake_MediaStreamTrack& aTrack) const
   {
     return HasTrack(aTrack);
   }
 
   void SetTrackEnabled(mozilla::TrackID aTrackID, bool aEnabled) {}
 
-  Fake_MediaStreamTrack*
+  void AddTrackInternal(Fake_MediaStreamTrack* aTrack) {}
+
+  already_AddRefed<Fake_MediaStreamTrack>
   CreateDOMTrack(mozilla::TrackID aTrackID, mozilla::MediaSegment::Type aType,
                  Fake_MediaStreamTrackSource* aSource)
   {
     switch(aType) {
       case mozilla::MediaSegment::AUDIO: {
-        return mAudioTrack;
+        return do_AddRef(mAudioTrack);
       }
       case mozilla::MediaSegment::VIDEO: {
-        return mVideoTrack;
+        return do_AddRef(mVideoTrack);
       }
       default: {
         MOZ_CRASH("Unkown media type");
       }
     }
   }
 
 private: