Bug 1324568 - Implement AudioScheduledSourceNode, r=padenot
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 21 Dec 2016 10:53:17 +0100
changeset 326783 a454e4dae7b9fdc4dd3fd5ddfd03bbcbbaac3189
parent 326782 6823579dd938b96c793b46d713d4918a5c158aa3
child 326784 bf42716f602061dfc2777c60c5fb8a612a3f40fe
push id31111
push usercbook@mozilla.com
push dateWed, 21 Dec 2016 15:57:24 +0000
treeherdermozilla-central@10a5e2fc24e4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1324568
milestone53.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 1324568 - Implement AudioScheduledSourceNode, r=padenot
dom/media/webaudio/AudioBufferSourceNode.cpp
dom/media/webaudio/AudioBufferSourceNode.h
dom/media/webaudio/AudioScheduledSourceNode.cpp
dom/media/webaudio/AudioScheduledSourceNode.h
dom/media/webaudio/ConstantSourceNode.cpp
dom/media/webaudio/ConstantSourceNode.h
dom/media/webaudio/OscillatorNode.cpp
dom/media/webaudio/OscillatorNode.h
dom/media/webaudio/moz.build
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/AudioBufferSourceNode.webidl
dom/webidl/AudioScheduledSourceNode.webidl
dom/webidl/ConstantSourceNode.webidl
dom/webidl/OscillatorNode.webidl
dom/webidl/moz.build
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -17,23 +17,25 @@
 #include "AudioDestinationNode.h"
 #include "AudioParamTimeline.h"
 #include <limits>
 #include <algorithm>
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioBufferSourceNode, AudioNode, mBuffer, mPlaybackRate, mDetune)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioBufferSourceNode,
+                                   AudioScheduledSourceNode, mBuffer,
+                                   mPlaybackRate, mDetune)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioBufferSourceNode)
-NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioScheduledSourceNode)
 
-NS_IMPL_ADDREF_INHERITED(AudioBufferSourceNode, AudioNode)
-NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioNode)
+NS_IMPL_ADDREF_INHERITED(AudioBufferSourceNode, AudioScheduledSourceNode)
+NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioScheduledSourceNode)
 
 /**
  * Media-thread playback engine for AudioBufferSourceNode.
  * Nothing is played until a non-null buffer has been set (via
  * AudioNodeStream::SetBuffer) and a non-zero mBufferEnd has been set (via
  * AudioNodeStream::SetInt32Parameter).
  */
 class AudioBufferSourceNodeEngine final : public AudioNodeEngine
