AudioWorkletImpl.cpp (4056B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #include "AudioWorkletImpl.h" 8 9 #include "AudioContext.h" 10 #include "AudioNodeTrack.h" 11 #include "AudioWorklet.h" 12 #include "GeckoProfiler.h" 13 #include "mozilla/dom/AudioWorkletBinding.h" 14 #include "mozilla/dom/AudioWorkletGlobalScope.h" 15 #include "mozilla/dom/MessageChannel.h" 16 #include "mozilla/dom/MessagePort.h" 17 #include "mozilla/dom/WorkletThread.h" 18 #include "nsGlobalWindowInner.h" 19 20 namespace mozilla { 21 22 /* static */ already_AddRefed<dom::AudioWorklet> 23 AudioWorkletImpl::CreateWorklet(dom::AudioContext* aContext, ErrorResult& aRv) { 24 MOZ_ASSERT(NS_IsMainThread()); 25 26 nsGlobalWindowInner* window = aContext->GetOwnerWindow(); 27 if (NS_WARN_IF(!window)) { 28 aRv.Throw(NS_ERROR_FAILURE); 29 return nullptr; 30 } 31 nsIPrincipal* principal = window->GetPrincipal(); 32 if (NS_WARN_IF(!principal)) { 33 aRv.Throw(NS_ERROR_FAILURE); 34 return nullptr; 35 } 36 37 RefPtr<dom::MessageChannel> messageChannel = 38 dom::MessageChannel::Constructor(window, aRv); 39 if (NS_WARN_IF(aRv.Failed())) { 40 return nullptr; 41 } 42 43 dom::UniqueMessagePortId globalScopePortId; 44 messageChannel->Port2()->CloneAndDisentangle(globalScopePortId); 45 46 RefPtr<AudioWorkletImpl> impl = 47 new AudioWorkletImpl(window, principal, aContext->DestinationTrack(), 48 std::move(globalScopePortId)); 49 50 // The Worklet owns a reference to the AudioContext so as to keep the graph 51 // thread running as long as the Worklet is alive by keeping the 52 // AudioDestinationNode alive. 53 return MakeAndAddRef<dom::AudioWorklet>( 54 window, std::move(impl), ToSupports(aContext), messageChannel->Port1()); 55 } 56 57 AudioWorkletImpl::AudioWorkletImpl(nsPIDOMWindowInner* aWindow, 58 nsIPrincipal* aPrincipal, 59 AudioNodeTrack* aDestinationTrack, 60 dom::UniqueMessagePortId&& aPortIdentifier) 61 : WorkletImpl(aWindow, aPrincipal), 62 mDestinationTrack(aDestinationTrack), 63 mGlobalScopePortIdentifier(std::move(aPortIdentifier)) {} 64 65 AudioWorkletImpl::~AudioWorkletImpl() = default; 66 67 JSObject* AudioWorkletImpl::WrapWorklet(JSContext* aCx, dom::Worklet* aWorklet, 68 JS::Handle<JSObject*> aGivenProto) { 69 MOZ_ASSERT(NS_IsMainThread()); 70 return dom::AudioWorklet_Binding::Wrap( 71 aCx, static_cast<dom::AudioWorklet*>(aWorklet), aGivenProto); 72 } 73 74 nsresult AudioWorkletImpl::SendControlMessage( 75 already_AddRefed<nsIRunnable> aRunnable) { 76 mDestinationTrack->SendRunnable(std::move(aRunnable)); 77 return NS_OK; 78 } 79 80 void AudioWorkletImpl::OnAddModuleStarted() const { 81 #ifdef MOZ_GECKO_PROFILER 82 profiler_add_marker(ProfilerStringView("AudioWorklet.addModule"), 83 geckoprofiler::category::MEDIA_RT, 84 {MarkerTiming::IntervalStart()}); 85 #endif 86 } 87 88 void AudioWorkletImpl::OnAddModulePromiseSettled() const { 89 #ifdef MOZ_GECKO_PROFILER 90 profiler_add_marker(ProfilerStringView("AudioWorklet.addModule"), 91 geckoprofiler::category::MEDIA_RT, 92 {MarkerTiming::IntervalEnd()}); 93 #endif 94 } 95 96 already_AddRefed<dom::WorkletGlobalScope> 97 AudioWorkletImpl::ConstructGlobalScope(JSContext* aCx) { 98 dom::WorkletThread::AssertIsOnWorkletThread(); 99 100 RefPtr<dom::AudioWorkletGlobalScope> globalScope = 101 new dom::AudioWorkletGlobalScope(this); 102 103 ErrorResult rv; 104 RefPtr<dom::MessagePort> deserializedPort = 105 dom::MessagePort::Create(globalScope, mGlobalScopePortIdentifier, rv); 106 if (NS_WARN_IF(rv.MaybeSetPendingException(aCx))) { 107 // The exception will be propagated into the global 108 return globalScope.forget(); 109 } 110 111 globalScope->SetPort(deserializedPort); 112 113 return globalScope.forget(); 114 } 115 116 } // namespace mozilla