Title: [269073] trunk
Revision
269073
Author
[email protected]
Date
2020-10-27 14:46:21 -0700 (Tue, 27 Oct 2020)

Log Message

[GPUProcess] Use async IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination
https://bugs.webkit.org/show_bug.cgi?id=218251

Reviewed by Geoffrey Garen.

Source/WebCore:

DefaultAudioDestinationNode::resume() / suspend() were already asynchronous operations. However, they expected
AudioDestination::start() / stop() to finish synchronously and would simply call their completion handler
asynchronously. Instead, we now make AudioDestination::start() / stop() asynchronous as well. This allows us
to use asynchronous IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination.

As a result of this change, I had to make AudioDestinationNode::startRendering() asynchronous as well since
it uses AudioDestination::start() internally.

As an improvement, the completion handler to AudioDestinationNode's startRendering() / resume() / suspend()
is now provided with an exception in cases where they fail. This allows the call sites to properly deal
with such errors instead of assuming things were successsful.

No new tests, no Web-facing beahvior change.

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::suspendRendering):
(WebCore::AudioContext::resumeRendering):
(WebCore::AudioContext::startRendering):
(WebCore::AudioContext::mayResumePlayback):
(WebCore::AudioContext::suspendPlayback):
* Modules/webaudio/AudioDestinationNode.h:
(WebCore::AudioDestinationNode::resume):
(WebCore::AudioDestinationNode::suspend):
(WebCore::AudioDestinationNode::close):
* Modules/webaudio/DefaultAudioDestinationNode.cpp:
(WebCore::DefaultAudioDestinationNode::startRendering):
(WebCore::DefaultAudioDestinationNode::resume):
(WebCore::DefaultAudioDestinationNode::suspend):
(WebCore::DefaultAudioDestinationNode::close):
* Modules/webaudio/DefaultAudioDestinationNode.h:
* Modules/webaudio/OfflineAudioContext.cpp:
(WebCore::OfflineAudioContext::startOfflineRendering):
(WebCore::OfflineAudioContext::resumeOfflineRendering):
* Modules/webaudio/OfflineAudioDestinationNode.cpp:
(WebCore::OfflineAudioDestinationNode::startRendering):
* Modules/webaudio/OfflineAudioDestinationNode.h:
* platform/audio/AudioDestination.h:
(WebCore::AudioDestination::start):
(WebCore::AudioDestination::stop):
* platform/audio/cocoa/AudioDestinationCocoa.cpp:
(WebCore::AudioDestinationCocoa::start):
(WebCore::AudioDestinationCocoa::stop):
* platform/audio/cocoa/AudioDestinationCocoa.h:
* platform/audio/gstreamer/AudioDestinationGStreamer.cpp:
(WebCore::AudioDestinationGStreamer::start):
(WebCore::AudioDestinationGStreamer::stop):
* platform/audio/gstreamer/AudioDestinationGStreamer.h:
* platform/mock/MockAudioDestinationCocoa.cpp:
(WebCore::MockAudioDestinationCocoa::start):
(WebCore::MockAudioDestinationCocoa::stop):
* platform/mock/MockAudioDestinationCocoa.h:

Source/WebKit:

Use async IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination.

* GPUProcess/media/RemoteAudioDestinationManager.messages.in:
* WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp:
(WebKit::RemoteAudioDestinationProxy::start):
(WebKit::RemoteAudioDestinationProxy::stop):
* WebProcess/GPU/media/RemoteAudioDestinationProxy.h:

LayoutTests:

* webaudio/audiocontext-state.html:
Update existing test which incorrectly expected the AudioContext's state to become "running" synchronously
after connecting a source node. The state switches to "running" asynchronously now. It is up to the user
agent if and when the audio context starts autoplaying so this should be an acceptable behavior change.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (269072 => 269073)


--- trunk/LayoutTests/ChangeLog	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/LayoutTests/ChangeLog	2020-10-27 21:46:21 UTC (rev 269073)
@@ -1,3 +1,15 @@
+2020-10-27  Chris Dumez  <[email protected]>
+
+        [GPUProcess] Use async IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination
+        https://bugs.webkit.org/show_bug.cgi?id=218251
+
+        Reviewed by Geoffrey Garen.
+
+        * webaudio/audiocontext-state.html:
+        Update existing test which incorrectly expected the AudioContext's state to become "running" synchronously
+        after connecting a source node. The state switches to "running" asynchronously now. It is up to the user
+        agent if and when the audio context starts autoplaying so this should be an acceptable behavior change.
+
 2020-10-27  Fujii Hironori  <[email protected]>
 
         [TextureMapper][GTK] Test compositing/clipping/border-radius-stacking-context-clip.html is failing

