Bug 1324548 - Add MediaStreamTrackAudioSourceNode. r=pehrsons,baku
☠☠ backed out by 3bed147b65d6 ☠ ☠
authorLéo Paquet <Léo Paquet>
Wed, 03 Apr 2019 14:00:28 +0000
changeset 467780 fda93e03e4696579766232114a61a1daf5248b88
parent 467779 8e6135544e33818c92e5fc4ba8d31ba04dab277a
child 467781 ba0820e380a330b9971299c168b2f75aa5140e7b
push id35810
push useraciure@mozilla.com
push dateThu, 04 Apr 2019 04:33:36 +0000
treeherdermozilla-central@b72c02e34261 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspehrsons, baku
bugs1324548
milestone68.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 1324548 - Add MediaStreamTrackAudioSourceNode. r=pehrsons,baku MozReview-Commit-ID: IdVqfNigMyu Differential Revision: https://phabricator.services.mozilla.com/D15958
dom/locales/en-US/chrome/dom/dom.properties
dom/media/MediaStreamTrack.cpp
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioContext.h
dom/media/webaudio/MediaStreamTrackAudioSourceNode.cpp
dom/media/webaudio/MediaStreamTrackAudioSourceNode.h
dom/media/webaudio/moz.build
dom/webidl/AudioContext.webidl
dom/webidl/MediaStreamTrackAudioSourceNode.webidl
dom/webidl/moz.build
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -100,16 +100,18 @@ MediaDecodeAudioDataUnknownError=An unkn
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
 MediaDecodeAudioDataInvalidContent=The buffer passed to decodeAudioData contains invalid content which cannot be decoded successfully.
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
 MediaDecodeAudioDataNoAudio=The buffer passed to decodeAudioData does not contain any audio.
 # LOCALIZATION NOTE: Do not translate HTMLMediaElement and createMediaElementSource.
 MediaElementAudioSourceNodeCrossOrigin=The HTMLMediaElement passed to createMediaElementSource has a cross-origin resource, the node will output silence.
 # LOCALIZATION NOTE: Do not translate MediaStream and createMediaStreamSource.
 MediaStreamAudioSourceNodeCrossOrigin=The MediaStream passed to createMediaStreamSource has a cross-origin resource, the node will output silence.
+# LOCALIZATION NOTE : Do not translate MediaStreamTrack and createMediaStreamTrackSource.
+MediaStreamTrackAudioSourceNodeCrossOrigin=The MediaStreamTrack passed to createMediaStreamTrackSource is a cross-origin resource, the node will output silence.
 # LOCALIZATION NOTE: Do not translate HTMLMediaElement and MediaStream.
 MediaElementAudioCaptureOfMediaStreamError=The captured HTMLMediaElement is playing a MediaStream. Applying volume or mute status is not currently supported.
 MediaLoadExhaustedCandidates=All candidate resources failed to load. Media load paused.
 MediaLoadSourceMissingSrc=<source> element has no “src” attribute. Media resource load failed.
 MediaStreamAudioSourceNodeDifferentRate=Connecting AudioNodes from AudioContexts with different sample-rate is currently not supported.
 # LOCALIZATION NOTE: Do not translate ConvolverNode
 ConvolverNodeAllocationError=Out-of-memory error when instantiating a ConvolverNode: the node will output silence.
 # LOCALIZATION NOTE: %1$S is the Http error code the server returned (e.g. 404, 500, etc), %2$S is the URL of the media resource which failed to load.
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -107,16 +107,20 @@ class MediaStreamTrack::MSGListener : pu
 
   void NotifyRemoved() override {
     // `mTrack` is a WeakPtr and must be destroyed on main thread.
     // We dispatch ourselves to main thread here in case the MediaStreamGraph
     // is holding the last reference to us.
     mGraph->DispatchToMainThreadStableState(
         NS_NewRunnableFunction("MediaStreamTrack::MSGListener::mTrackReleaser",
                                [self = RefPtr<MSGListener>(this)]() {}));
+
+    mGraph->Dispatch(NS_NewRunnableFunction(
+        "MediaStreamTrack::MSGListener::DoNotifyEnded",
+        [self = RefPtr<MSGListener>(this)]() { self->DoNotifyEnded(); }));
   }
 
   void DoNotifyEnded() {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mTrack) {
       return;
     }
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/dom/ConvolverNodeBinding.h"
 #include "mozilla/dom/DelayNodeBinding.h"
 #include "mozilla/dom/DynamicsCompressorNodeBinding.h"
 #include "mozilla/dom/GainNodeBinding.h"
 #include "mozilla/dom/IIRFilterNodeBinding.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/MediaElementAudioSourceNodeBinding.h"
 #include "mozilla/dom/MediaStreamAudioSourceNodeBinding.h"
