Bug 1007776 - Add a devtools API for muting the source AudioNodes; r=roc,smaug
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 19 Aug 2014 08:12:43 -0400
changeset 200254 eb7712477525ae30ecf1d95569abaf5932522c0f
parent 200253 77bf46f52906ecd6c09a13539642be83471661a1
child 200255 3fe332bf3dcb01cc4c6a178f85d8cb3ade887265
push id47857
push usereakhgari@mozilla.com
push dateTue, 19 Aug 2014 12:12:53 +0000
treeherdermozilla-inbound@eb7712477525 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, smaug
bugs1007776
milestone34.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 1007776 - Add a devtools API for muting the source AudioNodes; r=roc,smaug
content/media/AudioNodeExternalInputStream.cpp
content/media/webaudio/AudioNode.cpp
content/media/webaudio/test/mochitest.ini
content/media/webaudio/test/test_audioBufferSourceNodePassThrough.html
content/media/webaudio/test/test_mediaElementAudioSourceNodePassThrough.html
content/media/webaudio/test/test_mediaStreamAudioSourceNodePassThrough.html
content/media/webaudio/test/test_oscillatorNodePassThrough.html
dom/webidl/AudioBufferSourceNode.webidl
dom/webidl/MediaElementAudioSourceNode.webidl
dom/webidl/MediaStreamAudioSourceNode.webidl
dom/webidl/OscillatorNode.webidl
--- a/content/media/AudioNodeExternalInputStream.cpp
+++ b/content/media/AudioNodeExternalInputStream.cpp
@@ -319,17 +319,17 @@ void
 AudioNodeExternalInputStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
                                            uint32_t aFlags)
 {
   // According to spec, number of outputs is always 1.
   mLastChunks.SetLength(1);
 
   // GC stuff can result in our input stream being destroyed before this stream.
   // Handle that.
-  if (!IsEnabled() || mInputs.IsEmpty()) {
+  if (!IsEnabled() || mInputs.IsEmpty() || mPassThrough) {
     mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
     AdvanceOutputSegment();
     return;
   }
 
   MOZ_ASSERT(mInputs.Length() == 1);
 
   MediaStream* source = mInputs[0]->GetSource();
--- a/content/media/webaudio/AudioNode.cpp
+++ b/content/media/webaudio/AudioNode.cpp
@@ -415,24 +415,24 @@ void
 AudioNode::RemoveOutputParam(AudioParam* aParam)
 {
   mOutputParams.RemoveElement(aParam);
 }
 
 bool
 AudioNode::PassThrough() const
 {
-  MOZ_ASSERT(NumberOfInputs() == 1 && NumberOfOutputs() == 1);
+  MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1);
   return mPassThrough;
 }
 
 void
 AudioNode::SetPassThrough(bool aPassThrough)
 {
-  MOZ_ASSERT(NumberOfInputs() == 1 && NumberOfOutputs() == 1);
+  MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1);
   mPassThrough = aPassThrough;
   AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
   MOZ_ASSERT(ns, "How come we don't have a stream here?");
   ns->SetPassThrough(mPassThrough);
 }
 
 }
 }
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -33,16 +33,17 @@ support-files =
 [test_audioBufferSourceNodeLoop.html]
 [test_audioBufferSourceNodeLoopStartEnd.html]
 [test_audioBufferSourceNodeLoopStartEndSame.html]
 [test_audioBufferSourceNodeNeutered.html]
 [test_audioBufferSourceNodeNoStart.html]
 [test_audioBufferSourceNodeNullBuffer.html]
 [test_audioBufferSourceNodeOffset.html]
 skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752
+[test_audioBufferSourceNodePassThrough.html]
 [test_AudioContext.html]
 [test_audioDestinationNode.html]
 [test_AudioListener.html]
 [test_audioParamExponentialRamp.html]
 [test_audioParamGain.html]
 [test_audioParamLinearRamp.html]
 [test_audioParamSetCurveAtTime.html]
 [test_audioParamSetCurveAtTimeZeroDuration.html]