Modified: trunk/LayoutTests/webaudio/audiocontext-state.html (269072 => 269073)


--- trunk/LayoutTests/webaudio/audiocontext-state.html	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/LayoutTests/webaudio/audiocontext-state.html	2020-10-27 21:46:21 UTC (rev 269073)
@@ -16,20 +16,25 @@
 var context = null;
 var node = null;
 
+function onAudioContextAutoStart()
+{
+    context._onstatechange_ = null;
+    shouldBeEqualToString('context.state', 'running');
+
+    debug('Calling context.suspend()');
+    context.suspend().then(suspendSucceeded, suspendFailed);
+}
+
 function runTest() {
     window.jsTestIsAsync = true;
 
     context = new AudioContext();
+    context._onstatechange_ = onAudioContextAutoStart;
 
-    shouldBe('context.state', '"suspended"');
+    shouldBeEqualToString('context.state', 'suspended');
 
     node = context.createBufferSource();
     evalAndLog('node.connect(context.destination)');
-
-    shouldBe('context.state', '"running"');
-
-    debug('Calling context.suspend()');
-    context.suspend().then(suspendSucceeded, suspendFailed);
 }
 
 function suspendFailed() {

Modified: trunk/Source/WebCore/ChangeLog (269072 => 269073)


--- trunk/Source/WebCore/ChangeLog	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/ChangeLog	2020-10-27 21:46:21 UTC (rev 269073)
@@ -1,3 +1,62 @@
+2020-10-27  Chris Dumez  <[email protected]>
+
+        [GPUProcess] Use async IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination
+        https://bugs.webkit.org/show_bug.cgi?id=218251
+
+        Reviewed by Geoffrey Garen.
+
+        DefaultAudioDestinationNode::resume() / suspend() were already asynchronous operations. However, they expected
+        AudioDestination::start() / stop() to finish synchronously and would simply call their completion handler
+        asynchronously. Instead, we now make AudioDestination::start() / stop() asynchronous as well. This allows us
+        to use asynchronous IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination.
+
+        As a result of this change, I had to make AudioDestinationNode::startRendering() asynchronous as well since
+        it uses AudioDestination::start() internally.
+
+        As an improvement, the completion handler to AudioDestinationNode's startRendering() / resume() / suspend()
+        is now provided with an exception in cases where they fail. This allows the call sites to properly deal
+        with such errors instead of assuming things were successsful.
+
+        No new tests, no Web-facing beahvior change.
+
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::suspendRendering):
+        (WebCore::AudioContext::resumeRendering):
+        (WebCore::AudioContext::startRendering):
+        (WebCore::AudioContext::mayResumePlayback):
+        (WebCore::AudioContext::suspendPlayback):
+        * Modules/webaudio/AudioDestinationNode.h:
+        (WebCore::AudioDestinationNode::resume):
+        (WebCore::AudioDestinationNode::suspend):
+        (WebCore::AudioDestinationNode::close):
+        * Modules/webaudio/DefaultAudioDestinationNode.cpp:
+        (WebCore::DefaultAudioDestinationNode::startRendering):
+        (WebCore::DefaultAudioDestinationNode::resume):
+        (WebCore::DefaultAudioDestinationNode::suspend):
+        (WebCore::DefaultAudioDestinationNode::close):
+        * Modules/webaudio/DefaultAudioDestinationNode.h:
+        * Modules/webaudio/OfflineAudioContext.cpp:
+        (WebCore::OfflineAudioContext::startOfflineRendering):
+        (WebCore::OfflineAudioContext::resumeOfflineRendering):
+        * Modules/webaudio/OfflineAudioDestinationNode.cpp:
+        (WebCore::OfflineAudioDestinationNode::startRendering):
+        * Modules/webaudio/OfflineAudioDestinationNode.h:
+        * platform/audio/AudioDestination.h:
+        (WebCore::AudioDestination::start):
+        (WebCore::AudioDestination::stop):
+        * platform/audio/cocoa/AudioDestinationCocoa.cpp:
+        (WebCore::AudioDestinationCocoa::start):
+        (WebCore::AudioDestinationCocoa::stop):
+        * platform/audio/cocoa/AudioDestinationCocoa.h:
+        * platform/audio/gstreamer/AudioDestinationGStreamer.cpp:
+        (WebCore::AudioDestinationGStreamer::start):
+        (WebCore::AudioDestinationGStreamer::stop):
+        * platform/audio/gstreamer/AudioDestinationGStreamer.h:
+        * platform/mock/MockAudioDestinationCocoa.cpp:
+        (WebCore::MockAudioDestinationCocoa::start):
+        (WebCore::MockAudioDestinationCocoa::stop):
+        * platform/mock/MockAudioDestinationCocoa.h:
+
 2020-10-27  Fujii Hironori  <[email protected]>
 
         [TextureMapper][GTK] Test compositing/clipping/border-radius-stacking-context-clip.html is failing

Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -223,7 +223,11 @@
 
     lazyInitialize();
 
