Bug 1470856 - Add AudioWorklet definition. r=baku,karlt
MozReview-Commit-ID: 39eqjisGNTE
--- 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>