@@ -583,20 +585,20 @@ public:
   AudioNodeStream* mDestination;
   AudioNodeStream* mSource;
   AudioParamTimeline mPlaybackRateTimeline;
   AudioParamTimeline mDetuneTimeline;
   bool mLoop;
 };
 
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
-  : AudioNode(aContext,
-              2,
-              ChannelCountMode::Max,
-              ChannelInterpretation::Speakers)
+  : AudioScheduledSourceNode(aContext,
+                             2,
+                             ChannelCountMode::Max,
+                             ChannelInterpretation::Speakers)
   , mLoopStart(0.0)
   , mLoopEnd(0.0)
   // mOffset and mDuration are initialized in Start().
   , mPlaybackRate(new AudioParam(this, PLAYBACKRATE, 1.0f, "playbackRate"))
   , mDetune(new AudioParam(this, DETUNE, 0.0f, "detune"))
   , mLoop(false)
   , mStartCalled(false)
 {
@@ -707,16 +709,22 @@ AudioBufferSourceNode::Start(double aWhe
 
   // Don't set parameter unnecessarily
   if (aWhen > 0.0) {
     ns->SetDoubleParameter(START, aWhen);
   }
 }
 
 void
+AudioBufferSourceNode::Start(double aWhen, ErrorResult& aRv)
+{
+  Start(aWhen, 0 /* offset */, Optional<double>(), aRv);
+}
+
+void
 AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx)
 {
   AudioNodeStream* ns = mStream;
   if (!ns) {
     return;
   }
 
   if (mBuffer) {
--- a/dom/media/webaudio/AudioBufferSourceNode.h
+++ b/dom/media/webaudio/AudioBufferSourceNode.h
@@ -2,26 +2,26 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef AudioBufferSourceNode_h_
 #define AudioBufferSourceNode_h_
 
-#include "AudioNode.h"
+#include "AudioScheduledSourceNode.h"
 #include "AudioBuffer.h"
 
 namespace mozilla {
 namespace dom {
 
 struct AudioBufferSourceOptions;
 class AudioParam;
 
-class AudioBufferSourceNode final : public AudioNode
+class AudioBufferSourceNode final : public AudioScheduledSourceNode
                                   , public MainThreadMediaStreamListener
 {
 public:
   static already_AddRefed<AudioBufferSourceNode>
   Create(JSContext* aCx, AudioContext& aAudioContext,
          const AudioBufferSourceOptions& aOptions, ErrorResult& aRv);
 
   void DestroyMediaStream() override;
@@ -30,30 +30,33 @@ public:
   {
     return 0;
   }
   AudioBufferSourceNode* AsAudioBufferSourceNode() override
   {
     return this;
   }
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode, AudioNode)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode,
+                                           AudioScheduledSourceNode)
 
   static already_AddRefed<AudioBufferSourceNode>
   Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
               const AudioBufferSourceOptions& aOptions, ErrorResult& aRv)
   {
     return Create(aGlobal.Context(), aAudioContext, aOptions, aRv);
   }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void Start(double aWhen, double aOffset,
              const Optional<double>& aDuration, ErrorResult& aRv);
-  void Stop(double aWhen, ErrorResult& aRv);
+
+  void Start(double aWhen, ErrorResult& aRv) override;
+  void Stop(double aWhen, ErrorResult& aRv) override;
 
   AudioBuffer* GetBuffer(JSContext* aCx) const
   {
     return mBuffer;
   }
   void SetBuffer(JSContext* aCx, AudioBuffer* aBuffer)
   {
     mBuffer = aBuffer;
@@ -92,18 +95,16 @@ public:
   }
   void SetLoopEnd(double aEnd)
   {
     mLoopEnd = aEnd;
     SendLoopParametersToStream();
   }
   void SendDopplerShiftToStream(double aDopplerShift);
 
-  IMPL_EVENT_HANDLER(ended)
-
   void NotifyMainThreadStreamFinished() override;
 
   const char* NodeType() const override
   {
     return "AudioBufferSourceNode";
   }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AudioScheduledSourceNode.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AudioScheduledSourceNode.h"
+#include "mozilla/dom/AudioScheduledSourceNodeBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+AudioScheduledSourceNode::AudioScheduledSourceNode(AudioContext* aContext,
+                                                   uint32_t aChannelCount,
+                                                   ChannelCountMode aChannelCountMode,
+                                                   ChannelInterpretation aChannelInterpretation)
+  : AudioNode(aContext, aChannelCount, aChannelCountMode,
+              aChannelInterpretation)
+{}
+
+JSObject*
+AudioScheduledSourceNode::WrapObject(JSContext* aCx,
+                                     JS::Handle<JSObject*> aGivenProto)
+{
+  return AudioScheduledSourceNodeBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AudioScheduledSourceNode.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef AudioScheduledSourceNode_h_
+#define AudioScheduledSourceNode_h_
+
+#include "AudioNode.h"
+#include "mozilla/dom/AudioScheduledSourceNodeBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioContext;
+
+class AudioScheduledSourceNode : public AudioNode
+{
+public:
+  JSObject* WrapObject(JSContext* aCx,
+                       JS::Handle<JSObject*> aGivenProto) override;
+
+  virtual void Start(double aWhen, ErrorResult& aRv) = 0;
+  virtual void Stop(double aWhen, ErrorResult& aRv) = 0;
+
+  IMPL_EVENT_HANDLER(ended)
+
+protected:
+  AudioScheduledSourceNode(AudioContext* aContext,
+                           uint32_t aChannelCount,
+                           ChannelCountMode aChannelCountMode,
+                           ChannelInterpretation aChannelInterpretation);
+  virtual ~AudioScheduledSourceNode() = default;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/media/webaudio/ConstantSourceNode.cpp
+++ b/dom/media/webaudio/ConstantSourceNode.cpp
@@ -7,24 +7,24 @@
 #include "ConstantSourceNode.h"
 
 #include "AudioDestinationNode.h"
 #include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(ConstantSourceNode, AudioNode,
+NS_IMPL_CYCLE_COLLECTION_INHERITED(ConstantSourceNode, AudioScheduledSourceNode,
                                    mOffset)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ConstantSourceNode)
-NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioScheduledSourceNode)
 
-NS_IMPL_ADDREF_INHERITED(ConstantSourceNode, AudioNode)
-NS_IMPL_RELEASE_INHERITED(ConstantSourceNode, AudioNode)
+NS_IMPL_ADDREF_INHERITED(ConstantSourceNode, AudioScheduledSourceNode)
+NS_IMPL_RELEASE_INHERITED(ConstantSourceNode, AudioScheduledSourceNode)
 
 class ConstantSourceNodeEngine final : public AudioNodeEngine
 {
 public:
   ConstantSourceNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
     : AudioNodeEngine(aNode)
     , mSource(nullptr)
     , mDestination(aDestination->Stream())
@@ -137,20 +137,20 @@ public:
   AudioNodeStream* mSource;
   AudioNodeStream* mDestination;
   StreamTime mStart;
   StreamTime mStop;
   AudioParamTimeline mOffset;
 };
 
 ConstantSourceNode::ConstantSourceNode(AudioContext* aContext)
-  : AudioNode(aContext,
-              1,
-              ChannelCountMode::Max,
-              ChannelInterpretation::Speakers)
+  : AudioScheduledSourceNode(aContext,
+                             1,
+                             ChannelCountMode::Max,
+                             ChannelInterpretation::Speakers)
   , mOffset(new AudioParam(this, ConstantSourceNodeEngine::OFFSET,
                            1.0, "offset"))
   , mStartCalled(false)
 {
   ConstantSourceNodeEngine* engine = new ConstantSourceNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
                                     AudioNodeStream::NEED_MAIN_THREAD_FINISHED,
                                     aContext->Graph());
--- a/dom/media/webaudio/ConstantSourceNode.h
+++ b/dom/media/webaudio/ConstantSourceNode.h
@@ -2,33 +2,33 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ConstantSourceNode_h_
 #define ConstantSourceNode_h_
 
-#include "AudioNode.h"
+#include "AudioScheduledSourceNode.h"
 #include "AudioParam.h"
 #include "mozilla/dom/ConstantSourceNodeBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 class AudioContext;
 
-class ConstantSourceNode final : public AudioNode,
-                                 public MainThreadMediaStreamListener
+class ConstantSourceNode final : public AudioScheduledSourceNode
+                               , public MainThreadMediaStreamListener
 {
 public:
   explicit ConstantSourceNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ConstantSourceNode, AudioNode)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ConstantSourceNode, AudioScheduledSourceNode)
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<ConstantSourceNode>
   Constructor(const GlobalObject& aGlobal,
               AudioContext& aContext,
               const ConstantSourceOptions& aOptions,
               ErrorResult& aRv);
