Bug 1400363 - Part 1: Test muted/onmuted/onunmuted for webrtc cases. r=jib
authorByron Campen [:bwc] <docfaraday@gmail.com>
Wed, 29 Nov 2017 13:34:28 -0600
changeset 395734 787ddacd432d804ddebf75ae4dfae47d1ca7986f
parent 395733 be10a74ec95d4ef06553987ba31fd43ddb4a4d3c
child 395735 6cf1b98c8e77e56a5e45f1788a897fe480bb58ee
push id33054
push userrgurzau@mozilla.com
push dateFri, 08 Dec 2017 21:57:23 +0000
treeherdermozilla-central@6e2181b6137c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib
bugs1400363
milestone59.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 1400363 - Part 1: Test muted/onmuted/onunmuted for webrtc cases. r=jib MozReview-Commit-ID: ABFHeq4Eu6X
dom/media/tests/mochitest/test_peerConnection_audioRenegotiationInactiveAnswer.html
dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html
dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
dom/media/tests/mochitest/test_peerConnection_transceivers.html
dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html
--- a/dom/media/tests/mochitest/test_peerConnection_audioRenegotiationInactiveAnswer.html
+++ b/dom/media/tests/mochitest/test_peerConnection_audioRenegotiationInactiveAnswer.html
@@ -13,18 +13,28 @@
   });
 
   var test;
   runNetworkTest(function (options) {
     var helper = new AudioStreamHelper();
 
     test = new PeerConnectionTest(options);
     test.setMediaConstraints([{audio: true}], []);
+    var haveFirstUnmuteEvent;
+
+    test.chain.insertBefore("PC_REMOTE_SET_LOCAL_DESCRIPTION", [
+      function PC_REMOTE_SETUP_ONUNMUTE_1() {
+        haveFirstUnmuteEvent = haveEvent(test.pcRemote._pc.getReceivers()[0].track, "unmute");
+      }
+    ]);
 
     test.chain.append([
+      function PC_REMOTE_CHECK_AUDIO_UNMUTED() {
+        return haveFirstUnmuteEvent;
+      },
       function PC_REMOTE_CHECK_AUDIO_FLOWING() {
         return helper.checkAudioFlowing(test.pcRemote._pc.getRemoteStreams()[0]);
       }
     ]);
 
     addRenegotiation(test.chain, []);
 
     test.chain.insertAfter("PC_LOCAL_GET_ANSWER", [
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html
@@ -9,16 +9,18 @@
   createHTML({
     bug: "1017888",
     title: "Renegotiation: remove then add audio track"
   });
 
   runNetworkTest(function (options) {
     const test = new PeerConnectionTest(options);
     let originalTrack;
+    let haveMuteEvent;
+    let haveUnmuteEvent;
     addRenegotiation(test.chain,
       [
         function PC_REMOTE_FIND_RECEIVER(test) {
           is(test.pcRemote._pc.getReceivers().length, 1,
              "pcRemote should have one receiver");
           originalTrack = test.pcRemote._pc.getReceivers()[0].track;
         },
         function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
@@ -28,38 +30,53 @@
           // The new track's pipeline will start with a packet count of
           // 0, but the remote side will keep its old pipeline and packet
           // count.
           test.pcLocal.disableRtpCountChecking = true;
           return test.pcLocal.getAllUserMediaAndAddStreams([{audio: true}]);
         },
       ],
       [
+        function PC_REMOTE_WAIT_FOR_UNMUTE() {
+          return haveUnmuteEvent;
+        },
         function PC_REMOTE_CHECK_ADDED_TRACK(test) {
           is(test.pcRemote._pc.getTransceivers().length, 2,
               "pcRemote should have two transceivers");
           const track = test.pcRemote._pc.getTransceivers()[1].receiver.track;
 
           const analyser = new AudioStreamAnalyser(
               new AudioContext(), new MediaStream([track]));
           const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
           return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
         },
+        function PC_REMOTE_WAIT_FOR_MUTE() {
+          return haveMuteEvent;
+        },
         function PC_REMOTE_CHECK_REMOVED_TRACK(test) {
           is(test.pcRemote._pc.getTransceivers().length, 2,
               "pcRemote should have two transceivers");
           const track = test.pcRemote._pc.getTransceivers()[0].receiver.track;
 
           const analyser = new AudioStreamAnalyser(
               new AudioContext(), new MediaStream([track]));
           const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
           return analyser.waitForAnalysisSuccess(arr => arr[freq] < 50);
         }
       ]
     );
 
+    test.chain.insertBefore("PC_REMOTE_SET_LOCAL_DESCRIPTION", [
+      function PC_REMOTE_SETUP_ONMUTE(test) {
+        haveMuteEvent = haveEvent(test.pcRemote._pc.getReceivers()[0].track, "mute");
+      },
+      function PC_REMOTE_SETUP_ONUNMUTE(test) {
+        haveUnmuteEvent = haveEvent(test.pcRemote._pc.getReceivers()[1].track, "unmute");
+      }
+    ], false, 1);
+
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
@@ -11,16 +11,18 @@
     bug: "1017888",
     title: "Renegotiation: remove then add video track"
   });
 
   runNetworkTest(function (options) {
     const test = new PeerConnectionTest(options);
     const helper = new VideoStreamHelper();
     var originalTrack;
+    let haveMuteEvent;
+    let haveUnmuteEvent;
     addRenegotiation(test.chain,
       [
         function PC_REMOTE_FIND_RECEIVER(test) {
           is(test.pcRemote._pc.getReceivers().length, 1,
              "pcRemote should have one receiver");
           originalTrack = test.pcRemote._pc.getReceivers()[0].track;
         },
         function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
@@ -32,36 +34,51 @@
         },
         function PC_LOCAL_ADD_VIDEO_TRACK(test) {
           // Use fake:true here since the native fake device on linux doesn't
           // change color as needed by checkVideoPlaying() below.
           return test.pcLocal.getAllUserMediaAndAddStreams([{video: true, fake: true}]);
         },
       ],
       [
+        function PC_REMOTE_WAIT_FOR_UNMUTE() {
+          return haveUnmuteEvent;
+        },
         function PC_REMOTE_CHECK_ADDED_TRACK(test) {
           is(test.pcRemote._pc.getTransceivers().length, 2,
               "pcRemote should have two transceivers");
           const track = test.pcRemote._pc.getTransceivers()[1].receiver.track;
 
           const vAdded = test.pcRemote.remoteMediaElements.find(
               elem => elem.id.includes(track.id));
           return helper.checkVideoPlaying(vAdded);
         },
+        function PC_REMOTE_WAIT_FOR_MUTE() {
+          return haveMuteEvent;
+        },
         function PC_REMOTE_CHECK_REMOVED_TRACK(test) {
           is(test.pcRemote._pc.getTransceivers().length, 2,
               "pcRemote should have two transceivers");
           const track = test.pcRemote._pc.getTransceivers()[0].receiver.track;
 
           const vAdded = test.pcRemote.remoteMediaElements.find(
               elem => elem.id.includes(track.id));
           return helper.checkVideoPaused(vAdded, 10, 10, 16, 5000);
         }
       ]
     );
 
+    test.chain.insertBefore("PC_REMOTE_SET_LOCAL_DESCRIPTION", [
+      function PC_REMOTE_SETUP_ONMUTE(test) {
+        haveMuteEvent = haveEvent(test.pcRemote._pc.getReceivers()[0].track, "mute");
+      },
+      function PC_REMOTE_SETUP_ONUNMUTE(test) {
+        haveUnmuteEvent = haveEvent(test.pcRemote._pc.getReceivers()[1].track, "unmute");
+      }
+    ], false, 1);
+
     test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_transceivers.html
+++ b/dom/media/tests/mochitest/test_peerConnection_transceivers.html
@@ -74,16 +74,34 @@
       pc.oniceconnectionstatechange = iceCheck;
     });
   };
 
   let negotiationNeeded = pc => {
     return new Promise(resolve => pc.onnegotiationneeded = resolve);
   };
 
+  let countEvents = (target, name) => {
+    let result = {count: 0};
+    target.addEventListener(name, e => result.count++);
+    return result;
+  };
+
+  let gotMuteEvent = async track => {
+    await haveEvent(track, "mute");
+
+    ok(track.muted, "track should be muted after onmute");
+  };
+
+  let gotUnmuteEvent = async track => {
+    await haveEvent(track, "unmute");
+
+    ok(!track.muted, "track should not be muted after onunmute");
+  };
+
   let logExpected = expected => {
     info("(expected " + JSON.stringify(expected) + ")");
   };
 
   let hasProps = (observed, expected) => {
 
     if (observed === expected) {
       return true;
@@ -139,25 +157,25 @@
     pc.addTransceiver("audio");
     pc.addTransceiver("video");
 
     // NOTE: the w3c spec doesn't say anything about transceiver order, so this
     // may not necessarily be the same order we see on other browsers.
     hasProps(pc.getTransceivers(),
       [
         {
-          receiver: {track: {kind: "audio", readyState: "live"}},
+          receiver: {track: {kind: "audio", readyState: "live", muted: true}},
           sender: {track: null},
           direction: "sendrecv",
           mid: null,
           currentDirection: null,
           stopped: false
         },
         {
-          receiver: {track: {kind: "video", readyState: "live"}},
+          receiver: {track: {kind: "video", readyState: "live", muted: true}},
           sender: {track: null},
           direction: "sendrecv",
           mid: null,
           currentDirection: null,
           stopped: false
         }
       ]);
 
@@ -683,17 +701,16 @@
     trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, offer);
     hasProps(trackEvents, []);
 
     hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
 
     answer = await pc1.createAnswer();
     hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
 
-    // TODO(bug 1400363): Check onmute/muted
     await pc1.setLocalDescription(answer);
     hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
 
     trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, answer);
     hasProps(trackEvents, []);
 
     hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
 
@@ -708,17 +725,16 @@
     trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, offer);
     hasProps(trackEvents, []);
 
     hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
 
     answer = await pc1.createAnswer();
     hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
 
