Bug 1470856 - Add AudioWorklet definition. r=baku,karlt
authorArnaud Bienner <arnaud.bienner@gmail.com>
Wed, 27 Jun 2018 11:31:02 +0200
changeset 424466 74e0bf980eae79f08d96fabd018d0fb0a0b149bd
parent 424465 fb53c31538e73ebf5003eb6461cdbfdd5f2dcba0
child 424467 e9912e5af51b980491e43cb0ffc89d625edea4ea
push id34210
push userapavel@mozilla.com
push dateSat, 30 Jun 2018 09:48:57 +0000
treeherdermozilla-central@c0cd065ee5c8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, karlt
bugs1470856
milestone63.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 1470856 - Add AudioWorklet definition. r=baku,karlt MozReview-Commit-ID: 39eqjisGNTE
dom/bindings/Bindings.conf
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioContext.h
dom/webidl/AudioWorklet.webidl
dom/webidl/BaseAudioContext.webidl
dom/webidl/moz.build
dom/worklet/Worklet.cpp
dom/worklet/tests/mochitest.ini
dom/worklet/tests/test_audioWorklet.html
dom/worklet/tests/test_audioWorklet_insecureContext.html
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -89,16 +89,20 @@ DOMInterfaces = {
 'AudioNode' : {
     'concrete': False,
     'binaryNames': {
         'channelCountMode': 'channelCountModeValue',
         'channelInterpretation': 'channelInterpretationValue',
     },
 },
 
+'AudioWorklet': {
+    'nativeType': 'mozilla::dom::Worklet',
+},
+
 'BarProp': {
     'headerFile': 'mozilla/dom/BarProps.h',
 },
 
 'BaseAudioContext': {
     'nativeType': 'mozilla::dom::AudioContext',
 },
 
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -32,16 +32,17 @@
 #include "mozilla/dom/MediaStreamAudioSourceNodeBinding.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"
 
 #include "AudioBuffer.h"
 #include "AudioBufferSourceNode.h"
 #include "AudioChannelService.h"
 #include "AudioDestinationNode.h"
 #include "AudioListener.h"
 #include "AudioNodeStream.h"
 #include "AudioStream.h"
@@ -55,16 +56,17 @@
 #include "DynamicsCompressorNode.h"
 #include "GainNode.h"
 #include "IIRFilterNode.h"
 #include "MediaElementAudioSourceNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "MediaStreamAudioSourceNode.h"
 #include "MediaStreamGraph.h"
 #include "nsContentUtils.h"
+#include "nsGlobalWindowInner.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsRFPService.h"
 #include "OscillatorNode.h"
 #include "PannerNode.h"
 #include "PeriodicWave.h"
@@ -532,16 +534,38 @@ AudioListener*
 AudioContext::Listener()
 {
   if (!mListener) {
     mListener = new AudioListener(this);
   }
   return mListener;
 }
 
+Worklet*
+AudioContext::GetAudioWorklet(ErrorResult& aRv)
+{
+  if (!mWorklet) {
+    nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
+    if (NS_WARN_IF(!window)) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    nsCOMPtr<nsIPrincipal> principal =
+        nsGlobalWindowInner::Cast(window)->GetPrincipal();
+    if (NS_WARN_IF(!principal)) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+
+    mWorklet = new Worklet(window, principal, Worklet::eAudioWorklet);
+  }
+
+  return mWorklet;
+}
+
 bool
 AudioContext::IsRunning() const
 {
   return mAudioContextState == AudioContextState::Running;
 }
 
 already_AddRefed<Promise>
 AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -65,16 +65,17 @@ class IIRFilterNode;
 class MediaElementAudioSourceNode;
 class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
 class OscillatorNode;
 class PannerNode;
 class ScriptProcessorNode;
 class StereoPannerNode;
 class WaveShaperNode;
+class Worklet;
 class PeriodicWave;
 struct PeriodicWaveConstraints;
 class Promise;
 enum class OscillatorType : uint8_t;
 
 // This is addrefed by the OscillatorNodeEngine on the main thread
 // and then used from the MSG thread.
 // It can be released either from the graph thread or the main thread.
@@ -187,16 +188,19 @@ public:
 
   bool ShouldSuspendNewStream() const { return mSuspendCalled; }
 
   double CurrentTime();
 
   AudioListener* Listener();
 
   AudioContextState State() const { return mAudioContextState; }
+
+  Worklet* GetAudioWorklet(ErrorResult& aRv);
+
   bool IsRunning() const;
 
   // Those three methods return a promise to content, that is resolved when an
   // (possibly long) operation is completed on the MSG (and possibly other)
   // thread(s). To avoid having to match the calls and asychronous result when
   // the operation is completed, we keep a reference to the promises on the main
   // thread, and then send the promises pointers down the MSG thread, as a void*
   // (to make it very clear that the pointer is to merely be treated as an ID).
@@ -347,16 +351,17 @@ private:
   // MediaStreams for a given context, on the MediasStreamGraph side.
   const AudioContextId mId;
   // Note that it's important for mSampleRate to be initialized before
   // mDestination, as mDestination's constructor needs to access it!
   const float mSampleRate;
   AudioContextState mAudioContextState;
   RefPtr<AudioDestinationNode> mDestination;
   RefPtr<AudioListener> mListener;
+  RefPtr<Worklet> mWorklet;
   nsTArray<UniquePtr<WebAudioDecodeJob> > mDecodeJobs;
   // This array is used to keep the suspend/close promises alive until
   // they are resolved, so we can safely pass them accross threads.
   nsTArray<RefPtr<Promise>> mPromiseGripArray;
   // This array is used to onlly keep the resume promises alive until they are
   // resolved, so we can safely pass them accross threads. If the audio context
   // is not allowed to play, the promise would be pending in this array and be
   // resolved until audio context has been allowed and user call resume() again.
new file mode 100644
--- /dev/null
+++ b/dom/webidl/AudioWorklet.webidl
@@ -0,0 +1,15 @@
+/* -*- 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 © 2018 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[Exposed=Window, SecureContext, Pref="dom.audioworklet.enabled"]
+interface AudioWorklet : Worklet {
+};
\ No newline at end of file
--- a/dom/webidl/BaseAudioContext.webidl
+++ b/dom/webidl/BaseAudioContext.webidl
@@ -20,16 +20,18 @@ enum AudioContextState {
 };
 
 interface BaseAudioContext : EventTarget {
     readonly        attribute AudioDestinationNode destination;
     readonly        attribute float                sampleRate;
     readonly        attribute double               currentTime;
     readonly        attribute AudioListener        listener;
     readonly        attribute AudioContextState    state;
+    [Throws, SameObject, SecureContext, Pref="dom.audioworklet.enabled"]
+    readonly        attribute AudioWorklet         audioWorklet;
     // Bug 1324552: readonly        attribute double               baseLatency;
 
     [Throws]
     Promise<void> resume();
 
                     attribute EventHandler         onstatechange;
 
     [NewObject, Throws]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -379,16 +379,17 @@ WEBIDL_FILES = [
     'AudioNode.webidl',
     'AudioParam.webidl',
     'AudioParamMap.webidl',
     'AudioProcessingEvent.webidl',
     'AudioScheduledSourceNode.webidl',
     'AudioStreamTrack.webidl',
     'AudioTrack.webidl',
     'AudioTrackList.webidl',
+    'AudioWorklet.webidl',
     'AudioWorkletGlobalScope.webidl',
     'AudioWorkletNode.webidl',
     'AudioWorkletProcessor.webidl',
     'AutocompleteInfo.webidl',
     'BarProp.webidl',
     'BaseAudioContext.webidl',
     'BaseKeyframeTypes.webidl',
     'BasicCardPayment.webidl',
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Worklet.h"
 #include "WorkletThread.h"
 #include "AudioWorkletGlobalScope.h"
 #include "PaintWorkletGlobalScope.h"
 
 #include "mozilla/dom/WorkletBinding.h"
+#include "mozilla/dom/AudioWorkletBinding.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/RegisterWorkletBindings.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/ScriptLoader.h"
@@ -503,17 +504,21 @@ Worklet::~Worklet()
 {
   TerminateThread();
 }
 
 JSObject*
 Worklet::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return Worklet_Binding::Wrap(aCx, this, aGivenProto);
+  if (mWorkletType == eAudioWorklet) {
+    return AudioWorklet_Binding::Wrap(aCx, this, aGivenProto);
+  } else {
+    return Worklet_Binding::Wrap(aCx, this, aGivenProto);
+  }
 }
 
 already_AddRefed<Promise>
 Worklet::Import(const nsAString& aModuleURL, CallerType aCallerType,
                 ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return WorkletFetchHandler::Fetch(this, aModuleURL, aCallerType, aRv);
--- a/dom/worklet/tests/mochitest.ini
+++ b/dom/worklet/tests/mochitest.ini
@@ -6,14 +6,16 @@ support-files =
 [test_basic.html]
 [test_console.html]
 support-files=worklet_console.js
 [test_import_with_cache.html]
 skip-if = verify
 support-files=server_import_with_cache.sjs
 [test_dump.html]
 support-files=worklet_dump.js
+[test_audioWorklet_insecureContext.html]
 [test_audioWorklet.html]
 support-files=worklet_audioWorklet.js
+scheme = https
 [test_exception.html]
 support-files=worklet_exception.js
 [test_paintWorklet.html]
 support-files=worklet_paintWorklet.js
--- a/dom/worklet/tests/test_audioWorklet.html
+++ b/dom/worklet/tests/test_audioWorklet.html
@@ -28,19 +28,23 @@ function configureTest() {
         }
       }
     }
   }
 
   var cl = new consoleListener();
 
   return SpecialPowers.pushPrefEnv(
-    {"set": [["dom.audioWorklet.enabled", true],
+    {"set": [["dom.audioworklet.enabled", true],
              ["dom.worklet.enabled", true]]});
 }
 
 // This function is called into an iframe.
 function runTestInIframe() {
-  audioWorklet.import("worklet_audioWorklet.js")
+  ok(window.isSecureContext, "Test should run in secure context");
+  var audioContext = new AudioContext();
+  ok(audioContext.audioWorklet instanceof AudioWorklet,
+     "AudioContext.audioWorklet should be an instance of AudioWorklet");
+  audioContext.audioWorklet.import("worklet_audioWorklet.js")
 }
 </script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/worklet/tests/test_audioWorklet_insecureContext.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for No AudioWorklet in insecure context</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="common.js"></script>
+</head>
+<body>
+
+<script type="application/javascript">
+
+function configureTest() {
+  return SpecialPowers.pushPrefEnv(
+    {"set": [["dom.audioworklet.enabled", true],
+             ["dom.worklet.enabled", true]]});
+}
+
+// This function is called into an iframe.
+function runTestInIframe() {
+  ok(!window.isSecureContext, "Test should run in an insecure context");
+  var audioContext = new AudioContext();
+  ok(!("audioWorklet" in audioContext),
+     "AudioWorklet shouldn't be defined in AudioContext in a insecure context");
+  SimpleTest.finish();
+}
+</script>
+</body>
+</html>