@@ -40,20 +40,18 @@ public:
     return 0;
   }
 
   AudioParam* Offset() const
   {
     return mOffset;
   }
 
-  void Start(double aWhen, ErrorResult& rv);
-  void Stop(double aWhen, ErrorResult& rv);
-
-  IMPL_EVENT_HANDLER(ended)
+  void Start(double aWhen, ErrorResult& rv) override;
+  void Stop(double aWhen, ErrorResult& rv) override;
 
   void NotifyMainThreadStreamFinished() override;
 
   const char* NodeType() const override
   {
     return "ConstantSourceNode";
   }
 
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -10,24 +10,24 @@
 #include "AudioDestinationNode.h"
 #include "nsContentUtils.h"
 #include "WebAudioUtils.h"
 #include "blink/PeriodicWave.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(OscillatorNode, AudioNode,
+NS_IMPL_CYCLE_COLLECTION_INHERITED(OscillatorNode, AudioScheduledSourceNode,
                                    mPeriodicWave, mFrequency, mDetune)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OscillatorNode)
-NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioScheduledSourceNode)
 
-NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode)
-NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode)
+NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioScheduledSourceNode)
+NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioScheduledSourceNode)
 
 class OscillatorNodeEngine final : public AudioNodeEngine
 {
 public:
   OscillatorNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
     : AudioNodeEngine(aNode)
     , mSource(nullptr)
     , mDestination(aDestination->Stream())
@@ -403,20 +403,20 @@ public:
   RefPtr<ThreadSharedFloatArrayBufferList> mCustom;
   RefPtr<BasicWaveFormCache> mBasicWaveFormCache;
   uint32_t mCustomLength;
   bool mCustomDisableNormalization;
   RefPtr<WebCore::PeriodicWave> mPeriodicWave;
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
-  : AudioNode(aContext,
-              2,
-              ChannelCountMode::Max,
-              ChannelInterpretation::Speakers)
+  : AudioScheduledSourceNode(aContext,
+                             2,
+                             ChannelCountMode::Max,
+                             ChannelInterpretation::Speakers)
   , mType(OscillatorType::Sine)
   , mFrequency(new AudioParam(this, OscillatorNodeEngine::FREQUENCY,
                               440.0f, "frequency"))
   , mDetune(new AudioParam(this, OscillatorNodeEngine::DETUNE, 0.0f, "detune"))
   , mStartCalled(false)
 {
   OscillatorNodeEngine* engine = new OscillatorNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
--- a/dom/media/webaudio/OscillatorNode.h
+++ b/dom/media/webaudio/OscillatorNode.h
@@ -2,37 +2,37 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef OscillatorNode_h_
 #define OscillatorNode_h_
 
-#include "AudioNode.h"
+#include "AudioScheduledSourceNode.h"
 #include "AudioParam.h"
 #include "PeriodicWave.h"
 #include "mozilla/dom/OscillatorNodeBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 class AudioContext;
 struct OscillatorOptions;
 
-class OscillatorNode final : public AudioNode,
-                             public MainThreadMediaStreamListener
+class OscillatorNode final : public AudioScheduledSourceNode
+                           , public MainThreadMediaStreamListener
 {
 public:
   static already_AddRefed<OscillatorNode>
   Create(AudioContext& aAudioContext, const OscillatorOptions& aOptions,
          ErrorResult& aRv);
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OscillatorNode, AudioNode)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OscillatorNode, AudioScheduledSourceNode)
 
   static already_AddRefed<OscillatorNode>
   Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
               const OscillatorOptions& aOptions, ErrorResult& aRv)
   {
     return Create(aAudioContext, aOptions, aRv);
   }
 
