Bug 1425621 - Part 1: Test-case for removeTrack and MediaStream.onremovetrack. r?jib draft
authorByron Campen [:bwc] <docfaraday@gmail.com>
Mon, 18 Dec 2017 14:37:43 -0600
changeset 716413 1854ffd97cdfbd185e2dd2d649c0f9a03ad8996b
parent 716325 81362f7306fe413b19fdba27cd0e9a5525d902e1
child 716414 2ea24474de354364aec9577b58bc495698df2ef1
push id94437
push userbcampen@mozilla.com
push dateFri, 05 Jan 2018 18:53:15 +0000
reviewersjib
bugs1425621
milestone59.0a1
Bug 1425621 - Part 1: Test-case for removeTrack and MediaStream.onremovetrack. r?jib Also, expects onmute to happen before SRD resolves, even for offers. MozReview-Commit-ID: 2ibQKDfyHYH
dom/media/tests/mochitest/test_peerConnection_transceivers.html
--- a/dom/media/tests/mochitest/test_peerConnection_transceivers.html
+++ b/dom/media/tests/mochitest/test_peerConnection_transceivers.html
@@ -36,16 +36,34 @@
     let finishCollecting = () => {
       target.removeEventListener(name, handler);
       return events;
     };
 
     return {finish: finishCollecting};
   };
 
