Bug 1265403 - Support chaining AudioParam automation methods. r=smaug
authorPaul Adenot <paul@paul.cx>
Tue, 19 Apr 2016 14:52:27 +0200
changeset 331751 7df73cfe3c2f558242b806c6ae021dd363efebc5
parent 331750 750ff8b64b21633ccdc2e017d573c552d2ba2268
child 331752 2da0c84c972a7b103d5507ea29956d704389bdd4
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1265403
milestone48.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 1265403 - Support chaining AudioParam automation methods. r=smaug MozReview-Commit-ID: 7Jh5eWtfU4t
dom/media/webaudio/AudioParam.h
dom/media/webaudio/test/mochitest.ini
dom/media/webaudio/test/test_audioParamChaining.html
dom/webidl/AudioParam.webidl
--- a/dom/media/webaudio/AudioParam.h
+++ b/dom/media/webaudio/AudioParam.h
@@ -39,27 +39,31 @@ public:
   {
     return mNode->Context();
   }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // We override SetValueCurveAtTime to convert the Float32Array to the wrapper
   // object.
-  void SetValueCurveAtTime(const Float32Array& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
+  AudioParam* SetValueCurveAtTime(const Float32Array& aValues,
+                                  double aStartTime,
+                                  double aDuration,
+                                  ErrorResult& aRv)
   {
     if (!WebAudioUtils::IsTimeValid(aStartTime)) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return;
+      return this;
     }
     aValues.ComputeLengthAndData();
 
     EventInsertionHelper(aRv, AudioTimelineEvent::SetValueCurve,
                          aStartTime, 0.0f, 0.0f, aDuration, aValues.Data(),
                          aValues.Length());
+    return this;
   }
 
   void SetValue(float aValue)
   {
     AudioTimelineEvent event(AudioTimelineEvent::SetValue, 0.0f, aValue);
 
     ErrorResult rv;
     if (!ValidateEvent(event, rv)) {
@@ -68,71 +72,81 @@ public:
       return;
     }
 
     AudioParamTimeline::SetValue(aValue);
 
     SendEventToEngine(event);
   }
 
-  void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
+  AudioParam* SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
   {
     if (!WebAudioUtils::IsTimeValid(aStartTime)) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return;
+      return this;
     }
     EventInsertionHelper(aRv, AudioTimelineEvent::SetValueAtTime,
                          aStartTime, aValue);
+
+    return this;
   }
 
-  void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
+  AudioParam* LinearRampToValueAtTime(float aValue, double aEndTime,
+                                      ErrorResult& aRv)
   {
     if (!WebAudioUtils::IsTimeValid(aEndTime)) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return;
+      return this;
     }
     EventInsertionHelper(aRv, AudioTimelineEvent::LinearRamp, aEndTime, aValue);
+    return this;
   }
 
-  void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
+  AudioParam* ExponentialRampToValueAtTime(float aValue, double aEndTime,
+                                           ErrorResult& aRv)
   {
     if (!WebAudioUtils::IsTimeValid(aEndTime)) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return;
+      return this;
     }
     EventInsertionHelper(aRv, AudioTimelineEvent::ExponentialRamp,
                          aEndTime, aValue);
+    return this;
   }
 
-  void SetTargetAtTime(float aTarget, double aStartTime,
-                       double aTimeConstant, ErrorResult& aRv)
+  AudioParam* SetTargetAtTime(float aTarget, double aStartTime,
+                              double aTimeConstant, ErrorResult& aRv)
   {
     if (!WebAudioUtils::IsTimeValid(aStartTime) ||
         !WebAudioUtils::IsTimeValid(aTimeConstant)) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return;
+      return this;
     }
     EventInsertionHelper(aRv, AudioTimelineEvent::SetTarget,
                          aStartTime, aTarget,
                          aTimeConstant);
+
+    return this;
   }
 
-  void CancelScheduledValues(double aStartTime, ErrorResult& aRv)
+  AudioParam* CancelScheduledValues(double aStartTime, ErrorResult& aRv)
   {
     if (!WebAudioUtils::IsTimeValid(aStartTime)) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return;
+      return this;
     }
 
     // Remove some events on the main thread copy.
     AudioEventTimeline::CancelScheduledValues(aStartTime);
 
     AudioTimelineEvent event(AudioTimelineEvent::Cancel, aStartTime, 0.0f);
 
     SendEventToEngine(event);