-    destinationNode()->suspend([this, protectedThis = makeRef(*this), promise = WTFMove(promise)]() mutable {
+    destinationNode()->suspend([this, protectedThis = makeRef(*this), promise = WTFMove(promise)](Optional<Exception>&& exception) mutable {
+        if (exception) {
+            promise.reject(WTFMove(*exception));
+            return;
+        }
         setState(State::Suspended);
         promise.resolve();
     });
@@ -250,7 +254,12 @@
 
     lazyInitialize();
 
-    destinationNode()->resume([this, protectedThis = makeRef(*this), promise = WTFMove(promise)]() mutable {
+    destinationNode()->resume([this, protectedThis = makeRef(*this), promise = WTFMove(promise)](Optional<Exception>&& exception) mutable {
+        if (exception) {
+            promise.reject(WTFMove(*exception));
+            return;
+        }
+
         // Since we update the state asynchronously, we may have been interrupted after the
         // call to resume() and before this lambda runs. In this case, we don't want to
         // reset the state to running.
@@ -286,10 +295,11 @@
 
     makePendingActivity();
 
-    setState(State::Running);
-
     lazyInitialize();
-    destination()->startRendering();
+    destination()->startRendering([this, protectedThis = makeRef(*this)](Optional<Exception>&& exception) {
+        if (!exception)
+            setState(State::Running);
+    });
 }
 
 void AudioContext::lazyInitialize()
@@ -357,8 +367,8 @@
 
     lazyInitialize();
 
-    destinationNode()->resume([this, protectedThis = makeRef(*this)] {
-        setState(State::Running);
+    destinationNode()->resume([this, protectedThis = makeRef(*this)](Optional<Exception>&& exception) {
+        setState(exception ? State::Suspended : State::Running);
     });
 }
 
@@ -436,7 +446,10 @@
 
     lazyInitialize();
 
-    destinationNode()->suspend([this, protectedThis = makeRef(*this)] {
+    destinationNode()->suspend([this, protectedThis = makeRef(*this)](Optional<Exception>&& exception) {
+        if (exception)
+            return;
+
         bool interrupted = m_mediaSession->state() == PlatformMediaSession::Interrupted;
         setState(interrupted ? State::Interrupted : State::Suspended);
     });

Modified: trunk/Source/WebCore/Modules/webaudio/AudioDestinationNode.h (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/AudioDestinationNode.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/AudioDestinationNode.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -28,7 +28,7 @@
 #include "AudioIOCallback.h"
 #include "AudioNode.h"
 #include "ExceptionOr.h"
-#include <wtf/Function.h>
+#include <wtf/CompletionHandler.h>
 
 namespace WebCore {
 
@@ -53,10 +53,10 @@
     // Enable local/live input for the specified device.
     virtual void enableInput(const String& inputDeviceId) = 0;
 
-    virtual ExceptionOr<void> startRendering() = 0;
-    virtual void resume(WTF::Function<void ()>&&) { }
-    virtual void suspend(WTF::Function<void ()>&&) { }
-    virtual void close(WTF::Function<void ()>&&) { }
+    virtual void startRendering(CompletionHandler<void(Optional<Exception>&&)>&&) = 0;
+    virtual void resume(CompletionHandler<void(Optional<Exception>&&)>&& completionHandler) { completionHandler(WTF::nullopt); }
+    virtual void suspend(CompletionHandler<void(Optional<Exception>&&)>&& completionHandler) { completionHandler(WTF::nullopt); }
+    virtual void close(CompletionHandler<void()>&& completionHandler) { completionHandler(); }
 
     virtual bool isPlaying() { return false; }
     void isPlayingDidChange() override;

Modified: trunk/Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.cpp (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -119,37 +119,53 @@
     return { };
 }
 
-ExceptionOr<void> DefaultAudioDestinationNode::startRendering()
+void DefaultAudioDestinationNode::startRendering(CompletionHandler<void(Optional<Exception>&&)>&& completionHandler)
 {
     ASSERT(isInitialized());
     if (!isInitialized())
-        return Exception { InvalidStateError, "AudioDestinationNode is not initialized"_s };
+        return completionHandler(Exception { InvalidStateError, "AudioDestinationNode is not initialized"_s });
 
-    m_destination->start(dispatchToRenderThreadFunction());
-    return { };
+    auto innerCompletionHandler = [completionHandler = WTFMove(completionHandler)](bool success) mutable {
+        completionHandler(success ? WTF::nullopt : makeOptional(Exception { InvalidStateError, "Failed to start the audio device"_s }));
+    };
+
+    m_destination->start(dispatchToRenderThreadFunction(), WTFMove(innerCompletionHandler));
 }
 
-void DefaultAudioDestinationNode::resume(Function<void ()>&& function)
+void DefaultAudioDestinationNode::resume(CompletionHandler<void(Optional<Exception>&&)>&& completionHandler)
 {
     ASSERT(isInitialized());
-    if (isInitialized())
-        m_destination->start(dispatchToRenderThreadFunction());
-    context().postTask(WTFMove(function));
+    if (!isInitialized()) {
+        context().postTask([completionHandler = WTFMove(completionHandler)]() mutable {
+            completionHandler(Exception { InvalidStateError, "AudioDestinationNode is not initialized"_s });
+        });
+        return;
+    }
+    m_destination->start(dispatchToRenderThreadFunction(), [completionHandler = WTFMove(completionHandler)](bool success) mutable {
+        completionHandler(success ? WTF::nullopt : makeOptional(Exception { InvalidStateError, "Failed to start the audio device"_s }));
+    });
 }
 
-void DefaultAudioDestinationNode::suspend(Function<void ()>&& function)
+void DefaultAudioDestinationNode::suspend(CompletionHandler<void(Optional<Exception>&&)>&& completionHandler)
 {
     ASSERT(isInitialized());
-    if (isInitialized())
-        m_destination->stop();
-    context().postTask(WTFMove(function));
+    if (!isInitialized()) {
+        context().postTask([completionHandler = WTFMove(completionHandler)]() mutable {
+            completionHandler(Exception { InvalidStateError, "AudioDestinationNode is not initialized"_s });
+        });
+        return;
+    }
+
+    m_destination->stop([completionHandler = WTFMove(completionHandler)](bool success) mutable {
+        completionHandler(success ? WTF::nullopt : makeOptional(Exception { InvalidStateError, "Failed to stop the audio device"_s }));
+    });
 }
 
-void DefaultAudioDestinationNode::close(Function<void()>&& function)
+void DefaultAudioDestinationNode::close(CompletionHandler<void()>&& completionHandler)
 {
     ASSERT(isInitialized());
     uninitialize();
-    context().postTask(WTFMove(function));
+    context().postTask(WTFMove(completionHandler));
 }
 
 unsigned DefaultAudioDestinationNode::maxChannelCount() const

Modified: trunk/Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.h (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -43,7 +43,7 @@
     unsigned framesPerBuffer() const;
     float sampleRate() const final { return m_sampleRate; }
     
-    ExceptionOr<void> startRendering() final;
+    void startRendering(CompletionHandler<void(Optional<Exception>&&)>&&) final;
 
 private:
     explicit DefaultAudioDestinationNode(BaseAudioContext&, Optional<float>);
@@ -58,9 +58,9 @@
     bool requiresTailProcessing() const final { return false; }
 
     void enableInput(const String& inputDeviceId) final;
-    void resume(Function<void ()>&&) final;
-    void suspend(Function<void ()>&&) final;
-    void close(Function<void ()>&&) final;
+    void resume(CompletionHandler<void(Optional<Exception>&&)>&&) final;
+    void suspend(CompletionHandler<void(Optional<Exception>&&)>&&) final;
+    void close(CompletionHandler<void()>&&) final;
     unsigned maxChannelCount() const final;
     bool isPlaying() final;
 

Modified: trunk/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/OfflineAudioContext.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -105,16 +105,17 @@
 
     lazyInitialize();
 
-    auto result = destination()->startRendering();
-    if (result.hasException()) {
-        promise->reject(result.releaseException());
-        return;
-    }
+    destination()->startRendering([this, promise = WTFMove(promise), pendingActivity = ActiveDOMObject::makePendingActivity(*this)](Optional<Exception>&& exception) mutable {
+        if (exception) {
+            promise->reject(WTFMove(*exception));
+            return;
+        }
 
-    makePendingActivity();
-    m_pendingOfflineRenderingPromise = WTFMove(promise);
-    m_didStartOfflineRendering = true;
-    setState(State::Running);
+        makePendingActivity();
+        m_pendingOfflineRenderingPromise = WTFMove(promise);
+        m_didStartOfflineRendering = true;
+        setState(State::Running);
+    });
 }
 
 void OfflineAudioContext::suspendOfflineRendering(double suspendTime, Ref<DeferredPromise>&& promise)
@@ -166,15 +167,16 @@
     }
     ASSERT(state() == AudioContextState::Suspended);
 
-    auto result = destination()->startRendering();
-    if (result.hasException()) {
-        promise->reject(result.releaseException());
-        return;
-    }
+    destination()->startRendering([this, promise = WTFMove(promise), pendingActivity = ActiveDOMObject::makePendingActivity(*this)](Optional<Exception>&& exception) mutable {
+        if (exception) {
+            promise->reject(WTFMove(*exception));
+            return;
+        }
 
-    makePendingActivity();
-    setState(State::Running);
-    promise->resolve();
+        makePendingActivity();
+        setState(State::Running);
+        promise->resolve();
+    });
 }
 
 bool OfflineAudioContext::shouldSuspend()

Modified: trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.cpp (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -84,7 +84,7 @@
     AudioNode::uninitialize();
 }
 
-ExceptionOr<void> OfflineAudioDestinationNode::startRendering()
+void OfflineAudioDestinationNode::startRendering(CompletionHandler<void(Optional<Exception>&&)>&& completionHandler)
 {
     ALWAYS_LOG(LOGIDENTIFIER);
 
@@ -91,10 +91,10 @@
     ASSERT(isMainThread());
     ASSERT(m_renderTarget.get());
     if (!m_renderTarget.get())
-        return Exception { InvalidStateError, "OfflineAudioContextNode has no rendering buffer"_s };
+        return completionHandler(Exception { InvalidStateError, "OfflineAudioContextNode has no rendering buffer"_s });
     
     if (m_startedRendering)
-        return Exception { InvalidStateError, "Already started rendering"_s };
+        return completionHandler(Exception { InvalidStateError, "Already started rendering"_s });
 
     m_startedRendering = true;
     auto protectedThis = makeRef(*this);
@@ -121,12 +121,12 @@
         workletProxy->postTaskForModeToWorkletGlobalScope([offThreadRendering = WTFMove(offThreadRendering)](ScriptExecutionContext&) mutable {
             offThreadRendering();
         }, WorkerRunLoop::defaultMode());
-        return { };
+        return completionHandler(WTF::nullopt);
     }
 
     // FIXME: We should probably limit the number of threads we create for offline audio.
     m_renderThread = Thread::create("offline renderer", WTFMove(offThreadRendering), ThreadType::Audio);
-    return { };
+    completionHandler(WTF::nullopt);
 }
 
 auto OfflineAudioDestinationNode::offlineRender() -> OfflineRenderResult

Modified: trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.h (269072 => 269073)


--- trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/Modules/webaudio/OfflineAudioDestinationNode.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -50,7 +50,7 @@
 
     // AudioDestinationNode
     void enableInput(const String&) override { }
-    ExceptionOr<void> startRendering() final;
+    void startRendering(CompletionHandler<void(Optional<Exception>&&)>&&) final;
 
     float sampleRate() const final { return m_renderTarget->sampleRate(); }
 

Modified: trunk/Source/WebCore/platform/audio/AudioDestination.h (269072 => 269073)


--- trunk/Source/WebCore/platform/audio/AudioDestination.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/audio/AudioDestination.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -30,6 +30,7 @@
 #define AudioDestination_h
 
 #include <memory>
+#include <wtf/CompletionHandler.h>
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/text/WTFString.h>
 
@@ -50,8 +51,8 @@
 
     virtual ~AudioDestination() = default;
 
-    virtual void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread) = 0;
-    virtual void stop() = 0;
+    virtual void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& = [](bool) { }) = 0;
+    virtual void stop(CompletionHandler<void(bool)>&& = [](bool) { }) = 0;
     virtual bool isPlaying() = 0;
 
     // Sample-rate conversion may happen in AudioDestination to the hardware sample-rate

Modified: trunk/Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.cpp (269072 => 269073)


--- trunk/Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -99,24 +99,30 @@
     return m_renderBus->length();
 }
 
-void AudioDestinationCocoa::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread)
+void AudioDestinationCocoa::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler)
 {
     LOG(Media, "AudioDestinationCocoa::start");
     m_dispatchToRenderThread = WTFMove(dispatchToRenderThread);
-    OSStatus result = m_audioOutputUnitAdaptor.start();
+    auto success = m_audioOutputUnitAdaptor.start() == noErr;
+    if (success)
+        setIsPlaying(true);
 
-    if (!result)
-        setIsPlaying(true);
+    callOnMainThread([completionHandler = WTFMove(completionHandler), success]() mutable {
+        completionHandler(success);
+    });
 }
 
-void AudioDestinationCocoa::stop()
+void AudioDestinationCocoa::stop(CompletionHandler<void(bool)>&& completionHandler)
 {
     LOG(Media, "AudioDestinationCocoa::stop");
-    OSStatus result = m_audioOutputUnitAdaptor.stop();
+    auto success = m_audioOutputUnitAdaptor.stop() == noErr;
     m_dispatchToRenderThread = nullptr;
+    if (success)
+        setIsPlaying(false);
 
-    if (!result)
-        setIsPlaying(false);
+    callOnMainThread([completionHandler = WTFMove(completionHandler), success]() mutable {
+        completionHandler(success);
+    });
 }
 
 void AudioDestinationCocoa::setIsPlaying(bool isPlaying)

Modified: trunk/Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.h (269072 => 269073)


--- trunk/Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/audio/cocoa/AudioDestinationCocoa.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -70,8 +70,8 @@
 private:
     friend Ref<AudioDestination> AudioDestination::create(AudioIOCallback&, const String&, unsigned, unsigned, float);
 
-    void start(Function<void(Function<void()>&&)>&&) override;
-    void stop() override;
+    void start(Function<void(Function<void()>&&)>&&, CompletionHandler<void(bool)>&&) override;
+    void stop(CompletionHandler<void(bool)>&&) override;
 
     // AudioSourceProvider.
     WEBCORE_EXPORT void provideInput(AudioBus*, size_t framesToProcess) final;

Modified: trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp (269072 => 269073)


--- trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -217,33 +217,42 @@
     return TRUE;
 }
 
-void AudioDestinationGStreamer::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread)
+void AudioDestinationGStreamer::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler)
 {
     ASSERT(m_audioSinkAvailable);
-    if (!m_audioSinkAvailable)
-        return;
+    bool success = false;
+    if (m_audioSinkAvailable) {
+        if (dispatchToRenderThread)
+            webkitWebAudioSourceSetDispatchToRenderThreadCallback(WEBKIT_WEB_AUDIO_SRC(m_src.get()), WTFMove(dispatchToRenderThread));
 
-    if (dispatchToRenderThread)
-        webkitWebAudioSourceSetDispatchToRenderThreadCallback(WEBKIT_WEB_AUDIO_SRC(m_src.get()), WTFMove(dispatchToRenderThread));
+        GST_DEBUG("Starting");
+        if (gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+            g_warning("Error: Failed to set pipeline to playing");
+            m_isPlaying = false;
+        } else {
+            m_isPlaying = true;
+            success = true;
+        }
+    }
 
-    GST_DEBUG("Starting");
-    if (gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
-        g_warning("Error: Failed to set pipeline to playing");
-        m_isPlaying = false;
-        return;
-    }
-    m_isPlaying = true;
+    callOnMainThread([completionHandler = WTFMove(completionHandler), success]() mutable {
+        completionHandler(success);
+    });
 }
 