+  let collectAddTrackEvents = stream => {
+    let checkEvent = e => {
+      ok(e.track, "Track is set on event");
+      ok(stream.getTracks().includes(e.track),
+        "track in addtrack event is in the stream");
+    };
+    return collectEvents(stream, "addtrack", checkEvent);
+  };
+
+  let collectRemoveTrackEvents = stream => {
+    let checkEvent = e => {
+      ok(e.track, "Track is set on event");
+      ok(!stream.getTracks().includes(e.track),
+        "track in removetrack event is not in the stream");
+    };
+    return collectEvents(stream, "removetrack", checkEvent);
+  };
+
   let collectTrackEvents = pc => {
     let checkEvent = e => {
       ok(e.track, "Track is set on event");
       ok(e.receiver, "Receiver is set on event");
       ok(e.transceiver, "Transceiver is set on event");
       ok(e.streams, "Streams is set on event");
       e.streams.forEach(stream => {
         ok(stream.getTracks().includes(e.track),
@@ -762,16 +780,137 @@
         {currentDirection: "sendrecv"}
       ]);
 
     pc1.close();
     pc2.close();
     stopTracks(stream);
   };
 
+  let checkRemoveTrackNegotiation = async () => {
+    let pc1 = new RTCPeerConnection();
+    let pc2 = new RTCPeerConnection();
+    let stream = await getUserMedia({audio: true, video: true});
+    let audio = stream.getAudioTracks()[0];
+    pc1.addTrack(audio, stream);
+    let video = stream.getVideoTracks()[0];
+    pc1.addTrack(video, stream);
+    // We want both a sendrecv and sendonly transceiver to test that the
+    // appropriate direction changes happen.
+    pc1.getTransceivers()[1].direction = "sendonly";
+
+    let offer = await pc1.createOffer();
+
+    // Get a reference to the stream
+    let trackEventCollector = collectTrackEvents(pc2);
+    await pc2.setRemoteDescription(offer);
+    let pc2TrackEvents = trackEventCollector.finish();
+    hasProps(pc2TrackEvents,
+      [
+        {streams: [{id: stream.id}]},
+        {streams: [{id: stream.id}]}
+      ]);
+    let receiveStream = pc2TrackEvents[0].streams[0];
+
+    // Verify that rollback causes onremovetrack to fire for the added tracks
+    let removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
+    await pc2.setRemoteDescription({type: "rollback"});
+    let removedtracks = removetrackEventCollector.finish().map(e => e.track);
+    is(removedtracks.length, 2, "Rollback should have removed two tracks");
+    ok(removedtracks.includes(pc2TrackEvents[0].track), "First track should be removed");
+    ok(removedtracks.includes(pc2TrackEvents[1].track), "Second track should be removed");
+
+    offer = await pc1.createOffer();
+
+    let addtrackEventCollector = collectAddTrackEvents(receiveStream);
+    trackEventCollector = collectTrackEvents(pc2);
+    await pc2.setRemoteDescription(offer);
+    pc2TrackEvents = trackEventCollector.finish();
+    let addedtracks = addtrackEventCollector.finish().map(e => e.track);
+    is(addedtracks.length, 2,
+      "pc2.setRemoteDescription(offer) should have added two tracks to the receive stream");
+    ok(addedtracks.includes(pc2TrackEvents[0].track), "First track should be added");
+    ok(addedtracks.includes(pc2TrackEvents[1].track), "Second track should be added");
+
+    await pc1.setLocalDescription(offer);
+    let answer = await pc2.createAnswer();
+    await pc1.setRemoteDescription(answer);
+    await pc2.setLocalDescription(answer);
+    pc1.removeTrack(pc1.getSenders()[0]);
+
+    hasProps(pc1.getTransceivers(),
+      [
+        {
+          sender: {track: null},
+          direction: "recvonly"
+        },
+        {
+          sender: {track: video},
+          direction: "sendonly"
+        }
+      ]);
+
+    await negotiationNeeded(pc1);
+
+    pc1.removeTrack(pc1.getSenders()[1]);
+
+    hasProps(pc1.getTransceivers(),
+      [
+        {
+          sender: {track: null},
+          direction: "recvonly"
+        },
+        {
+          sender: {track: null},
+          direction: "inactive"
+        }
+      ]);
+
+    // pc1 as offerer
+    offer = await pc1.createOffer();
+
+    removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
+    await pc2.setRemoteDescription(offer);
+    removedtracks = removetrackEventCollector.finish().map(e => e.track);
+    is(removedtracks.length, 2, "Should have two removed tracks");
+    ok(removedtracks.includes(pc2TrackEvents[0].track), "First track should be removed");
+    ok(removedtracks.includes(pc2TrackEvents[1].track), "Second track should be removed");
+
+    addtrackEventCollector = collectAddTrackEvents(receiveStream);
+    await pc2.setRemoteDescription({type: "rollback"});
+    addedtracks = addtrackEventCollector.finish().map(e => e.track);
+    is(addedtracks.length, 2, "Rollback should have added two tracks");
+
+    // pc2 as offerer
+    offer = await pc2.createOffer();
+    await pc2.setLocalDescription(offer);
+    await pc1.setRemoteDescription(offer);
+    answer = await pc1.createAnswer();
+    await pc1.setLocalDescription(answer);
+
+    removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
+    await pc2.setRemoteDescription(answer);
+    removedtracks = removetrackEventCollector.finish().map(e => e.track);
+    is(removedtracks.length, 2, "Should have two removed tracks");
+
+    hasProps(pc2.getTransceivers(),
+      [
+        {
+          currentDirection: "inactive"
+        },
+        {
+          currentDirection: "inactive"
+        }
+      ]);
+
+    pc1.close();
+    pc2.close();
+    stopTracks(stream);
+  };
+
   let checkSetDirection = async () => {
     let pc = new RTCPeerConnection();
     pc.addTransceiver("audio");
 
     pc.getTransceivers()[0].direction = "sendonly";
     hasProps(pc.getTransceivers(),[{direction: "sendonly"}]);
     pc.getTransceivers()[0].direction = "recvonly";
     hasProps(pc.getTransceivers(),[{direction: "recvonly"}]);
@@ -1031,25 +1170,25 @@
     await pc2.setLocalDescription(answer);
     await gotMuteAudio1;
     await gotMuteVideo1;
 
     // Check whether disabling on remote causes onmute
     pc1.getTransceivers()[0].direction = "inactive";
     pc1.getTransceivers()[1].direction = "inactive";
     offer = await pc1.createOffer();
-    await pc2.setRemoteDescription(offer);
-    await pc1.setLocalDescription(offer);
-    answer = await pc2.createAnswer();
     let gotMuteAudio2 = gotMuteEvent(pc2.getTransceivers()[0].receiver.track);
     let gotMuteVideo2 = gotMuteEvent(pc2.getTransceivers()[1].receiver.track);
+    await pc2.setRemoteDescription(offer);
+    await gotMuteAudio2;
+    await gotMuteVideo2;
+    await pc1.setLocalDescription(offer);
+    answer = await pc2.createAnswer();
     await pc1.setRemoteDescription(answer);
     await pc2.setLocalDescription(answer);
-    await gotMuteAudio2;
-    await gotMuteVideo2;
 
     // Check whether onunmute fires when we turn everything on again
     pc1.getTransceivers()[0].direction = "sendrecv";
     pc1.getTransceivers()[1].direction = "sendrecv";
     offer = await pc1.createOffer();
     await pc2.setRemoteDescription(offer);
     await pc1.setLocalDescription(offer);
     answer = await pc2.createAnswer();
@@ -2054,16 +2193,17 @@
     await checkSendrecvWithTracklessStream();
     await checkAddTransceiverNoTrackDoesntPair();
     await checkAddTransceiverWithTrackDoesntPair();
     await checkAddTransceiverThenReplaceTrackDoesntPair();
     await checkAddTransceiverThenAddTrackPairs();
     await checkAddTrackPairs();
     await checkReplaceTrackNullDoesntPreventPairing();
     await checkRemoveAndReadd();
+    await checkRemoveTrackNegotiation();
     await checkMute();
     await checkOnAddStream();
     await checkStop();
     await checkStopAfterCreateOffer();
     await checkStopAfterSetLocalOffer();
     await checkStopAfterSetRemoteOffer();
     await checkStopAfterCreateAnswer();
     await checkStopAfterSetLocalAnswer();