+
+    return this;
   }
 
   uint32_t ParentNodeId()
   {
     return mNode->Id();
   }
 
   void GetName(nsAString& aName)
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -50,16 +50,17 @@ skip-if = (toolkit == 'gonk') || (toolki
 [test_audioBufferSourceNodeRate.html]
 [test_AudioContext.html]
 [test_audioContextSuspendResumeClose.html]
 skip-if = buildapp == 'mulet'
 tags=capturestream
 [test_audioDestinationNode.html]
 [test_AudioListener.html]
 [test_AudioNodeDevtoolsAPI.html]
+[test_audioParamChaining.html]
 [test_AudioParamDevtoolsAPI.html]
 [test_audioParamExponentialRamp.html]
 [test_audioParamGain.html]
 [test_audioParamLinearRamp.html]
 [test_audioParamSetCurveAtTime.html]
 [test_audioParamSetCurveAtTimeTwice.html]
 [test_audioParamSetCurveAtTimeZeroDuration.html]
 [test_audioParamSetTargetAtTime.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/test/test_audioParamChaining.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test whether we can create an AudioContext interface</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 frameToTime(frame, rate)
+{
+  return frame / rate;
+}
+
+const RATE = 44100;
+
+var oc = new OfflineAudioContext(1, 44100, RATE);
+// This allows us to have a source that is simply a DC offset.
+var source = oc.createBufferSource();
+var buf = oc.createBuffer(1, 1, RATE);
+buf.getChannelData(0)[0] = 1;
+source.loop = true;
+source.buffer = buf;
+
+source.start(0);
+
+var gain = oc.createGain();
+
+source.connect(gain).connect(oc.destination);
+
+var gain2 = oc.createGain();
+var rv2 = gain2.gain.linearRampToValueAtTime(0.1, 0.5);
+ok(rv2 instanceof AudioParam, "linearRampToValueAtTime returns an AudioParam.");
+ok(rv2 == gain2.gain, "linearRampToValueAtTime returns the right AudioParam.");
+
+rv2 = gain2.gain.exponentialRampToValueAtTime(0.01, 1.0);
+ok(rv2 instanceof AudioParam,
+    "exponentialRampToValueAtTime returns an AudioParam.");
+ok(rv2 == gain2.gain,
+    "exponentialRampToValueAtTime returns the right AudioParam.");
+
+rv2 = gain2.gain.setTargetAtTime(1.0, 2.0, 0.1);
+ok(rv2 instanceof AudioParam, "setTargetAtTime returns an AudioParam.");
+ok(rv2 == gain2.gain, "setTargetAtTime returns the right AudioParam.");
+
+var array = new Float32Array(10);
+rv2 = gain2.gain.setValueCurveAtTime(array, 10, 11);
+ok(rv2 instanceof AudioParam, "setValueCurveAtTime returns an AudioParam.");
+ok(rv2 == gain2.gain, "setValueCurveAtTime returns the right AudioParam.");
+
+// We chain three automation methods, making a gain step.
+var rv = gain.gain.setValueAtTime(0, frameToTime(0, RATE))
+                  .setValueAtTime(0.5, frameToTime(22000, RATE))
+                  .setValueAtTime(1, frameToTime(44000, RATE));
+
+ok(rv instanceof AudioParam, "setValueAtTime returns an AudioParam.");
+ok(rv == gain.gain, "setValueAtTime returns the right AudioParam.");
+
+oc.startRendering().then(function(rendered) {
+    console.log(rendered.getChannelData(0));
+    ok(rendered.getChannelData(0)[0] == 0,
+      "The value of the first step is correct.");
+    ok(rendered.getChannelData(0)[22050] == 0.5,
+      "The value of the second step is correct");
+    ok(rendered.getChannelData(0)[44099] == 1,
+      "The value of the third step is correct.");
+    SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/AudioParam.webidl
+++ b/dom/webidl/AudioParam.webidl
@@ -12,34 +12,34 @@
 
 interface AudioParam {
 
     attribute float value;
     readonly attribute float defaultValue;
 
     // Parameter automation. 
     [Throws]
-    void setValueAtTime(float value, double startTime);
+    AudioParam setValueAtTime(float value, double startTime);
     [Throws]
-    void linearRampToValueAtTime(float value, double endTime);
+    AudioParam linearRampToValueAtTime(float value, double endTime);
     [Throws]
-    void exponentialRampToValueAtTime(float value, double endTime);
+    AudioParam exponentialRampToValueAtTime(float value, double endTime);
 
     // Exponentially approach the target value with a rate having the given time constant. 
     [Throws]
-    void setTargetAtTime(float target, double startTime, double timeConstant);
+    AudioParam setTargetAtTime(float target, double startTime, double timeConstant);
 
     // Sets an array of arbitrary parameter values starting at time for the given duration. 
     // The number of values will be scaled to fit into the desired duration. 
     [Throws]
-    void setValueCurveAtTime(Float32Array values, double startTime, double duration);
+    AudioParam setValueCurveAtTime(Float32Array values, double startTime, double duration);
 
     // Cancels all scheduled parameter changes with times greater than or equal to startTime. 
     [Throws]
-    void cancelScheduledValues(double startTime);
+    AudioParam cancelScheduledValues(double startTime);
 
 };
 
 // Mozilla extension
 partial interface AudioParam {
   // The ID of the AudioNode this AudioParam belongs to.
   [ChromeOnly]
   readonly attribute unsigned long parentNodeId;