@@ -95,29 +96,32 @@ skip-if = (toolkit == 'gonk' && !debug) 
 [test_dynamicsCompressorNode.html]
 [test_dynamicsCompressorNodePassThrough.html]
 [test_gainNode.html]
 [test_gainNodeInLoop.html]
 [test_gainNodePassThrough.html]
 [test_maxChannelCount.html]
 [test_mediaDecoding.html]
 [test_mediaElementAudioSourceNode.html]
+[test_mediaElementAudioSourceNodePassThrough.html]
 [test_mediaStreamAudioDestinationNode.html]
 [test_mediaStreamAudioSourceNode.html]
 [test_mediaStreamAudioSourceNodeCrossOrigin.html]
+[test_mediaStreamAudioSourceNodePassThrough.html]
 [test_mediaStreamAudioSourceNodeResampling.html]
 [test_mixingRules.html]
 [test_mozaudiochannel.html]
 skip-if = (toolkit == 'gonk' && !debug)
 [test_nodeToParamConnection.html]
 [test_OfflineAudioContext.html]
 [test_offlineDestinationChannelCountLess.html]
 [test_offlineDestinationChannelCountMore.html]
 [test_oscillatorNode.html]
 [test_oscillatorNode2.html]
+[test_oscillatorNodePassThrough.html]
 [test_oscillatorNodeStart.html]
 [test_oscillatorTypeChange.html]
 [test_pannerNode.html]
 [test_pannerNode_equalPower.html]
 [test_pannerNodeAbove.html]
 [test_pannerNodeChannelCount.html]
 [test_pannerNodeHRTFSymmetry.html]
 [test_pannerNodeTail.html]
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_audioBufferSourceNodePassThrough.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test AudioBufferSourceNode with passthrough</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var gTest = {
+  length: 2048,
+  numberOfChannels: 1,
+  createGraph: function(context) {
+    var buffer = context.createBuffer(1, 2048, context.sampleRate);
+    for (var i = 0; i < 2048; ++i) {
+      buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
+    }
+
+    var source = context.createBufferSource();
+
+    source.buffer = buffer;
+
+    var srcWrapped = SpecialPowers.wrap(source);
+    ok("passThrough" in srcWrapped, "AudioBufferSourceNode should support the passThrough API");
+    srcWrapped.passThrough = true;
+
+    source.start(0);
+    return source;
+  },
+  createExpectedBuffers: function(context) {
+    var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+
+    return [expectedBuffer];
+  },
+};
+
+runTest();
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_mediaElementAudioSourceNodePassThrough.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<meta charset="utf-8">
+<head>
+  <title>Test MediaElementAudioSourceNode with passthrough</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();
+
+function test() {
+  var audio = new Audio("small-shot.ogg");
+  var context = new AudioContext();
+  var node = context.createMediaElementSource(audio);
+  var sp = context.createScriptProcessor(2048, 1);
+  node.connect(sp);
+  var nonzeroSampleCount = 0;
+  var complete = false;
+  var iterationCount = 0;
+
+  var srcWrapped = SpecialPowers.wrap(node);
+  ok("passThrough" in srcWrapped, "MediaElementAudioSourceNode should support the passThrough API");
+  srcWrapped.passThrough = true;
+
+  // This test ensures we receive at least expectedSampleCount nonzero samples
+  function processSamples(e) {
+    if (complete) {
+      return;
+    }
+
+    if (iterationCount == 0) {
+      // Don't start playing the audio until the AudioContext stuff is connected
+      // and running.
+      audio.play();
+    }
+    ++iterationCount;
+
+    var buf = e.inputBuffer.getChannelData(0);
+    var nonzeroSamplesThisBuffer = 0;
+    for (var i = 0; i < buf.length; ++i) {
+      if (buf[i] != 0) {
+        ++nonzeroSamplesThisBuffer;
+      }
+    }
+    nonzeroSampleCount += nonzeroSamplesThisBuffer;
+    if (iterationCount == 10) {
+      is(nonzeroSampleCount, 0, "The input must be silence");
+      SimpleTest.finish();
+      complete = true;
+    }
+  }
+
+  audio.oncanplaythrough = function() {
+    sp.onaudioprocess = processSamples;
+  };
+}
+
+SpecialPowers.pushPrefEnv({"set": [["media.preload.default", 2], ["media.preload.auto", 3]]}, test);
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_mediaStreamAudioSourceNodePassThrough.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<meta charset="utf-8">
+<head>
+  <title>Test MediaStreamAudioSourceNode passthrough</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function createBuffer(context, delay) {
+  var buffer = context.createBuffer(2, 2048, context.sampleRate);
+  for (var i = 0; i < 2048 - delay; ++i) {
+    buffer.getChannelData(0)[i + delay] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
+    buffer.getChannelData(1)[i + delay] = -buffer.getChannelData(0)[i + delay];
+  }
+  return buffer;
+}
+
+var gTest = {
+  length: 2048,
+  skipOfflineContextTests: true,
+  createGraph: function(context) {
+    var sourceGraph = new AudioContext();
+    var source = sourceGraph.createBufferSource();
+    source.buffer = createBuffer(context, 0);
+    var dest = sourceGraph.createMediaStreamDestination();
+    source.connect(dest);
+    source.start(0);
+
+    var mediaStreamSource = context.createMediaStreamSource(dest.stream);
+    // channelCount and channelCountMode should have no effect
+    mediaStreamSource.channelCount = 1;
+    mediaStreamSource.channelCountMode = "explicit";
+
+    var srcWrapped = SpecialPowers.wrap(mediaStreamSource);
+    ok("passThrough" in srcWrapped, "MediaStreamAudioSourceNode should support the passThrough API");
+    srcWrapped.passThrough = true;
+
+    return mediaStreamSource;
+  },
+  createExpectedBuffers: function(context) {
+    return context.createBuffer(2, 2048, context.sampleRate);
+  },
+};
+
+runTest();
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_oscillatorNodePassThrough.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test Oscillator with passthrough</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var gTest = {
+  length: 2048,
+  numberOfChannels: 1,
+  createGraph: function(context) {
+    var buffer = context.createBuffer(1, 2048, context.sampleRate);
+    for (var i = 0; i < 2048; ++i) {
+      buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
+    }
+
+    var source = context.createOscillator();
+
+    var srcWrapped = SpecialPowers.wrap(source);
+    ok("passThrough" in srcWrapped, "OscillatorNode should support the passThrough API");
+    srcWrapped.passThrough = true;
+
+    source.start(0);
+    return source;
+  },
+  createExpectedBuffers: function(context) {
+    var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+
+    return [expectedBuffer];
+  },
+};
+
+runTest();
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/AudioBufferSourceNode.webidl
+++ b/dom/webidl/AudioBufferSourceNode.webidl
@@ -23,8 +23,11 @@ interface AudioBufferSourceNode : AudioN
     [Throws]
     void start(optional double when = 0, optional double grainOffset = 0,
                optional double grainDuration);
     [Throws]
     void stop(optional double when = 0);
 
     attribute EventHandler onended;
 };