@@ -65,28 +65,27 @@ public:
   {
     return mFrequency;
   }
   AudioParam* Detune() const
   {
     return mDetune;
   }
 
-  void Start(double aWhen, ErrorResult& aRv);
-  void Stop(double aWhen, ErrorResult& aRv);
+  void Start(double aWhen, ErrorResult& aRv) override;
+  void Stop(double aWhen, ErrorResult& aRv) override;
+
   void SetPeriodicWave(PeriodicWave& aPeriodicWave)
   {
     mPeriodicWave = &aPeriodicWave;
     // SendTypeToStream will call SendPeriodicWaveToStream for us.
     mType = OscillatorType::Custom;
     SendTypeToStream();
   }
 
-  IMPL_EVENT_HANDLER(ended)
-
   void NotifyMainThreadStreamFinished() override;
 
   const char* NodeType() const override
   {
     return "OscillatorNode";
   }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
--- a/dom/media/webaudio/moz.build
+++ b/dom/media/webaudio/moz.build
@@ -49,16 +49,17 @@ EXPORTS.mozilla.dom += [
     'AudioBuffer.h',
     'AudioBufferSourceNode.h',
     'AudioContext.h',
     'AudioDestinationNode.h',
     'AudioListener.h',
     'AudioNode.h',
     'AudioParam.h',
     'AudioProcessingEvent.h',
+    'AudioScheduledSourceNode.h',
     'BiquadFilterNode.h',
     'ChannelMergerNode.h',
     'ChannelSplitterNode.h',
     'ConstantSourceNode.h',
     'ConvolverNode.h',
     'DelayNode.h',
     'DynamicsCompressorNode.h',
     'GainNode.h',
@@ -84,16 +85,17 @@ UNIFIED_SOURCES += [
     'AudioEventTimeline.cpp',
     'AudioListener.cpp',
     'AudioNode.cpp',
     'AudioNodeEngine.cpp',
     'AudioNodeExternalInputStream.cpp',
     'AudioNodeStream.cpp',
     'AudioParam.cpp',
     'AudioProcessingEvent.cpp',
+    'AudioScheduledSourceNode.cpp',
     'BiquadFilterNode.cpp',
     'BufferDecoder.cpp',
     'ChannelMergerNode.cpp',
     'ChannelSplitterNode.cpp',
     'ConstantSourceNode.cpp',
     'ConvolverNode.cpp',
     'DelayBuffer.cpp',
     'DelayNode.cpp',
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -150,16 +150,18 @@ var interfaceNamesInGlobalScope =
     "AudioListener",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioParam",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioProcessingEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "AudioScheduledSourceNode",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioStreamTrack",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "BarProp",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "BaseAudioContext",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "BatteryManager",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/AudioBufferSourceNode.webidl
+++ b/dom/webidl/AudioBufferSourceNode.webidl
@@ -16,30 +16,26 @@ dictionary AudioBufferSourceOptions {
              boolean      loop = false;
              double       loopEnd = 0;
              double       loopStart = 0;
              float        playbackRate = 1;
 };
 
 [Pref="dom.webaudio.enabled",
  Constructor(BaseAudioContext context, optional AudioBufferSourceOptions options)]
-interface AudioBufferSourceNode : AudioNode {
+interface AudioBufferSourceNode : AudioScheduledSourceNode {
 
     attribute AudioBuffer? buffer;
 
     readonly attribute AudioParam playbackRate;
     readonly attribute AudioParam detune;
 
     attribute boolean loop;
     attribute double loopStart;
     attribute double loopEnd;
 
     [Throws, UnsafeInPrerendering]
     void start(optional double when = 0, optional double grainOffset = 0,
                optional double grainDuration);
-    [Throws, UnsafeInPrerendering]
-    void stop(optional double when = 0);
-
-    attribute EventHandler onended;
 };
 
 // Mozilla extensions
 AudioBufferSourceNode implements AudioNodePassThrough;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/AudioScheduledSourceNode.webidl
@@ -0,0 +1,20 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://webaudio.github.io/web-audio-api/#idl-def-AudioScheduledSourceNode
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+interface AudioScheduledSourceNode : AudioNode {
+                    attribute EventHandler onended;
+    [Throws, UnsafeInPrerendering]
+    void start (optional double when = 0);
+
+    [Throws, UnsafeInPrerendering]
+    void stop (optional double when = 0);
+};
--- a/dom/webidl/ConstantSourceNode.webidl
+++ b/dom/webidl/ConstantSourceNode.webidl
@@ -11,16 +11,11 @@
  */
 
 dictionary ConstantSourceOptions {
     float offset = 1;
 };
 
 [Pref="dom.webaudio.enabled",
  Constructor(BaseAudioContext context, optional ConstantSourceOptions options)]
-interface ConstantSourceNode : AudioNode {
+interface ConstantSourceNode :  AudioScheduledSourceNode {
     readonly        attribute AudioParam   offset;
-                    attribute EventHandler onended;
-    [Throws, UnsafeInPrerendering]
-    void start (optional double when = 0);
-    [Throws, UnsafeInPrerendering]
-    void stop (optional double when = 0);
 };
--- a/dom/webidl/OscillatorNode.webidl
+++ b/dom/webidl/OscillatorNode.webidl
@@ -22,28 +22,21 @@ dictionary OscillatorOptions : AudioNode
              OscillatorType type = "sine";
              float          frequency = 440;
              float          detune = 0;
              PeriodicWave   periodicWave;
 };
 
 [Pref="dom.webaudio.enabled",
  Constructor(BaseAudioContext context, optional OscillatorOptions options)]
-interface OscillatorNode : AudioNode {
+interface OscillatorNode : AudioScheduledSourceNode {
 
     [SetterThrows]
     attribute OscillatorType type;
 
     readonly attribute AudioParam frequency; // in Hertz
     readonly attribute AudioParam detune; // in Cents
 
-    [Throws, UnsafeInPrerendering]
-    void start(optional double when = 0);
-    [Throws, UnsafeInPrerendering]
-    void stop(optional double when = 0);
     void setPeriodicWave(PeriodicWave periodicWave);
-
-    attribute EventHandler onended;
-
 };
 
 // Mozilla extensions
 OscillatorNode implements AudioNodePassThrough;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -36,16 +36,17 @@ WEBIDL_FILES = [
     'AudioBufferSourceNode.webidl',
     'AudioChannel.webidl',
     'AudioContext.webidl',
     'AudioDestinationNode.webidl',
     'AudioListener.webidl',
     'AudioNode.webidl',
     'AudioParam.webidl',
     'AudioProcessingEvent.webidl',
+    'AudioScheduledSourceNode.webidl',
     'AudioStreamTrack.webidl',
     'AudioTrack.webidl',
     'AudioTrackList.webidl',
     'AudioWorkletGlobalScope.webidl',
     'AutocompleteInfo.webidl',
     'BarProp.webidl',
     'BaseAudioContext.webidl',
     'BaseKeyframeTypes.webidl',