+#include "mozilla/dom/MediaStreamTrackAudioSourceNodeBinding.h"
 #include "mozilla/dom/OfflineAudioContextBinding.h"
 #include "mozilla/dom/OscillatorNodeBinding.h"
 #include "mozilla/dom/PannerNodeBinding.h"
 #include "mozilla/dom/PeriodicWaveBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/StereoPannerNodeBinding.h"
 #include "mozilla/dom/WaveShaperNodeBinding.h"
 #include "mozilla/dom/Worklet.h"
@@ -57,16 +58,17 @@
 #include "DelayNode.h"
 #include "DynamicsCompressorNode.h"
 #include "GainNode.h"
 #include "IIRFilterNode.h"
 #include "js/ArrayBuffer.h"  // JS::StealArrayBufferContents
 #include "MediaElementAudioSourceNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "MediaStreamAudioSourceNode.h"
+#include "MediaStreamTrackAudioSourceNode.h"
 #include "MediaStreamGraph.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsRFPService.h"
@@ -419,16 +421,25 @@ already_AddRefed<MediaStreamAudioSourceN
 AudioContext::CreateMediaStreamSource(DOMMediaStream& aMediaStream,
                                       ErrorResult& aRv) {
   MediaStreamAudioSourceOptions options;
   options.mMediaStream = aMediaStream;
 
   return MediaStreamAudioSourceNode::Create(*this, options, aRv);
 }
 
+already_AddRefed<MediaStreamTrackAudioSourceNode>
+AudioContext::CreateMediaStreamTrackSource(MediaStreamTrack& aMediaStreamTrack,
+                                           ErrorResult& aRv) {
+  MediaStreamTrackAudioSourceOptions options;
+  options.mMediaStreamTrack = aMediaStreamTrack;
+
+  return MediaStreamTrackAudioSourceNode::Create(*this, options, aRv);
+}
+
 already_AddRefed<GainNode> AudioContext::CreateGain(ErrorResult& aRv) {
   return GainNode::Create(*this, GainOptions(), aRv);
 }
 
 already_AddRefed<WaveShaperNode> AudioContext::CreateWaveShaper(
     ErrorResult& aRv) {
   return WaveShaperNode::Create(*this, WaveShaperOptions(), aRv);
 }
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -62,16 +62,18 @@ class DelayNode;
 class DynamicsCompressorNode;
 class GainNode;
 class GlobalObject;
 class HTMLMediaElement;
 class IIRFilterNode;
 class MediaElementAudioSourceNode;
 class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
+class MediaStreamTrack;
+class MediaStreamTrackAudioSourceNode;
 class OscillatorNode;
 class PannerNode;
 class ScriptProcessorNode;
 class StereoPannerNode;
 class WaveShaperNode;
 class Worklet;
 class PeriodicWave;
 struct PeriodicWaveConstraints;
@@ -241,16 +243,19 @@ class AudioContext final : public DOMEve
   already_AddRefed<GainNode> CreateGain(ErrorResult& aRv);
 
   already_AddRefed<WaveShaperNode> CreateWaveShaper(ErrorResult& aRv);
 
   already_AddRefed<MediaElementAudioSourceNode> CreateMediaElementSource(
       HTMLMediaElement& aMediaElement, ErrorResult& aRv);
   already_AddRefed<MediaStreamAudioSourceNode> CreateMediaStreamSource(
       DOMMediaStream& aMediaStream, ErrorResult& aRv);