+
+// Mozilla extensions
+AudioBufferSourceNode implements AudioNodePassThrough;
--- a/dom/webidl/MediaElementAudioSourceNode.webidl
+++ b/dom/webidl/MediaElementAudioSourceNode.webidl
@@ -9,8 +9,11 @@
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface MediaElementAudioSourceNode : AudioNode {
 
 };
 
+// Mozilla extensions
+MediaElementAudioSourceNode implements AudioNodePassThrough;
+
--- a/dom/webidl/MediaStreamAudioSourceNode.webidl
+++ b/dom/webidl/MediaStreamAudioSourceNode.webidl
@@ -9,8 +9,11 @@
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface MediaStreamAudioSourceNode : AudioNode {
 
 };
 
+// Mozilla extensions
+MediaStreamAudioSourceNode implements AudioNodePassThrough;
+
--- a/dom/webidl/OscillatorNode.webidl
+++ b/dom/webidl/OscillatorNode.webidl
@@ -31,8 +31,11 @@ interface OscillatorNode : AudioNode {
     [Throws]
     void stop(optional double when = 0);
     void setPeriodicWave(PeriodicWave periodicWave);
 
     attribute EventHandler onended;
 
 };
 
+// Mozilla extensions
+OscillatorNode implements AudioNodePassThrough;
+