Bug 855568 - Implement MediaElementAudioSourceNode
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 25 Jul 2013 15:01:49 +1200
changeset 141610 27f3845226754750f69e1c5b63ed985ea0276b18
parent 141609 11b2cd90a51ae9e1c1d2f8e610a681b07b9bcc6e
child 141611 e14729d47ea8ff0b0d24cac7d6f418106cdf35d0
push id32157
push userrocallahan@mozilla.com
push dateWed, 07 Aug 2013 02:31:51 +0000
treeherdermozilla-inbound@91f4bd08f12b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs855568
milestone26.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 855568 - Implement MediaElementAudioSourceNode X-Git-Commit-ID: 52f1fcdd561e8214e6820a3f2478d9e8b9623430
content/media/webaudio/AudioContext.cpp
content/media/webaudio/AudioContext.h
content/media/webaudio/MediaElementAudioSourceNode.cpp
content/media/webaudio/MediaElementAudioSourceNode.h
content/media/webaudio/moz.build
content/media/webaudio/test/Makefile.in
content/media/webaudio/test/test_mediaElementAudioSourceNode.html
dom/webidl/AudioContext.webidl
dom/webidl/MediaElementAudioSourceNode.webidl
dom/webidl/WebIDL.mk
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -3,24 +3,26 @@
 /* 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 "AudioContext.h"
 #include "nsContentUtils.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/AnalyserNode.h"
 #include "mozilla/dom/AudioContextBinding.h"
+#include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/OfflineAudioContextBinding.h"
 #include "MediaStreamGraph.h"
-#include "mozilla/dom/AnalyserNode.h"
 #include "AudioDestinationNode.h"
 #include "AudioBufferSourceNode.h"
 #include "AudioBuffer.h"
 #include "GainNode.h"
+#include "MediaElementAudioSourceNode.h"
 #include "MediaStreamAudioSourceNode.h"
 #include "DelayNode.h"
 #include "PannerNode.h"
 #include "AudioListener.h"
 #include "DynamicsCompressorNode.h"
 #include "BiquadFilterNode.h"
 #include "ScriptProcessorNode.h"
 #include "ChannelMergerNode.h"
@@ -249,25 +251,43 @@ AudioContext::CreateScriptProcessor(uint
 
 already_AddRefed<AnalyserNode>
 AudioContext::CreateAnalyser()
 {
   nsRefPtr<AnalyserNode> analyserNode = new AnalyserNode(this);
   return analyserNode.forget();
 }
 
+already_AddRefed<MediaElementAudioSourceNode>
+AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement,
+                                       ErrorResult& aRv)
+{
+  if (mIsOffline) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+  nsRefPtr<DOMMediaStream> stream = aMediaElement.MozCaptureStream(aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+  nsRefPtr<MediaElementAudioSourceNode> mediaElementAudioSourceNode =
+    new MediaElementAudioSourceNode(this, stream);
+  return mediaElementAudioSourceNode.forget();
+}
+
 already_AddRefed<MediaStreamAudioSourceNode>
 AudioContext::CreateMediaStreamSource(DOMMediaStream& aMediaStream,
                                       ErrorResult& aRv)
 {
   if (mIsOffline) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
-  nsRefPtr<MediaStreamAudioSourceNode> mediaStreamAudioSourceNode = new MediaStreamAudioSourceNode(this, &aMediaStream);
+  nsRefPtr<MediaStreamAudioSourceNode> mediaStreamAudioSourceNode =
+    new MediaStreamAudioSourceNode(this, &aMediaStream);
   return mediaStreamAudioSourceNode.forget();
 }
 
 already_AddRefed<GainNode>
 AudioContext::CreateGain()
 {
   nsRefPtr<GainNode> gainNode = new GainNode(this);
   return gainNode.forget();
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -47,16 +47,18 @@ class AudioListener;
 class BiquadFilterNode;
 class ChannelMergerNode;
 class ChannelSplitterNode;
 class ConvolverNode;
 class DelayNode;
 class DynamicsCompressorNode;
 class GainNode;
 class GlobalObject;
+class HTMLMediaElement;
+class MediaElementAudioSourceNode;
 class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
 class OfflineRenderSuccessCallback;
 class PannerNode;
 class ScriptProcessorNode;
 class WaveShaperNode;
 class PeriodicWave;
 
@@ -157,16 +159,18 @@ public:
   CreateWaveShaper();
 
   already_AddRefed<GainNode>
   CreateGainNode()
   {
     return CreateGain();
   }
 
+  already_AddRefed<MediaElementAudioSourceNode>
+  CreateMediaElementSource(HTMLMediaElement& aMediaElement, ErrorResult& aRv);
   already_AddRefed<MediaStreamAudioSourceNode>
   CreateMediaStreamSource(DOMMediaStream& aMediaStream, ErrorResult& aRv);
 
   already_AddRefed<DelayNode>
   CreateDelay(double aMaxDelayTime, ErrorResult& aRv);
 
   already_AddRefed<DelayNode>
   CreateDelayNode(double aMaxDelayTime, ErrorResult& aRv)
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/MediaElementAudioSourceNode.cpp
@@ -0,0 +1,27 @@
+/* -*- 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 "MediaElementAudioSourceNode.h"
+#include "mozilla/dom/MediaElementAudioSourceNodeBinding.h"
+#include "mozilla/dom/HTMLMediaElement.h"
+
+namespace mozilla {
+namespace dom {
+
+MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* aContext,
+                                                         DOMMediaStream* aStream)
+  : MediaStreamAudioSourceNode(aContext, aStream)
+{
+}
+
+JSObject*
+MediaElementAudioSourceNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return MediaElementAudioSourceNodeBinding::Wrap(aCx, aScope, this);
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/MediaElementAudioSourceNode.h
@@ -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/. */
+
+#ifndef MediaElementAudioSourceNode_h_
+#define MediaElementAudioSourceNode_h_
+
+#include "MediaStreamAudioSourceNode.h"
+
+namespace mozilla {
+namespace dom {
+
+class HTMLMediaElement;
+
+class MediaElementAudioSourceNode : public MediaStreamAudioSourceNode
+{
+public:
+  MediaElementAudioSourceNode(AudioContext* aContext,
+                              DOMMediaStream* aStream);
+
+  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+};
+
+}
+}
+
+#endif
--- a/content/media/webaudio/moz.build
+++ b/content/media/webaudio/moz.build
@@ -34,16 +34,17 @@ EXPORTS.mozilla.dom += [
     'BiquadFilterNode.h',
     'ChannelMergerNode.h',
     'ChannelSplitterNode.h',
     'ConvolverNode.h',
     'DelayNode.h',
     'DynamicsCompressorNode.h',
     'EnableWebAudioCheck.h',
     'GainNode.h',
+    'MediaElementAudioSourceNode.h',
     'MediaStreamAudioDestinationNode.h',
     'MediaStreamAudioSourceNode.h',
     'OfflineAudioCompletionEvent.h',
     'PannerNode.h',
     'PeriodicWave.h',
     'ScriptProcessorNode.h',
     'WaveShaperNode.h',
 ]
