diff --git a/dom/media/webaudio/AudioWorkletGlobalScope.cpp b/dom/media/webaudio/AudioWorkletGlobalScope.cpp index 96e935f4bc19..ba4f423c200c 100644 --- a/dom/media/webaudio/AudioWorkletGlobalScope.cpp +++ b/dom/media/webaudio/AudioWorkletGlobalScope.cpp @@ -12,6 +12,7 @@ #include "jsapi.h" #include "mozilla/dom/AudioWorkletGlobalScopeBinding.h" #include "mozilla/dom/AudioWorkletProcessor.h" +#include "mozilla/dom/MessagePort.h" #include "mozilla/dom/StructuredCloneHolder.h" #include "mozilla/dom/WorkletPrincipals.h" #include "mozilla/dom/AudioParamDescriptorBinding.h" @@ -296,6 +297,7 @@ AudioParamDescriptorMap AudioWorkletGlobalScope::DescriptorsFromJS( bool AudioWorkletGlobalScope::ConstructProcessor( const nsAString& aName, NotNull aSerializedOptions, + UniqueMessagePortId& aPortIdentifier, JS::MutableHandle aRetProcessor) { /** * See @@ -307,10 +309,15 @@ bool AudioWorkletGlobalScope::ConstructProcessor( } JSContext* cx = jsapi.cx(); ErrorResult rv; - /** TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1565956 + /** * 4. Let deserializedPort be the result of * StructuredDeserialize(serializedPort, the current Realm). */ + RefPtr deserializedPort = + MessagePort::Create(this, aPortIdentifier, rv); + if (NS_WARN_IF(rv.MaybeSetPendingException(cx))) { + return false; + } /** * 5. Let deserializedOptions be the result of * StructuredDeserialize(serializedOptions, the current Realm). @@ -329,11 +336,14 @@ bool AudioWorkletGlobalScope::ConstructProcessor( // AudioWorkletNode has already checked the definition exists. // See also https://github.com/WebAudio/web-audio-api/issues/1854 MOZ_ASSERT(processorCtor); - /** TODO https://bugzilla.mozilla.org/show_bug.cgi?id=1565956 + /** * 7. Store nodeReference and deserializedPort to node reference and * transferred port of this AudioWorkletGlobalScope's pending processor * construction data respectively. */ + // |nodeReference| is not required here because the "processorerror" event + // is thrown by WorkletNodeEngine::ConstructProcessor(). + mPortForProcessor = std::move(deserializedPort); /** * 8. Construct a callback function from processorCtor with the argument * of deserializedOptions. @@ -344,6 +354,8 @@ bool AudioWorkletGlobalScope::ConstructProcessor( RefPtr processor = processorCtor->Construct( options, rv, "AudioWorkletProcessor construction", CallbackFunction::eReportExceptions); + // https://github.com/WebAudio/web-audio-api/issues/2096 + mPortForProcessor = nullptr; if (rv.Failed()) { rv.SuppressException(); // already reported return false; diff --git a/dom/media/webaudio/AudioWorkletGlobalScope.h b/dom/media/webaudio/AudioWorkletGlobalScope.h index 1975ce5f766b..03b1b97ffccb 100644 --- a/dom/media/webaudio/AudioWorkletGlobalScope.h +++ b/dom/media/webaudio/AudioWorkletGlobalScope.h @@ -19,7 +19,9 @@ class AudioWorkletImpl; namespace dom { class AudioWorkletProcessorConstructor; +class MessagePort; class StructuredCloneHolder; +class UniqueMessagePortId; class AudioWorkletGlobalScope final : public WorkletGlobalScope { public: @@ -49,6 +51,7 @@ class AudioWorkletGlobalScope final : public WorkletGlobalScope { MOZ_CAN_RUN_SCRIPT bool ConstructProcessor(const nsAString& aName, NotNull aSerializedOptions, + UniqueMessagePortId& aPortIdentifier, JS::MutableHandle aRetProcessor); private: @@ -66,6 +69,10 @@ class AudioWorkletGlobalScope final : public WorkletGlobalScope { typedef nsRefPtrHashtable NodeNameToProcessorDefinitionMap; NodeNameToProcessorDefinitionMap mNameToProcessorMap; + // https://webaudio.github.io/web-audio-api/#pending-processor-construction-data-transferred-port + // This does not need to be traversed during cycle-collection because it is + // only set while this AudioWorkletGlobalScope is on the stack. + RefPtr mPortForProcessor; }; } // namespace dom diff --git a/dom/media/webaudio/AudioWorkletNode.cpp b/dom/media/webaudio/AudioWorkletNode.cpp index 67ed27020096..2b69b3b05dc9 100644 --- a/dom/media/webaudio/AudioWorkletNode.cpp +++ b/dom/media/webaudio/AudioWorkletNode.cpp @@ -30,7 +30,8 @@ class WorkletNodeEngine final : public AudioNodeEngine { MOZ_CAN_RUN_SCRIPT void ConstructProcessor(AudioWorkletImpl* aWorkletImpl, const nsAString& aName, - NotNull aSerializedOptions); + NotNull aSerializedOptions, + UniqueMessagePortId& aPortIdentifier); void ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom, const AudioBlock& aInput, AudioBlock* aOutput, @@ -120,13 +121,15 @@ void WorkletNodeEngine::SendProcessorError() { void WorkletNodeEngine::ConstructProcessor( AudioWorkletImpl* aWorkletImpl, const nsAString& aName, - NotNull aSerializedOptions) { + NotNull aSerializedOptions, + UniqueMessagePortId& aPortIdentifier) { MOZ_ASSERT(mInputs.mPorts.empty() && mOutputs.mPorts.empty()); RefPtr global = aWorkletImpl->GetGlobalScope(); MOZ_ASSERT(global); // global has already been used to register processor JS::RootingContext* cx = RootingCx(); mProcessor.init(cx); - if (!global->ConstructProcessor(aName, aSerializedOptions, &mProcessor) || + if (!global->ConstructProcessor(aName, aSerializedOptions, aPortIdentifier, + &mProcessor) || // mInputs and mOutputs outer arrays are fixed length and so much of the // initialization need only be performed once (i.e. here). NS_WARN_IF(!mInputs.mPorts.growBy(InputCount())) || @@ -501,11 +504,12 @@ already_AddRefed AudioWorkletNode::Constructor( // See bug 1535398. [track = audioWorkletNode->mTrack, workletImpl = RefPtr(workletImpl), - name = nsString(aName), options = std::move(serializedOptions)]() - MOZ_CAN_RUN_SCRIPT_BOUNDARY { + name = nsString(aName), options = std::move(serializedOptions), + portId = std::move(processorPortId)]() + MOZ_CAN_RUN_SCRIPT_BOUNDARY mutable { auto engine = static_cast(track->Engine()); engine->ConstructProcessor(workletImpl, name, - WrapNotNull(options.get())); + WrapNotNull(options.get()), portId); })); return audioWorkletNode.forget();