Bug 1436523 - Update dom/media/tests/mochitest tests to better handle loopback devices. r?achronop draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Mon, 26 Feb 2018 12:20:40 -0500
changeset 773434 c06d5d6cf097f5da035f747ce681786c60a22f71
parent 773433 a55255734449384822f6cfaa4036f67e0881f791
child 773435 0d2e6c4f657a35f824a2975982241500d16e95cc
push id104235
push userbvandyk@mozilla.com
push dateTue, 27 Mar 2018 22:55:40 +0000
reviewersachronop
bugs1436523, 1436424
milestone61.0a1
Bug 1436523 - Update dom/media/tests/mochitest tests to better handle loopback devices. r?achronop With changes giving loopback devices higher precedence in testing, various tests in dom/media/tests/mochitest have been updated to accommodate this. Many tests just worked, but some require tweaks, or to explicitly request fake devices. Also update webaudio's test_mediaStreamAudioSourceNodeGC test to explicitly use fake devices. This test does not have the loopback tone exposed to it in JS, so is unabel to adjust the loopback tone to suit its needs. Various tests are updated to set fake device prefs instead of requesting via gUM to move away from non-standard behaviour per bug 1436424. MozReview-Commit-ID: 5GAVZFzF2hq
dom/media/tests/mochitest/identity/test_fingerprints.html
dom/media/tests/mochitest/test_getUserMedia_constraints.html
dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html
dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html
dom/media/tests/mochitest/test_peerConnection_audioCodecs.html
dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html
dom/media/tests/mochitest/test_peerConnection_trackDisabling.html
dom/media/tests/mochitest/test_peerConnection_trackDisabling_clones.html
dom/media/tests/mochitest/test_peerConnection_videoCodecs.html
dom/media/webaudio/test/test_mediaStreamAudioSourceNodeNoGC.html
--- a/dom/media/tests/mochitest/identity/test_fingerprints.html
+++ b/dom/media/tests/mochitest/identity/test_fingerprints.html
@@ -56,19 +56,19 @@ function testMultipleFingerprints() {
   var pcDouble = new RTCPeerConnection({});
 
   var offer, match, fingerprints;
 
   var fail = msg =>
       (e => ok(false, 'error in ' + msg + ': ' +
                (e.message ? (e.message + '\n' + e.stack) : e)));
 
-  navigator.mediaDevices.getUserMedia({ audio: true, fake: true })
+  navigator.mediaDevices.getUserMedia({ audio: true })
     .then(stream => {
-      ok(stream, 'Got fake stream');
+      ok(stream, 'Got test stream');
       pcDouble.addStream(stream);
       return pcDouble.createOffer();
     })
     .then(o => {
       offer = o;
       ok(offer, 'Got offer');
 
       match = offer.sdp.match(fingerprintRegex);
@@ -99,13 +99,23 @@ function testMultipleFingerprints() {
       pcStrict.close();
       pcDouble.close();
       SimpleTest.finish();
     });
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({
-  set: [ [ 'media.peerconnection.identity.enabled', true ] ]
+  set: [
+    [ 'media.peerconnection.identity.enabled', true ],
+    // Disable permission to skip prompt when on platforms the use loopback
+    // test devices (these would normally trigger a prompt).
+    [ 'media.navigator.permission.disabled', true ],
+    // Since this test doesn't include head.js or pc.js, we need to set the fake
+    // device pref manually. On platforms where loopback devices are used they
+    // should still take precedence, however on some platforms no prefs would
+    // be set and the test would fail.
+    [ 'media.navigator.streams.fake', true ]
+  ]
 }, testMultipleFingerprints);
 </script>
   </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html
@@ -43,20 +43,20 @@ var tests = [
   { message: "unknown mediaSource in audio fails",
     constraints: { audio: { mediaSource: 'uncle' } },
     error: "OverconstrainedError",
     constraint: "mediaSource" },
   { message: "emtpy constraint fails",
     constraints: { },
     error: "TypeError" },
   { message: "Triggering mock failure in default video device fails",
-    constraints: { video: { deviceId: 'bad device' }, fake: true },
+    constraints: { video: { deviceId: 'bad device' } },
     error: "NotReadableError" },
   { message: "Triggering mock failure in default audio device fails",
-    constraints: { audio: { deviceId: 'bad device' }, fake: true },
+    constraints: { audio: { deviceId: 'bad device' } },
     error: "NotReadableError" },
   { message: "Success-path: optional video facingMode + audio ignoring facingMode",
     constraints: { audio: { mediaSource: 'microphone',
                             facingMode: 'left',
                             foo: 0,
                             advanced: [{ facingMode: 'environment' },
                                        { facingMode: 'user' },
                                        { bar: 0 }] },
@@ -96,17 +96,23 @@ var mustFailWith = (msg, reason, constra
     }
   });
 
 /**
  * Starts the test run by running through each constraint
  * test by verifying that the right resolution and rejection is fired.
  */
 
-runTest(() => Promise.resolve()
+runTest(() => pushPrefs(
+    // This test expects fake devices, particularly for the 'triggering mock
+    // failure *' steps. So explicitly disable loopback and setup fakes
+    ['media.audio_loopback_dev', ''],
+    ['media.video_loopback_dev', ''],
+    ['media.navigator.streams.fake', true]
+  )
   .then(() => {
     // Check supported constraints first.
     var dict = navigator.mediaDevices.getSupportedConstraints();
     var supported = Object.keys(dict);
 
     mustSupport.forEach(key => ok(supported.includes(key) && dict[key],
                                   "Supports " + key));
 
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
@@ -15,18 +15,25 @@ createHTML({
 });
 
 var gUMVideoElement;
 var captureStreamElement;
 
 const pausedTimeout = 1000;
 let h;
 
-runTest(() => getUserMedia({video: true, fake: true})
-  .then(stream => {
+runTest(async () => {
+  try {
+    await pushPrefs(
+      // This test expects fake video devices, as it expects captured frames to
+      // shift over time, which is not currently provided by loopback devices
+      ['media.video_loopback_dev', ''],
+      ['media.navigator.streams.fake', true]);
+
+    let stream = await getUserMedia({video: true});
     h = new VideoStreamHelper();
     gUMVideoElement =
       createMediaElement("video", "gUMVideo");
     gUMVideoElement.srcObject = stream;
     gUMVideoElement.play();
 
     info("Capturing");
     captureStreamElement =
@@ -37,58 +44,47 @@ runTest(() => getUserMedia({video: true,
     // Adding a dummy audio track to the stream will keep a consuming media
     // element from ending.
     // We could also solve it by repeatedly play()ing or autoplay, but then we
     // wouldn't be sure the media element stopped rendering video because it
     // went to the ended state or because there were no frames for the track.
     let osc = createOscillatorStream(new AudioContext(), 1000);
     captureStreamElement.srcObject.addTrack(osc.getTracks()[0]);
 
-    return h.checkVideoPlaying(captureStreamElement);
-  })
-  .then(() => {
+    await h.checkVideoPlaying(captureStreamElement);
     info("Video flowing. Pausing.");
     gUMVideoElement.pause();
+    await h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
 
-    return h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
-  })
-  .then(() => {
     info("Video stopped flowing. Playing.");
     gUMVideoElement.play();
+    await h.checkVideoPlaying(captureStreamElement);
 
-    return h.checkVideoPlaying(captureStreamElement);
-  })
-  .then(() => {
     info("Video flowing. Removing source.");
-    var stream = gUMVideoElement.srcObject;
+    stream = gUMVideoElement.srcObject;
     gUMVideoElement.srcObject = null;
+    await h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
 
-    return h.checkVideoPaused(captureStreamElement, { time: pausedTimeout })
-        .then(() => stream);
-  })
-  .then(stream => {
     info("Video stopped flowing. Setting source.");
     gUMVideoElement.srcObject = stream;
-    return h.checkVideoPlaying(captureStreamElement);
-  })
-  .then(() => {
+    await h.checkVideoPlaying(captureStreamElement);
+
     info("Video flowing. Changing source by track manipulation. Remove first.");
-    var track = gUMVideoElement.srcObject.getTracks()[0];
+    let track = gUMVideoElement.srcObject.getTracks()[0];
     gUMVideoElement.srcObject.removeTrack(track);
-    return h.checkVideoPaused(captureStreamElement, { time: pausedTimeout })
-        .then(() => track);
-  })
-  .then(track => {
+    await h.checkVideoPaused(captureStreamElement, { time: pausedTimeout });
+
     info("Video paused. Changing source by track manipulation. Add first.");
     gUMVideoElement.srcObject.addTrack(track);
     gUMVideoElement.play();
-    return h.checkVideoPlaying(captureStreamElement);
-  })
-  .then(() => {
+    await h.checkVideoPlaying(captureStreamElement);
+
     gUMVideoElement.srcObject.getTracks().forEach(t => t.stop());
     ok(true, "Test passed.");
-  })
-  .catch(e => ok(false, "Test failed: " + e + (e.stack ? "\n" + e.stack : ""))));
+  } catch (e) {
+    ok(false, "Test failed: " + e + (e.stack ? "\n" + e.stack : ""));
+  }
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html
@@ -7,26 +7,30 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "1017888",
     title: "Renegotiation: add second video stream"
   });
 
-  runNetworkTest(function (options) {
+  runNetworkTest(async function (options) {
+    // Use fake video here since the native fake device on linux doesn't
+    // change color as needed by checkVideoPlaying() below.
+    await pushPrefs(
+      ['media.video_loopback_dev', ''],
+      ['media.navigator.streams.fake', true]);
+
     const test = new PeerConnectionTest(options);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_ADD_SECOND_STREAM(test) {
           test.setMediaConstraints([{video: true}, {video: true}],
                                    [{video: true}]);
-          // 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}]);
+          return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
         },
       ],
       [
         function PC_REMOTE_CHECK_VIDEO_FLOW(test) {
           const h = new VideoStreamHelper();
           is(test.pcRemote.remoteMediaElements.length, 2,
              "Should have two remote media elements after renegotiation");
           return Promise.all(test.pcRemote.remoteMediaElements.map(video =>
--- a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html
@@ -7,45 +7,49 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "1017888",
     title: "Renegotiation: add second video stream, no bundle"
   });
 
-  runNetworkTest(function (options = {}) {
+  runNetworkTest(async function (options = {}) {
+    // Use fake video here since the native fake device on linux doesn't
+    // change color as needed by checkVideoPlaying() below.
+    await pushPrefs(
+      ['media.video_loopback_dev', ''],
+      ['media.navigator.streams.fake', true]);
+
     options.bundle = false;
     const test = new PeerConnectionTest(options);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_ADD_SECOND_STREAM(test) {
           test.setMediaConstraints([{video: true}, {video: true}],
                                    [{video: true}]);
           // Since this is a NoBundle variant, adding a track will cause us to
           // go back to checking.
           test.pcLocal.expectIceChecking();
-          // 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}]);
+          return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
         },
         function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
           test.pcRemote.expectIceChecking();
         },
       ],
       [
         function PC_REMOTE_CHECK_VIDEO_FLOW(test) {
           const h = new VideoStreamHelper();
           is(test.pcRemote.remoteMediaElements.length, 2,
              "Should have two remote media elements after renegotiation");
           return Promise.all(test.pcRemote.remoteMediaElements.map(video =>
             h.checkVideoPlaying(video)));
         },
       ]
     );
 
-    test.setMediaConstraints([{video: true, fake: true}], [{video: true}]);
+    test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_audioCodecs.html
+++ b/dom/media/tests/mochitest/test_peerConnection_audioCodecs.html
@@ -15,17 +15,17 @@
   // So all other present codecs can be removed.
   const codecs = [ "opus", "G722", "PCMU", "PCMA" ];
 
   async function testAudioCodec(options = {}, codec) {
     // sdputils checks for opus as part of its sdp sanity test
     options.opus = codec == "opus";
 
     let test = new PeerConnectionTest(options);
-    test.setMediaConstraints([{audio: true, fake: true}], []);
+    test.setMediaConstraints([{audio: true}], []);
 
     test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [
       function PC_LOCAL_FILTER_OUT_CODECS() {
         let otherCodec = codecs.find(c => c != codec);
         let otherId = sdputils.findCodecId(test.originalOffer.sdp, otherCodec);
 
         let id = sdputils.findCodecId(test.originalOffer.sdp, codec);
         test.originalOffer.sdp =
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
@@ -7,17 +7,23 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "1017888",
     title: "Renegotiation: remove then add video track"
   });
 
-  runNetworkTest(function (options) {
+  runNetworkTest(async function (options) {
+    // Use fake video here since the native fake device on linux doesn't
+    // change color as needed by checkVideoPlaying() below.
+    await pushPrefs(
+      ['media.video_loopback_dev', ''],
+      ['media.navigator.streams.fake', true]);
+
     const test = new PeerConnectionTest(options);
     const helper = new VideoStreamHelper();
     var originalTrack;
     let haveMuteEvent = new Promise(() => {});
     let haveUnmuteEvent = new Promise(() => {});
     addRenegotiation(test.chain,
       [
         function PC_REMOTE_FIND_RECEIVER(test) {
@@ -28,19 +34,17 @@
         function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
           // 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.removeSender(0);
         },
         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}]);
+          return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
         },
       ],
       [
         function PC_REMOTE_WAIT_FOR_UNMUTE() {
           return haveUnmuteEvent;
         },
         function PC_REMOTE_CHECK_ADDED_TRACK(test) {
           is(test.pcRemote._pc.getTransceivers().length, 2,
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html
@@ -7,17 +7,23 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "1017888",
     title: "Renegotiation: remove then add video track, no bundle"
   });
 
-  runNetworkTest(function (options) {
+  runNetworkTest(async function (options) {
+    // Use fake video here since the native fake device on linux doesn't
+    // change color as needed by checkVideoPlaying() below.
+    await pushPrefs(
+      ['media.video_loopback_dev', ''],
+      ['media.navigator.streams.fake', true]);
+
     options = options || { };
     options.bundle = false;
     const test = new PeerConnectionTest(options);
     const helper = new VideoStreamHelper();
     var originalTrack;
     addRenegotiation(test.chain,
       [
         function PC_REMOTE_FIND_RECEIVER(test) {
@@ -30,17 +36,17 @@
           // 0, but the remote side will keep its old pipeline and packet
           // count.
           test.pcLocal.disableRtpCountChecking = true;
           return test.pcLocal.removeSender(0);
         },
         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}]);
+          return test.pcLocal.getAllUserMediaAndAddStreams([{video: true}]);
         },
         function PC_LOCAL_EXPECT_ICE_CHECKING(test) {
           test.pcLocal.expectIceChecking();
         },
         function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
           test.pcRemote.expectIceChecking();
         },
       ],
--- a/dom/media/tests/mochitest/test_peerConnection_trackDisabling.html
+++ b/dom/media/tests/mochitest/test_peerConnection_trackDisabling.html
@@ -14,17 +14,22 @@ createHTML({
 
 runNetworkTest(async () => {
   var test = new PeerConnectionTest();
 
   await pushPrefs(
     ["media.getusermedia.camera.stop_on_disable.enabled", true],
     ["media.getusermedia.camera.stop_on_disable.delay_ms", 0],
     ["media.getusermedia.microphone.stop_on_disable.enabled", true],
-    ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0]);
+    ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0],
+    // Always use fake tracks since we depend on video to be somewhat green and
+    // audio to have a large 1000Hz component (or 440Hz if using fake devices).
+    ['media.audio_loopback_dev', ''],
+    ['media.video_loopback_dev', ''],
+    ['media.navigator.streams.fake', true]);
 
   test.setMediaConstraints([{audio: true, video: true}], []);
   test.chain.append([
     function CHECK_ASSUMPTIONS() {
       is(test.pcLocal.localMediaElements.length, 2,
          "pcLocal should have one media element");
       is(test.pcRemote.remoteMediaElements.length, 2,
          "pcRemote should have one media element");
--- a/dom/media/tests/mochitest/test_peerConnection_trackDisabling_clones.html
+++ b/dom/media/tests/mochitest/test_peerConnection_trackDisabling_clones.html
@@ -14,17 +14,21 @@ createHTML({
 
 runNetworkTest(async () => {
   var test = new PeerConnectionTest();
 
   await pushPrefs(
     ["media.getusermedia.camera.stop_on_disable.enabled", true],
     ["media.getusermedia.camera.stop_on_disable.delay_ms", 0],
     ["media.getusermedia.microphone.stop_on_disable.enabled", true],
-    ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0]);
+    ["media.getusermedia.microphone.stop_on_disable.delay_ms", 0],
+    // Always use fake tracks since we depend on audio to have a large 1000Hz
+    // component.
+    ['media.audio_loopback_dev', ''],
+    ['media.navigator.streams.fake', true]);
 
   var originalStream;
   var localVideoOriginal;
 
   test.setMediaConstraints([{audio: true, video: true}], []);
   test.chain.replace("PC_LOCAL_GUM", [
     function PC_LOCAL_GUM_CLONE() {
       return getUserMedia(test.pcLocal.constraints[0]).then(stream => {
--- a/dom/media/tests/mochitest/test_peerConnection_videoCodecs.html
+++ b/dom/media/tests/mochitest/test_peerConnection_videoCodecs.html
@@ -9,17 +9,17 @@
 <script type="application/javascript">
   createHTML({
     bug: "1395853",
     title: "Verify video content over WebRTC for every video codec",
   });
 
   async function testVideoCodec(options = {}, codec) {
     let test = new PeerConnectionTest(options);
-    test.setMediaConstraints([{video: true, fake: true}], []);
+    test.setMediaConstraints([{video: true}], []);
 
     test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [
       function PC_LOCAL_FILTER_OUT_CODECS() {
         let otherCodec = codecs.find(c => c != codec);
         let otherId = sdputils.findCodecId(test.originalOffer.sdp, otherCodec.name, otherCodec.offset);
         let otherRtpmapMatcher = new RegExp(`a=rtpmap:${otherId}.*\\r\\n`, "gi");
 
         let id = sdputils.findCodecId(test.originalOffer.sdp, codec.name, codec.offset);
@@ -67,16 +67,21 @@
   const codecs = [
     { name: "VP8" },
     { name: "VP9" },
     { name: "H264" },
     { name: "H264", offset: 1 },
   ];
 
   runNetworkTest(async (options) => {
+    // This test expects the video being captured will change color. Use fake
+    // video device as loopback does not currently change.
+    await pushPrefs(
+      ['media.video_loopback_dev', ''],
+      ['media.navigator.streams.fake', true]);
     for (let codec of codecs) {
       info(`Testing video for codec ${codec.name}`);
       try {
         await testVideoCodec(options, codec);
       } catch(e) {
         ok(false, `Error in test for codec ${codec.name}: ${e}\n${e.stack}`);
       }
       info(`Tested video for codec ${codec.name}`);
--- a/dom/media/webaudio/test/test_mediaStreamAudioSourceNodeNoGC.html
+++ b/dom/media/webaudio/test/test_mediaStreamAudioSourceNodeNoGC.html
@@ -45,45 +45,51 @@ function waitForAudio(analysisFunction, 
         return;
       }
       requestAnimationFrame(loop);
     };
     loop();
   });
 }
 
-navigator.mediaDevices.getUserMedia({audio: true, fake: true})
-  .then(stream => {
+SpecialPowers.pushPrefEnv({
+  set: [
+    // This test expects the fake audio device, specifically for the tones
+    // it outputs. Explicitly disable the audio loopback device and enable
+    // fake streams.
+    ['media.audio_loopback_dev', ''],
+    ['media.navigator.streams.fake', true]
+  ]
+}).then(async () => {
+  try {
+    let stream = await navigator.mediaDevices.getUserMedia({audio: true});
     stream.onended = () => ended = true;
     let source = context.createMediaStreamSource(stream);
     source.connect(analyser);
-    analyser.connect(context.destination);
-  })
-  .then(() => {
+    await analyser.connect(context.destination);
+
     ok(true, "Waiting for audio to pass through the analyser")
-    return waitForAudio(arr => arr[binIndexForFrequency(1000)] > 200,
-                        wait(60000, "Timeout waiting for audio"));
-  })
-  .then(() => {
+    await waitForAudio(arr => arr[binIndexForFrequency(1000)] > 200,
+                       wait(60000, "Timeout waiting for audio"));
+
     ok(true, "Audio was detected by the analyser. Forcing CC.");
     SpecialPowers.forceCC();
     SpecialPowers.forceGC();
     SpecialPowers.forceCC();
     SpecialPowers.forceGC();
 
     info("Checking that GC didn't destroy the stream or source node");
-    return waitForAudio(arr => arr[binIndexForFrequency(1000)] < 50,
-                        wait(5000, "Timeout waiting for GC (timeout OK)"))
+    await waitForAudio(arr => arr[binIndexForFrequency(1000)] < 50,
+                       wait(5000, "Timeout waiting for GC (timeout OK)"))
                   .then(() => Promise.reject("Audio stopped unexpectedly"),
                         () => Promise.resolve());
-  })
-  .then(() => {
+
     ok(true, "Audio is still flowing");
     SimpleTest.finish();
-  })
-  .catch(e => {
+  } catch(e) {
     ok(false, "Error executing test: " + e + (e.stack ? "\n" + e.stack : ""));
     SimpleTest.finish();
-  });
+  }
+});
 </script>
 </pre>
 </body>
 </html>