Skip to content

Commit

Permalink
Cherry-pick a78127a. rdar://123634374
Browse files Browse the repository at this point in the history
    [Cocoa] Audio distortion during media playback when many AudioContexts are created
    https://bugs.webkit.org/show_bug.cgi?id=269833
    rdar://122590884

    Reviewed by Chris Dumez.

    In WebKit, each AudioContext created results in an additional thread serving that context's
    AudioDestination. (In WebKitLegacy, each AudioContext will result in an additional
    AudioOutputUnit running on a single high-priority audio thread.) When many threads
    (or AudioOutputUnits) are created, the overhead alone can cause underruns. And when this
    happens on the high-priority audio thread, it affects all audio playback within that
    process.

    Rather than create new threads or AudioOutputUnits (that are all rendering on the same
    thread to the same buffer in the end) for each AudioContext, a shared AudioDestination
    can be used for multiple AudioContext's with the same number of channels and sample rate.
    For common scenarios, this means only one high-priority audio thread will be created
    and serviced by a single AudioDestination. Specifically for WebKit, it means a single
    RemoteAudioDestination/Proxy pair for each WebContent process.

    * Source/WebCore/platform/audio/SharedAudioDestination.cpp: Added.
    (WebCore::SharedAudioDestinationAdapter::framesPerBuffer const):
    (WebCore::SharedAudioDestinationAdapter::sharedMap):
    (WebCore::SharedAudioDestinationAdapter::ensureAdapter):
    (WebCore::SharedAudioDestinationAdapter::SharedAudioDestinationAdapter):
    (WebCore::m_configurationSemaphore):
    (WebCore::SharedAudioDestinationAdapter::addRenderer):
    (WebCore::SharedAudioDestinationAdapter::removeRenderer):
    (WebCore::SharedAudioDestinationAdapter::configureRenderThread):
    (WebCore::SharedAudioDestinationAdapter::render):
    (WebCore::SharedAudioDestination::create):
    (WebCore::SharedAudioDestination::SharedAudioDestination):
    (WebCore::SharedAudioDestination::~SharedAudioDestination):
    (WebCore::SharedAudioDestination::start):
    (WebCore::SharedAudioDestination::stop):
    (WebCore::SharedAudioDestination::framesPerBuffer const):
    (WebCore::SharedAudioDestination::setIsPlaying):
    * Source/WebCore/platform/audio/SharedAudioDestination.h: Added.
    * Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.cpp:
    (WebCore::AudioDestination::create):
    * Source/WebKit/WebProcess/GPU/media/WebMediaStrategy.cpp:
    (WebKit::WebMediaStrategy::createAudioDestination):

    Canonical link: https://commits.webkit.org/275262@main

Identifier: 273664.1304@safari-7619.1.5-branch
  • Loading branch information
jernoble authored and MyahCobbs committed Feb 26, 2024
1 parent faea49f commit b36fd0e
Show file tree
Hide file tree
Showing 8 changed files with 418 additions and 3 deletions.
1 change: 1 addition & 0 deletions Source/WebCore/Headers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
platform/audio/PlatformMediaSessionManager.h
platform/audio/PlatformRawAudioData.h
platform/audio/PushPullFIFO.h
platform/audio/SharedAudioDestination.h