-void AudioDestinationGStreamer::stop()
+void AudioDestinationGStreamer::stop(CompletionHandler<void(bool)>&& completionHandler)
 {
     ASSERT(m_audioSinkAvailable);
-    if (!m_audioSinkAvailable)
-        return;
-
-    GST_DEBUG("Stopping");
-    gst_element_set_state(m_pipeline.get(), GST_STATE_PAUSED);
-    m_isPlaying = false;
+    bool success = false;
+    if (m_audioSinkAvailable) {
+        GST_DEBUG("Stopping");
+        gst_element_set_state(m_pipeline.get(), GST_STATE_PAUSED);
+        m_isPlaying = false;
+        success = true;
+    }
+    callOnMainThread([completionHandler = WTFMove(completionHandler), success]() mutable {
+        completionHandler(success);
+    });
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.h (269072 => 269073)


--- trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -34,8 +34,8 @@
     AudioDestinationGStreamer(AudioIOCallback&, unsigned long numberOfOutputChannels, float sampleRate);
     virtual ~AudioDestinationGStreamer();
 
-    void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread) override;
-    void stop() override;
+    void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&&) override;
+    void stop(CompletionHandler<void(bool)>&&) override;
 
     bool isPlaying() override { return m_isPlaying; }
     float sampleRate() const override { return m_sampleRate; }

