Bug 1531803 - Part 6: Fire track events when that track has been added to a stream. r=jib,smaug
authorByron Campen [:bwc] <docfaraday@gmail.com>
Mon, 29 Apr 2019 15:52:03 +0000
changeset 530753 d2ba7da778f0ec24b08c80c870ed0f86b42e6758
parent 530752 6bf3fd241bb89e14d9535b04085b2949000e6329
child 530754 0f80cad005ba3ccad49740641f0fe404267ec535
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, smaug
bugs1531803
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1531803 - Part 6: Fire track events when that track has been added to a stream. r=jib,smaug Differential Revision: https://phabricator.services.mozilla.com/D25799
dom/media/PeerConnection.jsm
dom/webidl/RTCRtpReceiver.webidl
media/webrtc/signaling/src/peerconnection/TransceiverImpl.cpp
--- a/dom/media/PeerConnection.jsm
+++ b/dom/media/PeerConnection.jsm
@@ -1332,38 +1332,61 @@ class RTCPeerConnection {
     this._queueTaskWithClosedCheck(() => {
       if (this._negotiationNeeded) {
         this.dispatchEvent(new this._win.Event("negotiationneeded"));
       }
     });
   }
 
   _processTrackAdditionsAndRemovals() {
-    let postProcessing = {
-      updateStreamFunctions: [],
-      muteTracks: [],
-      trackEvents: [],
-    };
+    const removeList = [];
+    const addList = [];
+    const muteTracks = [];
+    const trackEventInits = [];
 
-    for (let transceiver of this._transceivers) {
+    for (const transceiver of this._transceivers) {
       transceiver.receiver.processTrackAdditionsAndRemovals(transceiver,
-                                                            postProcessing);
+        {removeList, addList, muteTracks, trackEventInits});
     }
 
-    for (let f of postProcessing.updateStreamFunctions) {
-      f();
+    muteTracks.forEach(track => {
+      // Check this as late as possible, in case JS has messed with this state.
+      if (!track.muted) {
+        track.mutedChanged(true);
+      }
+    });
+
+    for (const {stream, track} of removeList) {
+      // Check this as late as possible, in case JS messes with the track lists.
+      if (stream.getTracks().includes(track)) {
+        stream.removeTrack(track);
+        // Removing tracks from JS does not result in the stream getting a
+        // removetrack event, so we need to do that here.
+        stream.dispatchEvent(
+            new this._win.MediaStreamTrackEvent("removetrack", { track }));
+      }
     }
 
-    for (let t of postProcessing.muteTracks) {
-      t.mutedChanged(true);
+    for (const {stream, track} of addList) {
+      // Check this as late as possible, in case JS messes with the track lists.
+      if (!stream.getTracks().includes(track)) {
+        stream.addTrack(track);
+        // Adding tracks from JS does not result in the stream getting an
+        // addtrack event, so we need to do that here.
+        stream.dispatchEvent(
+            new this._win.MediaStreamTrackEvent("addtrack", { track }));
+      }
     }
 
-    for (let ev of postProcessing.trackEvents) {
-      this.dispatchEvent(ev);
-    }
+    trackEventInits.forEach(init => {
+      this.dispatchEvent(new this._win.RTCTrackEvent("track", init));
+      // Fire legacy event as well for a little bit.
+      this.dispatchEvent(new this._win.MediaStreamTrackEvent("addtrack",
+          { track: init.track }));
+    });
   }
 
   // TODO(Bug 1241291): Legacy event, remove eventually
   _fireLegacyAddStreamEvents() {
     for (let stream of this._newStreams) {
       let ev = new this._win.MediaStreamEvent("addstream", { stream });
       this.dispatchEvent(ev);
     }
@@ -2085,25 +2108,25 @@ class RTCRtpSender {
 setupPrototype(RTCRtpSender, {
   classID: PC_SENDER_CID,
   contractID: PC_SENDER_CONTRACT,
   QueryInterface: ChromeUtils.generateQI([]),
 });
 
 class RTCRtpReceiver {
   constructor(pc, transceiverImpl) {
-    // We do not set the track here; that is done when _transceiverImpl is set
     Object.assign(this,
         {
           _pc: pc,
           _transceiverImpl: transceiverImpl,
           track: transceiverImpl.getReceiveTrack(),
-          _remoteSetSendBit: false,
-          _ontrackFired: false,
-          streamIds: [],
+          _recvBit: false,
+          _oldRecvBit: false,
+          _streams: [],
+          _oldstreams: [],
           // Sync and contributing sources must be kept cached so that timestamps
           // remain stable, as the timestamp offset can vary
           // note key = entry.source + entry.sourceType
           _rtpSources: new Map(),
           _rtpSourcesJsTimestamp: null,
         });
   }
 
@@ -2186,87 +2209,62 @@ class RTCRtpReceiver {
     return this._getRtpSourcesByType("contributing");
   }
 
   getSynchronizationSources() {
     return this._getRtpSourcesByType("synchronization");
   }
 
   setStreamIds(streamIds) {
-    this.streamIds = streamIds;
+    this._streams = streamIds.map(id => this._pc._getOrCreateStream(id));
   }
 
-  setRemoteSendBit(sendBit) {
-    this._remoteSetSendBit = sendBit;
+  setRecvBit(recvBit) {
+    this._recvBit = recvBit;
   }
 
   processTrackAdditionsAndRemovals(transceiver,
-                                   {updateStreamFunctions, muteTracks, trackEvents}) {
-    let streamsWithTrack = this.streamIds
-      .map(id => this._pc._getOrCreateStream(id));
-
-    let streamsWithoutTrack = this._pc.getRemoteStreams()
-      .filter(s => !this.streamIds.includes(s.id));
+      {removeList, addList, muteTracks, trackEventInits}) {
+    const receiver = this.__DOM_IMPL__;
+    const track = this.track;
+    const streams = this._streams;
+    const streamsAdded = streams.filter(s => !this._oldstreams.includes(s));
+    const streamsRemoved = this._oldstreams.filter(s => !streams.includes(s));
 
-    updateStreamFunctions.push(...streamsWithTrack.map(stream => () => {
-      if (!stream.getTracks().includes(this.track)) {
-        stream.addTrack(this.track);
-        // Adding tracks from JS does not result in the stream getting
-        // onaddtrack, so we need to do that here.
-        stream.dispatchEvent(
-            new this._pc._win.MediaStreamTrackEvent(
-              "addtrack", { track: this.track }));
-      }
-    }));
+    addList.push(...streamsAdded.map(stream => ({stream, track})));
+    removeList.push(...streamsRemoved.map(stream => ({stream, track})));
+    this._oldstreams = this._streams;
+
+    let needsTrackEvent = (streamsAdded.length != 0);
 
-    updateStreamFunctions.push(...streamsWithoutTrack.map(stream => () => {
-      // Content JS might remove this track from the stream before this function fires (ugh)
-      if (stream.getTracks().includes(this.track)) {
-        stream.removeTrack(this.track);
-        // Removing tracks from JS does not result in the stream getting
-        // onremovetrack, so we need to do that here.
-        stream.dispatchEvent(
-            new this._pc._win.MediaStreamTrackEvent(
-              "removetrack", { track: this.track }));
+    if (this._recvBit != this._oldRecvBit) {
+      this._oldRecvBit = this._recvBit;
+      if (this._recvBit) {
+        // New track, set in case streamsAdded is empty
+        needsTrackEvent = true;
+      } else {
+        muteTracks.push(track);
       }
-    }));
+    }
 
-    if (!this._remoteSetSendBit) {
-      // remote used "recvonly" or "inactive"
-      this._ontrackFired = false;
-      if (!this.track.muted) {
-        muteTracks.push(this.track);
-      }
-    } else if (!this._ontrackFired) {
-      // remote used "sendrecv" or "sendonly", and we haven't fired ontrack
-      let ev = new this._pc._win.RTCTrackEvent("track", {
-        receiver: this.__DOM_IMPL__,
-        track: this.track,
-        streams: streamsWithTrack,
-        transceiver });
-      trackEvents.push(ev);
-      this._ontrackFired = true;
-
-      // Fire legacy event as well for a little bit.
-      ev = new this._pc._win.MediaStreamTrackEvent("addtrack",
-          { track: this.track });
-      trackEvents.push(ev);
+    if (needsTrackEvent) {
+      trackEventInits.push({track, streams, receiver, transceiver});
     }
   }
 }
 setupPrototype(RTCRtpReceiver, {
   classID: PC_RECEIVER_CID,
   contractID: PC_RECEIVER_CONTRACT,
   QueryInterface: ChromeUtils.generateQI([]),
 });
 
 class RTCRtpTransceiver {
   constructor(pc, transceiverImpl, init, kind, sendTrack) {
     let receiver = pc._win.RTCRtpReceiver._create(
-        pc._win, new RTCRtpReceiver(pc, transceiverImpl, kind));
+        pc._win, new RTCRtpReceiver(pc, transceiverImpl));
     let streams = (init && init.streams) || [];
     let sender = pc._win.RTCRtpSender._create(
         pc._win, new RTCRtpSender(pc, transceiverImpl, this, sendTrack, kind, streams));
 
     let direction = (init && init.direction) || "sendrecv";
     Object.assign(this,
         {
           _pc: pc,
--- a/dom/webidl/RTCRtpReceiver.webidl
+++ b/dom/webidl/RTCRtpReceiver.webidl
@@ -15,14 +15,14 @@ interface RTCRtpReceiver {
   [Pref="media.peerconnection.rtpsourcesapi.enabled"]
   sequence<RTCRtpContributingSource>    getContributingSources();
   [Pref="media.peerconnection.rtpsourcesapi.enabled"]
   sequence<RTCRtpSynchronizationSource> getSynchronizationSources();
 
   [ChromeOnly]
   void setStreamIds(sequence<DOMString> streamIds);
   [ChromeOnly]
-  void setRemoteSendBit(boolean sendBit);
+  void setRecvBit(boolean recvBit);
   [ChromeOnly]
   void processTrackAdditionsAndRemovals(
       RTCRtpTransceiver transceiver,
       object postProcessing);
 };
--- a/media/webrtc/signaling/src/peerconnection/TransceiverImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/TransceiverImpl.cpp
@@ -489,18 +489,17 @@ void TransceiverImpl::SyncWithJS(dom::RT
   for (const auto& id : mJsepTransceiver->mRecvTrack.GetStreamIds()) {
     receiveStreamIds.AppendElement(NS_ConvertUTF8toUTF16(id.c_str()), fallible);
   }
   receiver->SetStreamIds(receiveStreamIds, aRv);
   if (aRv.Failed()) {
     return;
   }
 
-  receiver->SetRemoteSendBit(mJsepTransceiver->mRecvTrack.GetRemoteSetSendBit(),
-                             aRv);
+  receiver->SetRecvBit(mJsepTransceiver->mRecvTrack.GetRemoteSetSendBit(), aRv);
   if (aRv.Failed()) {
     return;
   }
 
   // AddTrack magic from JS
   if (aJsTransceiver.GetAddTrackMagic(aRv)) {
     mJsepTransceiver->SetAddTrackMagic();
   }