platform/calc/CalcExpressionNode.h
platform/calc/CalculationValue.h
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/Sources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2209,6 +2209,7 @@ platform/audio/ReverbAccumulationBuffer.cpp
platform/audio/ReverbConvolver.cpp
platform/audio/ReverbConvolverStage.cpp
platform/audio/ReverbInputBuffer.cpp
platform/audio/SharedAudioDestination.cpp
platform/audio/SincResampler.cpp
platform/audio/StereoPanner.cpp
platform/audio/UpSampler.cpp
Expand Down
10 changes: 10 additions & 0 deletions Source/WebCore/WebCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -5190,6 +5190,7 @@
CD8D306F23AD4FA8006C3975 /* CDMLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = CD8D306D23AD4FA8006C3975 /* CDMLogging.h */; };
CD92F5132260FFEE00F87BB3 /* DocumentFullscreen.h in Headers */ = {isa = PBXBuildFile; fileRef = CD92F5102260FFEE00F87BB3 /* DocumentFullscreen.h */; settings = {ATTRIBUTES = (Private, ); }; };
CD92F5182261038200F87BB3 /* FullscreenManager.h in Headers */ = {isa = PBXBuildFile; fileRef = CD92F5162261038200F87BB3 /* FullscreenManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
CD948D8F2B850E8200104CB3 /* SharedAudioDestination.h in Headers */ = {isa = PBXBuildFile; fileRef = CD948D8D2B850E8100104CB3 /* SharedAudioDestination.h */; settings = {ATTRIBUTES = (Private, ); }; };
CD94A5DE1F72F57B00F525C5 /* CDMClient.h in Headers */ = {isa = PBXBuildFile; fileRef = CD94A5C91F71CA9D00F525C5 /* CDMClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
CD9CC58524C6BBEB00CD3C64 /* VP9Utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = CD6FE5BA24BCE7B6009FCDA4 /* VP9Utilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
CD9DE17517AAC74C00EA386D /* JSMediaSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CD9DE17317AAC74C00EA386D /* JSMediaSource.h */; };
Expand Down Expand Up @@ -18239,6 +18240,8 @@
CD641EB11818F5ED00EE4C41 /* MediaSourcePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSourcePrivate.h; sourceTree = "<group>"; };
CD641EB21818F5ED00EE4C41 /* SourceBufferPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceBufferPrivate.h; sourceTree = "<group>"; };
CD641EC7181ED60100EE4C41 /* MediaSample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MediaSample.h; sourceTree = "<group>"; };
CD66AE032B816C4D00963337 /* SharedAudioDestinationCocoa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SharedAudioDestinationCocoa.h; sourceTree = "<group>"; };
CD66AE042B816C4D00963337 /* SharedAudioDestinationCocoa.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SharedAudioDestinationCocoa.cpp; sourceTree = "<group>"; };
CD6A1F0C297A1A8F00F7B9FA /* CanvasObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CanvasObserver.h; sourceTree = "<group>"; };
CD6FE5B724BCE645009FCDA4 /* VP9UtilitiesCocoa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VP9UtilitiesCocoa.h; sourceTree = "<group>"; };
CD6FE5B824BCE645009FCDA4 /* VP9UtilitiesCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VP9UtilitiesCocoa.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -18311,6 +18314,8 @@
CD92F5102260FFEE00F87BB3 /* DocumentFullscreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DocumentFullscreen.h; sourceTree = "<group>"; };
CD92F5162261038200F87BB3 /* FullscreenManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FullscreenManager.h; sourceTree = "<group>"; };
CD92F5172261038200F87BB3 /* FullscreenManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FullscreenManager.cpp; sourceTree = "<group>"; };
CD948D8D2B850E8100104CB3 /* SharedAudioDestination.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SharedAudioDestination.h; sourceTree = "<group>"; };
CD948D8E2B850E8100104CB3 /* SharedAudioDestination.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SharedAudioDestination.cpp; sourceTree = "<group>"; };
CD94A5C91F71CA9D00F525C5 /* CDMClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDMClient.h; sourceTree = "<group>"; };
CD94A5CC1F71CB6900F525C5 /* CDMRequirement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDMRequirement.h; sourceTree = "<group>"; };
CD94A5CD1F71CB6900F525C5 /* CDMKeySystemConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDMKeySystemConfiguration.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -34352,6 +34357,8 @@
CDC734131977896C0046BFC5 /* CARingBuffer.h */,
417F7AED2139BF6500FBA7EC /* MediaSessionManagerCocoa.h */,
417F7AEA2139BF6400FBA7EC /* MediaSessionManagerCocoa.mm */,
CD66AE042B816C4D00963337 /* SharedAudioDestinationCocoa.cpp */,
CD66AE032B816C4D00963337 /* SharedAudioDestinationCocoa.h */,
417F7AEB2139BF6400FBA7EC /* WebAudioBufferList.cpp */,
417F7AEC2139BF6500FBA7EC /* WebAudioBufferList.h */,
);
Expand Down Expand Up @@ -37580,6 +37587,8 @@
FD31607512B026F700C1A359 /* ReverbConvolverStage.h */,
FD31607612B026F700C1A359 /* ReverbInputBuffer.cpp */,
FD31607712B026F700C1A359 /* ReverbInputBuffer.h */,
CD948D8E2B850E8100104CB3 /* SharedAudioDestination.cpp */,
CD948D8D2B850E8100104CB3 /* SharedAudioDestination.h */,
FD00D7A214A3F61900734011 /* SincResampler.cpp */,
FD00D7A314A3F61900734011 /* SincResampler.h */,
E7FBE7C524EC36F300A18E62 /* StereoPanner.cpp */,
Expand Down Expand Up @@ -42074,6 +42083,7 @@
46C963C62B6C9CAE002F46D1 /* ShareableBitmapHandle.h in Headers */,
46ADA8792B6D5B6500D9D746 /* ShareableResource.h in Headers */,
1D9F0FC12122029B005D8FD4 /* ShareData.h in Headers */,
CD948D8F2B850E8200104CB3 /* SharedAudioDestination.h in Headers */,
1A4A954E0B4EDCCB002D8C3C /* SharedBuffer.h in Headers */,
51FA2EDF27506FDE0011C15D /* SharedBufferChunkReader.h in Headers */,
510A91DC24CF46FE00BFD89C /* SharedGamepadValue.h in Headers */,
Expand Down
328 changes: 328 additions & 0 deletions Source/WebCore/platform/audio/SharedAudioDestination.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
/*
* Copyright (C) 2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "SharedAudioDestination.h"

#if ENABLE(WEB_AUDIO)

#include "AudioUtilities.h"
#include <wtf/NeverDestroyed.h>
#include <wtf/WTFSemaphore.h>
#include <wtf/WeakPtr.h>
#include <wtf/WorkQueue.h>

namespace WebCore {

class SharedAudioDestinationAdapter : public ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<SharedAudioDestinationAdapter>, public AudioIOCallback {
public:
using AudioDestinationCreationFunction = SharedAudioDestination::AudioDestinationCreationFunction;
static Ref<SharedAudioDestinationAdapter> ensureAdapter(unsigned numberOfOutputChannels, float sampleRate, AudioDestinationCreationFunction&& ensureFunction);
~SharedAudioDestinationAdapter();

void addRenderer(SharedAudioDestination&, CompletionHandler<void(bool)>&&);
void removeRenderer(SharedAudioDestination&, CompletionHandler<void(bool)>&&);

unsigned framesPerBuffer() const
{
return m_workBus->length();
}

private:
using AdapterKey = std::tuple<unsigned, float>;
using AdapterMap = HashMap<AdapterKey, ThreadSafeWeakPtr<SharedAudioDestinationAdapter>>;
static AdapterMap& sharedMap();

SharedAudioDestinationAdapter(unsigned numberOfOutputChannels, float sampleRate, AudioDestinationCreationFunction&&);

void render(AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess, const AudioIOPosition& outputPosition) final;
void isPlayingDidChange() final { }

void configureRenderThread(CompletionHandler<void(bool)>&&);

Ref<AudioDestination> protectedDestination() { return m_destination; }
Ref<AudioBus> protectedWorkBus() { return m_workBus; }
Ref<WorkQueue> protectedConfigurationQueue() { return m_configurationQueue; }

unsigned m_numberOfOutputChannels;
float m_sampleRate;

Ref<AudioDestination> m_destination;
Ref<AudioBus> m_workBus;
Ref<WorkQueue> m_configurationQueue;

bool m_started { false };

Lock m_renderLock;
Semaphore m_configurationSemaphore;

// Only accessed on m_configurationQueue:
Vector<RefPtr<SharedAudioDestination>> m_renderers;

bool m_needsConfiguration WTF_GUARDED_BY_LOCK(m_renderLock) { true };
Vector<RefPtr<SharedAudioDestination>> m_newRenderers WTF_GUARDED_BY_LOCK(m_renderLock);

// Only accessed on the audio thread:
Vector<RefPtr<SharedAudioDestination>> m_configuredRenderers;
};

auto SharedAudioDestinationAdapter::sharedMap() -> AdapterMap&
{
static MainThreadNeverDestroyed<AdapterMap> map;
return map;
}

Ref<SharedAudioDestinationAdapter> SharedAudioDestinationAdapter::ensureAdapter(unsigned numberOfOutputChannels, float sampleRate, AudioDestinationCreationFunction&& ensureFunction)
{
std::tuple key { numberOfOutputChannels, sampleRate };
auto results = sharedMap().find(key);
if (results != sharedMap().end()) {
if (RefPtr existingAdapter = results->value.get())
return existingAdapter.releaseNonNull();
}

Ref newAdapter = adoptRef(*new SharedAudioDestinationAdapter(numberOfOutputChannels, sampleRate, WTFMove(ensureFunction)));
auto weakAdapter = ThreadSafeWeakPtr<SharedAudioDestinationAdapter> { newAdapter.get() };
sharedMap().set(key, WTFMove(weakAdapter));
return newAdapter;
}

SharedAudioDestinationAdapter::SharedAudioDestinationAdapter(unsigned numberOfOutputChannels, float sampleRate, AudioDestinationCreationFunction&& ensureFunction)
: m_numberOfOutputChannels { numberOfOutputChannels }
, m_sampleRate { sampleRate }
, m_destination { ensureFunction(*this) }
, m_workBus { AudioBus::create(numberOfOutputChannels, AudioUtilities::renderQuantumSize).releaseNonNull() }
, m_configurationQueue { WorkQueue::create("SharedAudioDestinationAdapter configuration queue") }
, m_configurationSemaphore(0)
{
}

SharedAudioDestinationAdapter::~SharedAudioDestinationAdapter()
{
auto key = std::make_tuple(m_numberOfOutputChannels, m_sampleRate);
sharedMap().remove(key);
protectedDestination()->clearCallback();
}

void SharedAudioDestinationAdapter::addRenderer(SharedAudioDestination& renderer, CompletionHandler<void(bool)>&& completionHandler)
{
protectedConfigurationQueue()->dispatch([this, weakThis = ThreadSafeWeakPtr { *this }, renderer = RefPtr { &renderer }, completionHandler = WTFMove(completionHandler)] () mutable {
RefPtr protectedThis = weakThis.get();
if (!protectedThis) {
callOnMainThread([completionHandler = WTFMove(completionHandler)] () mutable { completionHandler(false);
});
return;
}

if (!m_renderers.contains(renderer))
m_renderers.append(WTFMove(renderer));
configureRenderThread(WTFMove(completionHandler));
});
}

void SharedAudioDestinationAdapter::removeRenderer(SharedAudioDestination& renderer, CompletionHandler<void(bool)>&& completionHandler)
{
protectedConfigurationQueue()->dispatch([this, weakThis = ThreadSafeWeakPtr { *this }, renderer = RefPtr { &renderer }, completionHandler = WTFMove(completionHandler)] () mutable {
RefPtr protectedThis = weakThis.get();
if (!protectedThis) {
callOnMainThread([completionHandler = WTFMove(completionHandler)] () mutable { completionHandler(false);
});
return;
}

m_renderers.removeFirst(renderer);
configureRenderThread(WTFMove(completionHandler));
});
}

void SharedAudioDestinationAdapter::configureRenderThread(CompletionHandler<void(bool)>&& completionHandler)
{
ASSERT(m_configurationQueue->isCurrent());
{
Locker locker { m_renderLock };
m_newRenderers = m_renderers;
m_needsConfiguration = true;
}

bool shouldStart = !m_started && !m_renderers.isEmpty();
bool shouldStop = m_started && m_renderers.isEmpty();

// If the destination has not been started, and the list of
// renderers is empty, do not wait for the render thread to
// finish configuration, as it will never run.
bool shouldSkipRendering = !m_started && m_renderers.isEmpty();

if (!shouldSkipRendering) {
// The AudioDestination must be started for configuration to take place.
if (shouldStart) {
// Dispatching to the main thread is required for destinations
// which are subclasses of AudioDestinationResampler.
callOnMainThreadAndWait([this] {
protectedDestination()->start(nullptr, [] (bool) { });
});
m_started = true;
}

m_configurationSemaphore.wait();

// The AudioDestination must not be stopped before configuration takes place.
if (shouldStop) {
// Dispatching to the main thread is required for destinations
// which are subclasses of AudioDestinationResampler.
callOnMainThreadAndWait([this] {
protectedDestination()->stop();
});
m_started = false;
}
}

// Move the previously configured list of renderers to the MainThread for destruction:
Vector<RefPtr<SharedAudioDestination>> renderersToDispose;
{
Locker locker { m_renderLock };
renderersToDispose = std::exchange(m_newRenderers, { });
}

callOnMainThread([completionHandler = WTFMove(completionHandler), renderersToDispose = WTFMove(renderersToDispose)]() mutable {
renderersToDispose.clear();
completionHandler(true);
});
}

void SharedAudioDestinationAdapter::render(AudioBus* sourceBus, AudioBus* destinationBus, size_t numberOfFrames, const AudioIOPosition& outputPosition)
{
if (m_renderLock.tryLock()) {
Locker locker { AdoptLock, m_renderLock };
if (m_needsConfiguration) {
// The SharedAudioDestinationAdapter avoids allocing or deallocing on the
// high priority audio thread by merely swapping the contents of the renderer
// configuration vectors. After the swap, the contents of m_newRenderers will
// be destroyed by configureRenderThread() on the m_configurationWorkQueue.
std::swap(m_newRenderers, m_configuredRenderers);
m_needsConfiguration = false;
m_configurationSemaphore.signal();
}
}

bool isFirstRenderer = true;
for (RefPtr renderer : m_configuredRenderers) {
if (isFirstRenderer) {
// The first renderer should render directly to destinationBus.
renderer->sharedRender(sourceBus, destinationBus, numberOfFrames, outputPosition);
isFirstRenderer = false;
continue;
}
// Subsequent renderers should render to the m_workBus, which will
// then be summed to the destinationBus.
Ref protectedWorkBus = this->protectedWorkBus();
renderer->sharedRender(sourceBus, protectedWorkBus.ptr(), numberOfFrames, outputPosition);
destinationBus->sumFrom(protectedWorkBus);
}
}
Ref<SharedAudioDestination> SharedAudioDestination::create(AudioIOCallback& callback, unsigned numberOfOutputChannels, float sampleRate, AudioDestinationCreationFunction&& ensureFunction)
{
return adoptRef(*new SharedAudioDestination(callback, numberOfOutputChannels, sampleRate, WTFMove(ensureFunction)));
}

SharedAudioDestination::SharedAudioDestination(AudioIOCallback& callback, unsigned numberOfOutputChannels, float sampleRate, AudioDestinationCreationFunction&& ensureFunction)
: AudioDestination(callback, sampleRate)
, m_outputAdapter(SharedAudioDestinationAdapter::ensureAdapter(numberOfOutputChannels, sampleRate, WTFMove(ensureFunction)))
{
}

SharedAudioDestination::~SharedAudioDestination()
{
if (isPlaying())
stop([] (bool) { });
}

void SharedAudioDestination::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler)
{
{
Locker locker { m_dispatchToRenderThreadLock };
m_dispatchToRenderThread = WTFMove(dispatchToRenderThread);
}

setIsPlaying(true);
protectedOutputAdapter()->addRenderer(*this, WTFMove(completionHandler));
}

void SharedAudioDestination::stop(CompletionHandler<void(bool)>&& completionHandler)
{
setIsPlaying(false);
protectedOutputAdapter()->removeRenderer(*this, WTFMove(completionHandler));

{
Locker locker { m_dispatchToRenderThreadLock };
m_dispatchToRenderThread = nullptr;
}
}

unsigned SharedAudioDestination::framesPerBuffer() const
{
return m_outputAdapter->framesPerBuffer();
}

void SharedAudioDestination::setIsPlaying(bool isPlaying)
{
ASSERT(isMainThread());

if (m_isPlaying == isPlaying)
return;

m_isPlaying = isPlaying;

{
Locker locker { m_callbackLock };
if (m_callback)
m_callback->isPlayingDidChange();
}
}

void SharedAudioDestination::sharedRender(AudioBus* sourceBus, AudioBus* destinationBus, size_t numberOfFrames, const AudioIOPosition& outputPosition)
{
if (!m_dispatchToRenderThreadLock.tryLock()) {
destinationBus->zero();
return;
}

Locker locker { AdoptLock, m_dispatchToRenderThreadLock };
if (!m_dispatchToRenderThread)
callRenderCallback(sourceBus, destinationBus, numberOfFrames, outputPosition);
else {
m_dispatchToRenderThread([protectedThis = Ref { *this }, sourceBus = RefPtr { sourceBus }, destinationBus = RefPtr { destinationBus }, numberOfFrames, outputPosition]() mutable {
protectedThis->callRenderCallback(sourceBus.get(), destinationBus.get(), numberOfFrames, outputPosition);
});
}
}

Ref<SharedAudioDestinationAdapter> SharedAudioDestination::protectedOutputAdapter()
{
return m_outputAdapter;
}

} // namespace WebCore

#endif // ENABLE(WEB_AUDIO)
Loading

0 comments on commit b36fd0e

Please sign in to comment.