+  already_AddRefed<MediaStreamTrackAudioSourceNode>
+  CreateMediaStreamTrackSource(MediaStreamTrack& aMediaStreamTrack,
+                               ErrorResult& aRv);
 
   already_AddRefed<DelayNode> CreateDelay(double aMaxDelayTime,
                                           ErrorResult& aRv);
 
   already_AddRefed<PannerNode> CreatePanner(ErrorResult& aRv);
 
   already_AddRefed<ConvolverNode> CreateConvolver(ErrorResult& aRv);
 
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/MediaStreamTrackAudioSourceNode.cpp
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "MediaStreamTrackAudioSourceNode.h"
+#include "mozilla/dom/MediaStreamTrackAudioSourceNodeBinding.h"
+#include "AudioNodeEngine.h"
+#include "AudioNodeExternalInputStream.h"
+#include "AudioStreamTrack.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/CORSMode.h"
+#include "nsContentUtils.h"
+#include "nsIScriptError.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrackAudioSourceNode)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaStreamTrackAudioSourceNode)
+  tmp->Destroy();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputTrack)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
+    MediaStreamTrackAudioSourceNode, AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputTrack)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackAudioSourceNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+
+NS_IMPL_ADDREF_INHERITED(MediaStreamTrackAudioSourceNode, AudioNode)
+NS_IMPL_RELEASE_INHERITED(MediaStreamTrackAudioSourceNode, AudioNode)
+
+MediaStreamTrackAudioSourceNode::MediaStreamTrackAudioSourceNode(
+    AudioContext* aContext)
+    : AudioNode(aContext, 2, ChannelCountMode::Max,
+                ChannelInterpretation::Speakers),
+      mTrackListener(this) {}
+
+/* static */ already_AddRefed<MediaStreamTrackAudioSourceNode>
+MediaStreamTrackAudioSourceNode::Create(
+    AudioContext& aAudioContext,
+    const MediaStreamTrackAudioSourceOptions& aOptions, ErrorResult& aRv) {
+  if (aAudioContext.IsOffline()) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+
+  if (aAudioContext.Graph() != aOptions.mMediaStreamTrack->Graph()) {
+    nsCOMPtr<nsPIDOMWindowInner> pWindow = aAudioContext.GetParentObject();
+    Document* document = pWindow ? pWindow->GetExtantDoc() : nullptr;
+    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                    NS_LITERAL_CSTRING("Web Audio"), document,
+                                    nsContentUtils::eDOM_PROPERTIES,
+                                    "MediaStreamAudioSourceNodeDifferentRate");
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+
+  RefPtr<MediaStreamTrackAudioSourceNode> node =
+      new MediaStreamTrackAudioSourceNode(&aAudioContext);
+
+  node->Init(aOptions.mMediaStreamTrack, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  return node.forget();
+}
+
+void MediaStreamTrackAudioSourceNode::Init(MediaStreamTrack* aMediaStreamTrack,
+                                           ErrorResult& aRv) {
+  MOZ_ASSERT(aMediaStreamTrack);
+
+  if (!aMediaStreamTrack->AsAudioStreamTrack()) {
+    mTrackListener.NotifyEnded(nullptr);
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  MediaStreamGraph* graph = Context()->Graph();
+
+  AudioNodeEngine* engine = new MediaStreamTrackAudioSourceNodeEngine(this);
+  mStream = AudioNodeExternalInputStream::Create(graph, engine);
+
+  MOZ_ASSERT(mStream);
+
+  mInputTrack = aMediaStreamTrack;
+  ProcessedMediaStream* outputStream =
+      static_cast<ProcessedMediaStream*>(mStream.get());
+  mInputPort = mInputTrack->ForwardTrackContentsTo(outputStream);
+  PrincipalChanged(mInputTrack);  // trigger enabling/disabling of the connector
+  mInputTrack->AddPrincipalChangeObserver(this);
+
+  mInputTrack->AddConsumer(&mTrackListener);
+}
+
+void MediaStreamTrackAudioSourceNode::Destroy() {
+  if (mInputTrack) {
+    mInputTrack->RemovePrincipalChangeObserver(this);
+    mInputTrack->RemoveConsumer(&mTrackListener);
+    mInputTrack = nullptr;
+  }
+  mTrackListener.NotifyEnded(mInputTrack);
+
+  if (mInputPort) {
+    mInputPort->Destroy();
+    mInputPort = nullptr;
+  }
+}
+
+MediaStreamTrackAudioSourceNode::~MediaStreamTrackAudioSourceNode() {
+  Destroy();
+}
+
+/**
+ * Changes the principal. Note that this will be called on the main thread, but
+ * changes will be enacted on the MediaStreamGraph thread. If the principal
+ * change results in the document principal losing access to the stream, then
+ * there needs to be other measures in place to ensure that any media that is
+ * governed by the new stream principal is not available to the MediaStreamGraph
+ * before this change completes. Otherwise, a site could get access to
+ * media that they are not authorized to receive.
+ *
+ * One solution is to block the altered content, call this method, then dispatch
+ * another change request to the MediaStreamGraph thread that allows the content
+ * under the new principal to flow. This might be unnecessary if the principal
+ * change is changing to be the document principal.
+ */
+void MediaStreamTrackAudioSourceNode::PrincipalChanged(
+    MediaStreamTrack* aMediaStreamTrack) {
+  MOZ_ASSERT(aMediaStreamTrack == mInputTrack);
+
+  bool subsumes = false;
+  Document* doc = nullptr;
+  if (nsPIDOMWindowInner* parent = Context()->GetParentObject()) {
+    doc = parent->GetExtantDoc();
+    if (doc) {
+      nsIPrincipal* docPrincipal = doc->NodePrincipal();
+      nsIPrincipal* trackPrincipal = aMediaStreamTrack->GetPrincipal();
+      if (!trackPrincipal ||
+          NS_FAILED(docPrincipal->Subsumes(trackPrincipal, &subsumes))) {
+        subsumes = false;
+      }
+    }
+  }
+  auto stream = static_cast<AudioNodeExternalInputStream*>(mStream.get());
+  bool enabled = subsumes || aMediaStreamTrack->GetCORSMode() != CORS_NONE;
+  stream->SetInt32Parameter(MediaStreamTrackAudioSourceNodeEngine::ENABLE,
+                            enabled);
+  fprintf(stderr, "NOW: %s", enabled ? "enabled" : "disabled");
+
+  if (!enabled && doc) {
+    nsContentUtils::ReportToConsole(
+        nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Web Audio"), doc,
+        nsContentUtils::eDOM_PROPERTIES, CrossOriginErrorString());
+  }
+}
+
+size_t MediaStreamTrackAudioSourceNode::SizeOfExcludingThis(
+    MallocSizeOf aMallocSizeOf) const {
+  size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
+  if (mInputPort) {
+    amount += mInputPort->SizeOfIncludingThis(aMallocSizeOf);
+  }
+  return amount;
+}
+
+size_t MediaStreamTrackAudioSourceNode::SizeOfIncludingThis(
+    MallocSizeOf aMallocSizeOf) const {
+  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+}
+
+void MediaStreamTrackAudioSourceNode::DestroyMediaStream() {
+  if (mInputPort) {
+    mInputPort->Destroy();
+    mInputPort = nullptr;
+  }
+  AudioNode::DestroyMediaStream();
+}
+
+JSObject* MediaStreamTrackAudioSourceNode::WrapObject(
+    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
+  return MediaStreamTrackAudioSourceNode_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+}  // namespace dom
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/MediaStreamTrackAudioSourceNode.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 MediaStreamTrackAudioSourceNode_h_
+#define MediaStreamTrackAudioSourceNode_h_
+
+#include "AudioNode.h"
+#include "AudioNodeEngine.h"
+#include "mozilla/WeakPtr.h"
+
+namespace mozilla {
+
+namespace dom {
+
+class AudioContext;
+struct MediaStreamTrackAudioSourceOptions;
+
+class MediaStreamTrackAudioSourceNodeEngine final : public AudioNodeEngine {
+ public:
+  explicit MediaStreamTrackAudioSourceNodeEngine(AudioNode* aNode)
+      : AudioNodeEngine(aNode), mEnabled(false) {}
+
+  bool IsEnabled() const { return mEnabled; }
+  enum Parameters { ENABLE };
+  void SetInt32Parameter(uint32_t aIndex, int32_t aValue) override {
+    switch (aIndex) {
+      case ENABLE:
+        mEnabled = !!aValue;
+        break;
+      default:
+        NS_ERROR("MediaStreamTrackAudioSourceNodeEngine bad parameter index");
+    }
+  }
+
+ private:
+  bool mEnabled;
+};
+
+class MediaStreamTrackAudioSourceNode
+    : public AudioNode,
+      public PrincipalChangeObserver<MediaStreamTrack>,
+      public SupportsWeakPtr<MediaStreamTrackAudioSourceNode> {
+ public:
+  static already_AddRefed<MediaStreamTrackAudioSourceNode> Create(
+      AudioContext& aContext,
+      const MediaStreamTrackAudioSourceOptions& aOptions, ErrorResult& aRv);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MediaStreamTrackAudioSourceNode)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrackAudioSourceNode,
+                                           AudioNode)
+
+  static already_AddRefed<MediaStreamTrackAudioSourceNode> Constructor(
+      const GlobalObject& aGlobal, AudioContext& aAudioContext,
+      const MediaStreamTrackAudioSourceOptions& aOptions, ErrorResult& aRv) {
+    return Create(aAudioContext, aOptions, aRv);
+  }
+
+  JSObject* WrapObject(JSContext* aCx,
+                       JS::Handle<JSObject*> aGivenProto) override;
+
+  void DestroyMediaStream() override;
+
+  uint16_t NumberOfInputs() const override { return 0; }
+
+  const char* NodeType() const override {
+    return "MediaStreamTrackAudioSourceNode";
+  }
+
+  virtual const char* CrossOriginErrorString() const {
+    return "MediaStreamTrackAudioSourceNodeCrossOrigin";
+  }
+
+  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
+
+  // From PrincipalChangeObserver<MediaStreamTrack>.
+  void PrincipalChanged(MediaStreamTrack* aMediaStreamTrack) override;
+
+ protected:
+  explicit MediaStreamTrackAudioSourceNode(AudioContext* aContext);
+  void Init(MediaStreamTrack* aMediaStreamTrack, ErrorResult& aRv);
+  void Destroy();
+  virtual ~MediaStreamTrackAudioSourceNode();
+
+  class TrackListener : public MediaStreamTrackConsumer {
+   public:
+    explicit TrackListener(MediaStreamTrackAudioSourceNode* aNode)
+        : mNode(aNode) {}
+
+    void NotifyEnded(MediaStreamTrack* aTrack) override {
+      if (mNode) {
+        mNode->MarkInactive();
+        mNode->DestroyMediaStream();
+        mNode = nullptr;
+      }
+    }
+
+   private:
+    WeakPtr<MediaStreamTrackAudioSourceNode> mNode;
+  };
+
+ private:
+  RefPtr<MediaInputPort> mInputPort;
+  RefPtr<MediaStreamTrack> mInputTrack;
+  TrackListener mTrackListener;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif
--- a/dom/media/webaudio/moz.build
+++ b/dom/media/webaudio/moz.build
@@ -61,16 +61,17 @@ EXPORTS.mozilla.dom += [
     'ConvolverNode.h',
     'DelayNode.h',
     'DynamicsCompressorNode.h',
     'GainNode.h',
     'IIRFilterNode.h',
     'MediaElementAudioSourceNode.h',
     'MediaStreamAudioDestinationNode.h',
     'MediaStreamAudioSourceNode.h',
+    'MediaStreamTrackAudioSourceNode.h',
     'OscillatorNode.h',
     'PannerNode.h',
     'PeriodicWave.h',
     'ScriptProcessorNode.h',
     'StereoPannerNode.h',
     'WaveShaperNode.h',
 ]
 
@@ -105,16 +106,17 @@ UNIFIED_SOURCES += [
     'DynamicsCompressorNode.cpp',
     'FFTBlock.cpp',
     'GainNode.cpp',
     'IIRFilterNode.cpp',
     'MediaBufferDecoder.cpp',
     'MediaElementAudioSourceNode.cpp',
     'MediaStreamAudioDestinationNode.cpp',
     'MediaStreamAudioSourceNode.cpp',
+    'MediaStreamTrackAudioSourceNode.cpp',
     'OscillatorNode.cpp',
     'PannerNode.cpp',
     'PeriodicWave.cpp',
     'ScriptProcessorNode.cpp',
     'StereoPannerNode.cpp',
     'ThreeDPoint.cpp',
     'WaveShaperNode.cpp',
     'WebAudioUtils.cpp',
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -27,13 +27,14 @@ interface AudioContext : BaseAudioContex
     Promise<void> close();
 
     [NewObject, Throws]
     MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
 
     [NewObject, Throws]
     MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
 
-    // Bug 1324548: MediaStreamTrackAudioSourceNode createMediaStreamTrackSource (AudioMediaStreamTrack mediaStreamTrack);
+    [NewObject, Throws]
+    MediaStreamTrackAudioSourceNode createMediaStreamTrackSource(MediaStreamTrack mediaStreamTrack);
 
     [NewObject, Throws]
     MediaStreamAudioDestinationNode createMediaStreamDestination();
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MediaStreamTrackAudioSourceNode.webidl
@@ -0,0 +1,24 @@
+/* -*- 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/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+dictionary MediaStreamTrackAudioSourceOptions {
+    required MediaStreamTrack mediaStreamTrack;
+};
+
+[Pref="dom.webaudio.enabled",
+ Constructor(AudioContext context, MediaStreamTrackAudioSourceOptions options)]
+interface MediaStreamTrackAudioSourceNode : AudioNode {
+
+};
+
+// Mozilla extensions
+MediaStreamTrackAudioSourceNode implements AudioNodePassThrough;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -173,16 +173,19 @@ with Files("MediaDevice*"):
     BUG_COMPONENT = ("Core", "WebRTC")
 
 with Files("Media*Source*"):
     BUG_COMPONENT = ("Core", "Web Audio")
 
 with Files("MediaStream*"):
     BUG_COMPONENT = ("Core", "WebRTC")
 
+with Files("MediaStreamTrackAudio*"):
+    BUG_COMPONENT = ("Core", "Web Audio")
+
 with Files("MediaStreamAudio*"):
     BUG_COMPONENT = ("Core", "Web Audio")
 
 with Files("MediaEncryptedEvent.webidl"):
     BUG_COMPONENT = ("Core", "Audio/Video")
 
 with Files("MediaKey*"):
     BUG_COMPONENT = ("Core", "Audio/Video: Playback")
@@ -652,16 +655,17 @@ WEBIDL_FILES = [
     'MediaQueryList.webidl',
     'MediaRecorder.webidl',
     'MediaSource.webidl',
     'MediaStream.webidl',
     'MediaStreamAudioDestinationNode.webidl',
     'MediaStreamAudioSourceNode.webidl',
     'MediaStreamError.webidl',
     'MediaStreamTrack.webidl',
+    'MediaStreamTrackAudioSourceNode.webidl',
     'MediaTrackConstraintSet.webidl',
     'MediaTrackSettings.webidl',
     'MediaTrackSupportedConstraints.webidl',
     'MerchantValidationEvent.webidl',
     'MessageChannel.webidl',
     'MessageEvent.webidl',
     'MessagePort.webidl',
     'MIDIAccess.webidl',