Modified: trunk/Source/WebCore/platform/mock/MockAudioDestinationCocoa.cpp (269072 => 269073)


--- trunk/Source/WebCore/platform/mock/MockAudioDestinationCocoa.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/mock/MockAudioDestinationCocoa.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -45,23 +45,27 @@
 
 MockAudioDestinationCocoa::~MockAudioDestinationCocoa() = default;
 
-void MockAudioDestinationCocoa::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread)
+void MockAudioDestinationCocoa::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler)
 {
     m_dispatchToRenderThread = WTFMove(dispatchToRenderThread);
     m_timer.startRepeating(Seconds { m_numberOfFramesToProcess / sampleRate() });
     setIsPlaying(true);
+
+    callOnMainThread([completionHandler = WTFMove(completionHandler)]() mutable {
+        completionHandler(true);
+    });
 }
 
-void MockAudioDestinationCocoa::stop()
+void MockAudioDestinationCocoa::stop(CompletionHandler<void(bool)>&& completionHandler)
 {
     m_timer.stop();
     setIsPlaying(false);
 
-    BinarySemaphore semaphore;
-    m_workQueue->dispatch([&semaphore] {
-        semaphore.signal();
+    m_workQueue->dispatch([completionHandler = WTFMove(completionHandler)]() mutable {
+        callOnMainThread([completionHandler = WTFMove(completionHandler)]() mutable {
+            completionHandler(true);
+        });
     });
-    semaphore.wait();
 }
 
 void MockAudioDestinationCocoa::tick()

Modified: trunk/Source/WebCore/platform/mock/MockAudioDestinationCocoa.h (269072 => 269073)


--- trunk/Source/WebCore/platform/mock/MockAudioDestinationCocoa.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebCore/platform/mock/MockAudioDestinationCocoa.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -47,8 +47,8 @@
     WEBCORE_EXPORT virtual ~MockAudioDestinationCocoa();
 
 private:
-    void start(Function<void(Function<void()>&&)>&&) final;
-    void stop() final;
+    void start(Function<void(Function<void()>&&)>&&, CompletionHandler<void(bool)>&&) final;
+    void stop(CompletionHandler<void(bool)>&&) final;
 
     void tick();
 

Modified: trunk/Source/WebKit/ChangeLog (269072 => 269073)


--- trunk/Source/WebKit/ChangeLog	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebKit/ChangeLog	2020-10-27 21:46:21 UTC (rev 269073)
@@ -1,3 +1,18 @@
+2020-10-27  Chris Dumez  <[email protected]>
+
+        [GPUProcess] Use async IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination
+        https://bugs.webkit.org/show_bug.cgi?id=218251
+
+        Reviewed by Geoffrey Garen.
+
+        Use async IPC for RemoteAudioDestinationManager's StartAudioDestination / StopAudioDestination.
+
+        * GPUProcess/media/RemoteAudioDestinationManager.messages.in:
+        * WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp:
+        (WebKit::RemoteAudioDestinationProxy::start):
+        (WebKit::RemoteAudioDestinationProxy::stop):
+        * WebProcess/GPU/media/RemoteAudioDestinationProxy.h:
+
 2020-10-27  Brian Burg  <[email protected]>
 
         [Cocoa] Introduce _WKInspectorConfiguration for customizing local and remote Web Inspectors

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.messages.in (269072 => 269073)


--- trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.messages.in	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.messages.in	2020-10-27 21:46:21 UTC (rev 269073)
@@ -27,8 +27,8 @@
     CreateAudioDestination(String inputDeviceId, uint32_t numberOfInputChannels, uint32_t numberOfOutputChannels, float sampleRate, float hardwareSampleRate) -> (WebKit::RemoteAudioDestinationIdentifier identifier) Synchronous
     DeleteAudioDestination(WebKit::RemoteAudioDestinationIdentifier identifier) -> () Async
 
-    StartAudioDestination(WebKit::RemoteAudioDestinationIdentifier identifier) -> (bool isPlaying) Synchronous
-    StopAudioDestination(WebKit::RemoteAudioDestinationIdentifier identifier) -> (bool isPlaying) Synchronous
+    StartAudioDestination(WebKit::RemoteAudioDestinationIdentifier identifier) -> (bool isPlaying) Async
+    StopAudioDestination(WebKit::RemoteAudioDestinationIdentifier identifier) -> (bool isPlaying) Async
 #if PLATFORM(COCOA)
     AudioSamplesStorageChanged(WebKit::RemoteAudioDestinationIdentifier identifier, WebKit::SharedMemory::IPCHandle storageHandle, WebCore::CAAudioStreamDescription description, uint64_t numberOfFrames)
 #endif

Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp (269072 => 269073)


--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp	2020-10-27 21:46:21 UTC (rev 269073)
@@ -102,24 +102,22 @@
     m_renderThread->waitForCompletion();
 }
 
-void RemoteAudioDestinationProxy::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread)
+void RemoteAudioDestinationProxy::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler)
 {
-    m_dispatchToRenderThread = WTFMove(dispatchToRenderThread);
-    bool isPlaying;
-    WebProcess::singleton().ensureGPUProcessConnection().connection().sendSync(
-        Messages::RemoteAudioDestinationManager::StartAudioDestination(m_destinationID),
-        Messages::RemoteAudioDestinationManager::StartAudioDestination::Reply(isPlaying), 0);
-    setIsPlaying(isPlaying);
+    WebProcess::singleton().ensureGPUProcessConnection().connection().sendWithAsyncReply(Messages::RemoteAudioDestinationManager::StartAudioDestination(m_destinationID), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), dispatchToRenderThread = WTFMove(dispatchToRenderThread)](bool isPlaying) mutable {
+        m_dispatchToRenderThread = WTFMove(dispatchToRenderThread);
+        setIsPlaying(isPlaying);
+        completionHandler(isPlaying);
+    });
 }
 
