Bug 1470856 - Add AudioWorklet definition. r=baku,karlt draft
authorArnaud Bienner <arnaud.bienner@gmail.com>
Wed, 27 Jun 2018 11:31:02 +0200
changeset 812472 97c18e1125c490f3e9aa3b9d5c864f99da6fd265
parent 812437 bf149090f6b5db3fe86618b5f1047b70b1bff8b5
push id114562
push userbmo:arnaud.bienner@gmail.com
push dateFri, 29 Jun 2018 13:31:17 +0000
reviewersbaku, karlt
bugs1470856
milestone63.0a1
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',
     'AutocompleteInfo.webidl',
     'BarProp.webidl',
     'BaseAudioContext.webidl',
     'BaseKeyframeTypes.webidl',
     'BasicCardPayment.webidl',
     'BatteryManager.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>