@@ -62,16 +63,17 @@ CPP_SOURCES += [
     'ChannelMergerNode.cpp',
     'ChannelSplitterNode.cpp',
     'ConvolverNode.cpp',
     'DelayNode.cpp',
     'DynamicsCompressorNode.cpp',
     'EnableWebAudioCheck.cpp',
     'GainNode.cpp',
     'MediaBufferDecoder.cpp',
+    'MediaElementAudioSourceNode.cpp',
     'MediaStreamAudioDestinationNode.cpp',
     'MediaStreamAudioSourceNode.cpp',
     'OfflineAudioCompletionEvent.cpp',
     'PannerNode.cpp',
     'PeriodicWave.cpp',
     'ScriptProcessorNode.cpp',
     'ThreeDPoint.cpp',
     'WaveShaperNode.cpp',
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -62,16 +62,17 @@ MOCHITEST_FILES := \
   test_delayNode.html \
   test_delayNodeSmallMaxDelay.html \
   test_delayNodeWithGain.html \
   test_dynamicsCompressorNode.html \
   test_gainNode.html \
   test_gainNodeInLoop.html \
   test_maxChannelCount.html \
   test_mediaDecoding.html \
+  test_mediaElementAudioSourceNode.html \
   test_mediaStreamAudioDestinationNode.html \
   test_mediaStreamAudioSourceNode.html \
   test_mediaStreamAudioSourceNodeCrossOrigin.html \
   test_mediaStreamAudioSourceNodeResampling.html \
   test_mixingRules.html \
   test_nodeToParamConnection.html \
   test_OfflineAudioContext.html \
   test_offlineDestinationChannelCountLess.html \
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_mediaElementAudioSourceNode.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<meta charset="utf-8">
+<head>
+  <title>Test MediaElementAudioSourceNode</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();
+
+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 expectedMinNonzeroSampleCount;
+var expectedMaxNonzeroSampleCount;
+var nonzeroSampleCount = 0;
+var complete = false;
+var iterationCount = 0;
+
+// 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;
+  is(e.inputBuffer.numberOfChannels, 1,
+     "Checking data channel count (nonzeroSamplesThisBuffer=" +
+     nonzeroSamplesThisBuffer + ")");
+  ok(nonzeroSampleCount <= expectedMaxNonzeroSampleCount,
+     "Too many nonzero samples (got " + nonzeroSampleCount + ", expected max " + expectedMaxNonzeroSampleCount + ")");
+  if (nonzeroSampleCount >= expectedMinNonzeroSampleCount &&
+      nonzeroSamplesThisBuffer == 0) {
+    ok(true,
+     "Check received enough nonzero samples (got " + nonzeroSampleCount + ", expected min " + expectedMinNonzeroSampleCount + ")");
+    SimpleTest.finish();
+    complete = true;
+  }
+}
+
+audio.oncanplaythrough = function() {
+  // Use a fuzz factor of 100 to account for samples that just happen to be zero
+  expectedMinNonzeroSampleCount = Math.floor(audio.duration*context.sampleRate) - 100;
+  expectedMaxNonzeroSampleCount = Math.floor(audio.duration*context.sampleRate) + 500;
+  sp.onaudioprocess = processSamples;
+};
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -38,16 +38,18 @@ interface AudioContext : EventTarget {
     [Creator, Throws]
     ScriptProcessorNode createScriptProcessor(optional unsigned long bufferSize = 0,
                                               optional unsigned long numberOfInputChannels = 2,
                                               optional unsigned long numberOfOutputChannels = 2);
 
     [Creator]
     AnalyserNode createAnalyser();
     [Creator, Throws]
+    MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
+    [Creator, Throws]
     MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
     [Creator]
     GainNode createGain();
     [Creator, Throws]
     DelayNode createDelay(optional double maxDelayTime = 1);
     [Creator]
     BiquadFilterNode createBiquadFilter();
     [Creator]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MediaElementAudioSourceNode.webidl
@@ -0,0 +1,17 @@
+/* -*- 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://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[PrefControlled]
+interface MediaElementAudioSourceNode : AudioNode {
+
+};
+
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -178,16 +178,17 @@ webidl_files = \
   ImageData.webidl \
   ImageDocument.webidl \
   InspectorUtils.webidl \
   KeyboardEvent.webidl \
   KeyEvent.webidl \
   LinkStyle.webidl \
   LocalMediaStream.webidl \
   Location.webidl \
+  MediaElementAudioSourceNode.webidl \
   MediaError.webidl \
   MediaRecorder.webidl \
   MediaSource.webidl \
   MediaStream.webidl \
   MediaStreamAudioDestinationNode.webidl \
   MediaStreamAudioSourceNode.webidl \
   MediaStreamEvent.webidl \
   MediaStreamTrack.webidl \