-void RemoteAudioDestinationProxy::stop()
+void RemoteAudioDestinationProxy::stop(CompletionHandler<void(bool)>&& completionHandler)
 {
-    bool isPlaying;
-    WebProcess::singleton().ensureGPUProcessConnection().connection().sendSync(
-        Messages::RemoteAudioDestinationManager::StopAudioDestination(m_destinationID),
-        Messages::RemoteAudioDestinationManager::StopAudioDestination::Reply(isPlaying), 0);
-    setIsPlaying(isPlaying);
-    m_dispatchToRenderThread = nullptr;
+    WebProcess::singleton().ensureGPUProcessConnection().connection().sendWithAsyncReply(Messages::RemoteAudioDestinationManager::StopAudioDestination(m_destinationID), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](bool isPlaying) mutable {
+        setIsPlaying(isPlaying);
+        m_dispatchToRenderThread = nullptr;
+        completionHandler(!isPlaying);
+    });
 }
 
 #if PLATFORM(COCOA)

Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.h (269072 => 269073)


--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.h	2020-10-27 21:40:20 UTC (rev 269072)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.h	2020-10-27 21:46:21 UTC (rev 269073)
@@ -75,8 +75,8 @@
 #endif
 
 private:
-    void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread) final;
-    void stop() final;
+    void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&&) final;
+    void stop(CompletionHandler<void(bool)>&&) final;
 
 #if !PLATFORM(COCOA)
     bool isPlaying() final { return false; }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to