Bug 934512 - Test that MediaStreamAudioSourceNode does not get GCed while it has live audio tracks. r?padenot draft
authorAndreas Pehrson <pehrsons@gmail.com>
Wed, 29 Jun 2016 12:27:44 +0200
changeset 382264 25ad359798267fb69a8278a8845d6950bc443186
parent 382263 16cea127fef62da96df364d9943c85a5b4c5e3a2
child 382265 4c4502793194961a0bb9ddbec6ae589a7f11ada7
push id21678
push userpehrsons@gmail.com
push dateWed, 29 Jun 2016 12:45:55 +0000
reviewerspadenot
bugs934512
milestone50.0a1
Bug 934512 - Test that MediaStreamAudioSourceNode does not get GCed while it has live audio tracks. r?padenot MozReview-Commit-ID: u5Qh2aC7gI
dom/media/webaudio/test/mochitest.ini
dom/media/webaudio/test/test_mediaStreamAudioSourceNodeNoGC.html
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -140,16 +140,17 @@ tags=capturestream
 skip-if = toolkit == 'android' # bug 1145816
 [test_mediaElementAudioSourceNodeCrossOrigin.html]
 tags=capturestream
 skip-if = toolkit == 'android' # bug 1145816
 [test_mediaStreamAudioDestinationNode.html]
 [test_mediaStreamAudioSourceNode.html]
 [test_mediaStreamAudioSourceNodeCrossOrigin.html]
 tags=capturestream
+[test_mediaStreamAudioSourceNodeNoGC.html]
 [test_mediaStreamAudioSourceNodePassThrough.html]
 [test_mediaStreamAudioSourceNodeResampling.html]
 tags=capturestream
 [test_mixingRules.html]
 skip-if = toolkit == 'android' # bug 1091965
 [test_mozaudiochannel.html]
 # Android: bug 1061675; OSX 10.6: bug 1097721
 skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') || (os == 'mac' && os_version == '10.6')
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/test/test_mediaStreamAudioSourceNodeNoGC.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<meta charset="utf-8">
+<head>
+  <title>Test that MediaStreamAudioSourceNode and its input MediaStream stays alive while there are active tracks</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("gUM and WebAudio data is async to main thread. " +
+                               "We need a timeout to see that something does " +
+                               "NOT happen to data.");
+
+var context = new AudioContext();
+var analyser = context.createAnalyser();
+
+function wait(millis, resolveWithThis) {
+  return new Promise(resolve => setTimeout(() => resolve(resolveWithThis), millis));
+}
+
+function binIndexForFrequency(frequency) {
+  return 1 + Math.round(frequency * analyser.fftSize / context.sampleRate);
+}
+
+function waitForAudio(analysisFunction, cancelPromise) {
+  var data = new Uint8Array(analyser.frequencyBinCount);
+  var cancelled = false;
+  var cancelledMsg = "";
+  cancelPromise.then(msg => {
+    cancelled = true;
+    cancelledMsg = msg;
+  });
+  return new Promise((resolve, reject) => {
+    var loop = () => {
+      analyser.getByteFrequencyData(data);
+      if (cancelled) {
+        reject(new Error("waitForAudio cancelled: " + cancelledMsg));
+        return;
+      }
+      if (analysisFunction(data)) {
+        resolve();
+        return;
+      }
+      requestAnimationFrame(loop);
+    };
+    loop();
+  });
+}
+
+navigator.mediaDevices.getUserMedia({audio: true, fake: true})
+  .then(stream => {
+    stream.onended = () => ended = true;
+    let source = context.createMediaStreamSource(stream);
+    source.connect(analyser);
+    analyser.connect(context.destination);
+  })
+  .then(() => {
+    ok(true, "Waiting for audio to pass through the analyser")
+    return waitForAudio(arr => arr[binIndexForFrequency(1000)] > 200,
+                        wait(60000, "Timeout waiting for audio"));
+  })
+  .then(() => {
+    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)"))
+                  .then(() => Promise.reject("Audio stopped unexpectedly"),
+                        () => Promise.resolve());
+  })
+  .then(() => {
+    ok(true, "Audio is still flowing");
+    SimpleTest.finish();
+  })
+  .catch(e => {
+    ok(false, "Error executing test: " + e + (e.stack ? "\n" + e.stack : ""));
+    SimpleTest.finish();
+  });
+</script>
+</pre>
+</body>
+</html>