-    // TODO(bug 1400363): Check onunmute/muted
     await pc1.setLocalDescription(answer);
     hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
 
     trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, answer);
     hasProps(trackEvents,
       [
         {
           track: pc2.getTransceivers()[0].receiver.track,
@@ -775,16 +791,143 @@
     await iceConnected(pc1);
     await iceConnected(pc2);
 
     pc1.close();
     pc2.close();
     stopTracks(stream);
   };
 
+  let checkMute = async () => {
+    let pc1 = new RTCPeerConnection();
+    let stream1 = await getUserMedia({audio: true, video: true});
+    let audio1 = stream1.getAudioTracks()[0];
+    pc1.addTrack(audio1, stream1);
+    let countMuteAudio1 = countEvents(pc1.getTransceivers()[0].receiver.track, "mute");
+    let countUnmuteAudio1 = countEvents(pc1.getTransceivers()[0].receiver.track, "unmute");
+
+    let video1 = stream1.getVideoTracks()[0];
+    pc1.addTrack(video1, stream1);
+    let countMuteVideo1 = countEvents(pc1.getTransceivers()[1].receiver.track, "mute");
+    let countUnmuteVideo1 = countEvents(pc1.getTransceivers()[1].receiver.track, "unmute");
+
+    let pc2 = new RTCPeerConnection();
+    let stream2 = await getUserMedia({audio: true, video: true});
+    let audio2 = stream2.getAudioTracks()[0];
+    pc2.addTrack(audio2, stream2);
+    let countMuteAudio2 = countEvents(pc2.getTransceivers()[0].receiver.track, "mute");
+    let countUnmuteAudio2 = countEvents(pc2.getTransceivers()[0].receiver.track, "unmute");
+
+    let video2 = stream2.getVideoTracks()[0];
+    pc2.addTrack(video2, stream2);
+    let countMuteVideo2 = countEvents(pc2.getTransceivers()[1].receiver.track, "mute");
+    let countUnmuteVideo2 = countEvents(pc2.getTransceivers()[1].receiver.track, "unmute");
+
+
+    // Check that receive tracks start muted
+    hasProps(pc1.getTransceivers(),
+      [
+        {receiver: {track: {kind: "audio", muted: true}}},
+        {receiver: {track: {kind: "video", muted: true}}}
+      ]);
+
+    hasProps(pc1.getTransceivers(),
+      [
+        {receiver: {track: {kind: "audio", muted: true}}},
+        {receiver: {track: {kind: "video", muted: true}}}
+      ]);
+
+    let offer = await pc1.createOffer();
+    await pc2.setRemoteDescription(offer);
+    trickle(pc1, pc2);
+    await pc1.setLocalDescription(offer);
+    let answer = await pc2.createAnswer();
+    await pc1.setRemoteDescription(answer);
+    trickle(pc2, pc1);
+    await pc2.setLocalDescription(answer);
+
+    let gotUnmuteAudio1 = gotUnmuteEvent(pc1.getTransceivers()[0].receiver.track);
+    let gotUnmuteVideo1 = gotUnmuteEvent(pc1.getTransceivers()[1].receiver.track);
+
+    let gotUnmuteAudio2 = gotUnmuteEvent(pc2.getTransceivers()[0].receiver.track);
+    let gotUnmuteVideo2 = gotUnmuteEvent(pc2.getTransceivers()[1].receiver.track);
+
+    await iceConnected(pc1);
+    await iceConnected(pc2);
+
+    // Check that receive tracks are unmuted when RTP starts flowing
+    await gotUnmuteAudio1;
+    await gotUnmuteVideo1;
+    await gotUnmuteAudio2;
+    await gotUnmuteVideo2;
+
+    // Check whether disabling recv locally causes onmute
+    pc1.getTransceivers()[0].direction = "sendonly";
+    pc1.getTransceivers()[1].direction = "sendonly";
+    offer = await pc1.createOffer();
+    await pc2.setRemoteDescription(offer);
+    await pc1.setLocalDescription(offer);
+    answer = await pc2.createAnswer();
+    let gotMuteAudio1 = gotMuteEvent(pc1.getTransceivers()[0].receiver.track);
+    let gotMuteVideo1 = gotMuteEvent(pc1.getTransceivers()[1].receiver.track);
+    await pc1.setRemoteDescription(answer);
+    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 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();
+    gotUnmuteAudio1 = gotUnmuteEvent(pc1.getTransceivers()[0].receiver.track);
+    gotUnmuteVideo1 = gotUnmuteEvent(pc1.getTransceivers()[1].receiver.track);
+    gotUnmuteAudio2 = gotUnmuteEvent(pc2.getTransceivers()[0].receiver.track);
+    gotUnmuteVideo2 = gotUnmuteEvent(pc2.getTransceivers()[1].receiver.track);
+    await pc1.setRemoteDescription(answer);
+    await pc2.setLocalDescription(answer);
+    await gotUnmuteAudio1;
+    await gotUnmuteVideo1;
+    await gotUnmuteAudio2;
+    await gotUnmuteVideo2;
+
+    // Wait a little, just in case some stray events fire
+    await wait(100);
+
+    is(1, countMuteAudio1.count, "Got 1 mute event for pc1's audio track");
+    is(1, countMuteVideo1.count, "Got 1 mute event for pc1's video track");
+    is(1, countMuteAudio2.count, "Got 1 mute event for pc2's audio track");
+    is(1, countMuteVideo2.count, "Got 1 mute event for pc2's video track");
+    is(2, countUnmuteAudio1.count, "Got 2 unmute events for pc1's audio track");
+    is(2, countUnmuteVideo1.count, "Got 2 unmute events for pc1's video track");
+    is(2, countUnmuteAudio2.count, "Got 2 unmute events for pc2's audio track");
+    is(2, countUnmuteVideo2.count, "Got 2 unmute events for pc2's video track");
+
+    pc1.close();
+    pc2.close();
+    stopTracks(stream1);
+    stopTracks(stream2);
+  };
+
   let checkStop = async () => {
     let pc1 = new RTCPeerConnection();
     let stream = await getUserMedia({audio: true});
     let track = stream.getAudioTracks()[0];
     pc1.addTrack(track, stream);
 
     let offer = await pc1.createOffer();
     await pc1.setLocalDescription(offer);
@@ -1685,16 +1828,17 @@
     await checkCurrentDirection();
     await checkSendrecvWithNoSendTrack();
     await checkAddTransceiverNoTrackDoesntPair();
     await checkAddTransceiverWithTrackDoesntPair();
     await checkAddTransceiverThenReplaceTrackDoesntPair();
     await checkAddTransceiverThenAddTrackPairs();
     await checkAddTrackPairs();
     await checkReplaceTrackNullDoesntPreventPairing();
+    await checkMute();
     await checkStop();
     await checkStopAfterCreateOffer();
     await checkStopAfterSetLocalOffer();
     await checkStopAfterSetRemoteOffer();
     await checkStopAfterCreateAnswer();
     await checkStopAfterSetLocalAnswer();
     await checkStopAfterClose();
     await checkLocalRollback();
--- a/dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html
+++ b/dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html
@@ -22,17 +22,28 @@
 
     test.chain.replace("PC_LOCAL_GUM", [
       function PC_LOCAL_CANVAS_CAPTURESTREAM(test) {
         test.pcLocal.attachLocalStream(emitter.stream());
         emitter.start();
       }
     ]);
 
+    var haveFirstUnmuteEvent;
+
+    test.chain.insertBefore("PC_REMOTE_SET_LOCAL_DESCRIPTION", [
+      function PC_REMOTE_SETUP_ONUNMUTE_1() {
+        haveFirstUnmuteEvent = haveEvent(test.pcRemote._pc.getReceivers()[0].track, "unmute");
+      }
+    ]);
+
     test.chain.append([
+      function PC_REMOTE_CHECK_VIDEO_UNMUTED() {
+        return haveFirstUnmuteEvent;
+      },
       function PC_REMOTE_WAIT_FOR_FRAMES() {
         var vremote = test.pcRemote.remoteMediaElements[0];
         ok(vremote, "Should have remote video element for pcRemote");
         return addFinallyToPromise(helper.checkVideoPlaying(vremote))
             .finally(() => emitter.stop());
       }
     ]);