Diff
Modified: trunk/Source/WebCore/ChangeLog (270906 => 270907)
--- trunk/Source/WebCore/ChangeLog 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebCore/ChangeLog 2020-12-16 21:07:59 UTC (rev 270907)
@@ -1,3 +1,24 @@
+2020-12-16 Chris Dumez <[email protected]>
+
+ [GPUProcess] Avoid doing an IPC per rendering quantum when using WebAudio
+ https://bugs.webkit.org/show_bug.cgi?id=219818
+
+ Reviewed by Geoff Garen.
+
+ * platform/audio/AudioDestination.h:
+ Make sure AudioDestination always gets destroyed on the main thread.
+
+ * platform/audio/cocoa/CARingBuffer.cpp:
+ (WebCore::CARingBuffer::lastReadFrame const):
+ (WebCore::CARingBufferStorageVector::setLastReadFrame):
+ (WebCore::CARingBufferStorageVector::lastReadFrame const):
+ (WebCore::CARingBuffer::fetchIfHasEnoughData):
+ (WebCore::CARingBuffer::fetch):
+ * platform/audio/cocoa/CARingBuffer.h:
+ Add API to CARingBuffer to query the last frame that the reader attempted to
+ read. This is helpful to make sure the writer keeps up with the reader and
+ does not stray too far ahead.
+
2020-12-16 Víctor Manuel Jáquez Leal <[email protected]>
[Debug][GStreamer] Crash in fast/mediastream/change-tracks-media-stream-being-played.html
Modified: trunk/Source/WebCore/platform/audio/AudioDestination.h (270906 => 270907)
--- trunk/Source/WebCore/platform/audio/AudioDestination.h 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebCore/platform/audio/AudioDestination.h 2020-12-16 21:07:59 UTC (rev 270907)
@@ -43,7 +43,7 @@
// The audio hardware periodically calls the AudioIOCallback render() method asking it to render/output the next render quantum of audio.
// It optionally will pass in local/live audio input when it calls render().
-class AudioDestination : public ThreadSafeRefCounted<AudioDestination> {
+class AudioDestination : public ThreadSafeRefCounted<AudioDestination, WTF::DestructionThread::Main> {
WTF_MAKE_FAST_ALLOCATED;
public:
// Pass in (numberOfInputChannels > 0) if live/local audio input is desired.
Modified: trunk/Source/WebCore/platform/audio/cocoa/CARingBuffer.cpp (270906 => 270907)
--- trunk/Source/WebCore/platform/audio/cocoa/CARingBuffer.cpp 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebCore/platform/audio/cocoa/CARingBuffer.cpp 2020-12-16 21:07:59 UTC (rev 270907)
@@ -181,6 +181,7 @@
timeBounds.m_updateCounter = 0;
}
m_timeBoundsQueuePtr = 0;
+ m_lastReadFrame = 0;
}
CARingBuffer::Error CARingBuffer::store(const AudioBufferList* list, size_t framesToWrite, uint64_t startFrame)
@@ -269,6 +270,11 @@
m_buffers->getCurrentFrameBounds(startFrame, endFrame);
}
+uint64_t CARingBuffer::lastReadFrame() const
+{
+ return m_buffers->lastReadFrame();
+}
+
void CARingBufferStorageVector::getCurrentFrameBounds(uint64_t& startFrame, uint64_t& endFrame)
{
uint32_t curPtr = m_timeBoundsQueuePtr.load();
@@ -279,6 +285,16 @@
endFrame = bounds.m_endFrame;
}
+void CARingBufferStorageVector::setLastReadFrame(uint64_t lastReadFrame)
+{
+ m_lastReadFrame.store(lastReadFrame, std::memory_order_release);
+}
+
+uint64_t CARingBufferStorageVector::lastReadFrame() const
+{
+ return m_lastReadFrame.load(std::memory_order_acquire);
+}
+
void CARingBuffer::clipTimeBounds(uint64_t& startRead, uint64_t& endRead)
{
uint64_t startTime;
@@ -325,6 +341,8 @@
bool CARingBuffer::fetchIfHasEnoughData(AudioBufferList* list, size_t frameCount, uint64_t startFrame, FetchMode mode)
{
+ m_buffers->setLastReadFrame(startFrame + frameCount);
+
// When the RingBuffer is backed by shared memory, getCurrentFrameBounds() makes sure we pull frame bounds from shared memory before fetching.
uint64_t start, end;
getCurrentFrameBounds(start, end);
@@ -337,6 +355,8 @@
void CARingBuffer::fetch(AudioBufferList* list, size_t frameCount, uint64_t startRead, FetchMode mode)
{
+ m_buffers->setLastReadFrame(startRead + frameCount);
+
// When the RingBuffer is backed by shared memory, make sure we pull frame bounds from shared memory before fetching.
updateFrameBounds();
fetchInternal(list, frameCount, startRead, mode);
Modified: trunk/Source/WebCore/platform/audio/cocoa/CARingBuffer.h (270906 => 270907)
--- trunk/Source/WebCore/platform/audio/cocoa/CARingBuffer.h 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebCore/platform/audio/cocoa/CARingBuffer.h 2020-12-16 21:07:59 UTC (rev 270907)
@@ -51,6 +51,8 @@
virtual uint64_t currentStartFrame() const = 0;
virtual uint64_t currentEndFrame() const = 0;
virtual void flush() = 0;
+ virtual void setLastReadFrame(uint64_t) = 0;
+ virtual uint64_t lastReadFrame() const = 0;
};
class CARingBufferStorageVector final : public CARingBufferStorage {
@@ -64,9 +66,11 @@
void* data() final { return m_buffer.data(); }
void getCurrentFrameBounds(uint64_t& startTime, uint64_t& endTime) final;
void setCurrentFrameBounds(uint64_t startFrame, uint64_t endFrame) final;
- uint64_t currentStartFrame() const;
- uint64_t currentEndFrame() const;
+ uint64_t currentStartFrame() const final;
+ uint64_t currentEndFrame() const final;
void flush() final;
+ void setLastReadFrame(uint64_t) final;
+ uint64_t lastReadFrame() const final;
struct TimeBounds {
TimeBounds()
@@ -84,6 +88,7 @@
Vector<TimeBounds> m_timeBoundsQueue;
Lock m_currentFrameBoundsLock;
std::atomic<int32_t> m_timeBoundsQueuePtr { 0 };
+ std::atomic<uint64_t> m_lastReadFrame { 0 };
};
class CARingBuffer {
@@ -113,6 +118,9 @@
WEBCORE_EXPORT void getCurrentFrameBounds(uint64_t& startFrame, uint64_t& endFrame);
+ // Note that this will only return useful values if the reader has read-write access to the storage.
+ WEBCORE_EXPORT uint64_t lastReadFrame() const;
+
uint32_t channelCount() const { return m_channelCount; }
CARingBufferStorage& storage() { return m_buffers; }
Modified: trunk/Source/WebKit/CMakeLists.txt (270906 => 270907)
--- trunk/Source/WebKit/CMakeLists.txt 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/CMakeLists.txt 2020-12-16 21:07:59 UTC (rev 270907)
@@ -226,7 +226,6 @@
WebProcess/GPU/media/MediaPlayerPrivateRemote
WebProcess/GPU/media/MediaSourcePrivateRemote
- WebProcess/GPU/media/RemoteAudioDestinationProxy
WebProcess/GPU/media/RemoteAudioSession
WebProcess/GPU/media/RemoteAudioSourceProviderManager
WebProcess/GPU/media/RemoteCDMInstanceSession
Modified: trunk/Source/WebKit/ChangeLog (270906 => 270907)
--- trunk/Source/WebKit/ChangeLog 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/ChangeLog 2020-12-16 21:07:59 UTC (rev 270907)
@@ -1,3 +1,58 @@
+2020-12-16 Chris Dumez <[email protected]>
+
+ [GPUProcess] Avoid doing an IPC per rendering quantum when using WebAudio
+ https://bugs.webkit.org/show_bug.cgi?id=219818
+
+ Reviewed by Geoff Garen.
+
+ Previously, the GPUProcess was sending an IPC to the WebProcess to request to rendering
+ of each quantum, which was very inefficient and a big regression compared to when we
+ do not use a GPUProcess.
+
+ To address the issue, we now start a rendering timer on the WebProcess side when rendering
+ starts, so that the WebProcess renders each quantum as needed, without needing an IPC from
+ the GPUProcess. Whenever a quantum is rendered, the WebProcess adds it to the RingBuffer
+ it shares with the GPUProcess.
+
+ To make sure that the WebProcess' writer keeps up with the GPUProcess' reader and that it
+ does not stray too far ahead, the writer keeps track of the last frame that the reader
+ attempted to read. It uses this information to try and stay a few rendering quantums ahead
+ of the GPUProcess, to avoid missed frames.
+
+ * CMakeLists.txt:
+ * DerivedSources-input.xcfilelist:
+ * DerivedSources-output.xcfilelist:
+ * DerivedSources.make:
+ * GPUProcess/media/RemoteAudioDestinationManager.cpp:
+ (WebKit::RemoteAudioDestination::audioSamplesStorageChanged):
+ (WebKit::RemoteAudioDestination::RemoteAudioDestination):
+ (WebKit::RemoteAudioDestination::render):
+ * Platform/SharedMemory.h:
+ (WebKit::SharedMemory::protection const):
+ * Shared/Cocoa/SharedRingBufferStorage.cpp:
+ (WebKit::SharedRingBufferStorage::sharedFrameBounds const):
+ (WebKit::SharedRingBufferStorage::setCurrentFrameBounds):
+ (WebKit::SharedRingBufferStorage::setLastReadFrame):
+ (WebKit::SharedRingBufferStorage::lastReadFrame const):
+ * Shared/Cocoa/SharedRingBufferStorage.h:
+ * SourcesCocoa.txt:
+ * WebKit.xcodeproj/project.pbxproj:
+ * WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp:
+ (WebKit::RemoteAudioDestinationProxy::RemoteAudioDestinationProxy):
+ (WebKit::RemoteAudioDestinationProxy::startRenderingThread):
+ (WebKit::RemoteAudioDestinationProxy::stopRenderingThreadIfNecessary):
+ (WebKit::RemoteAudioDestinationProxy::connectToGPUProcess):
+ (WebKit::RemoteAudioDestinationProxy::~RemoteAudioDestinationProxy):
+ (WebKit::RemoteAudioDestinationProxy::start):
+ (WebKit::RemoteAudioDestinationProxy::startRendering):
+ (WebKit::RemoteAudioDestinationProxy::stop):
+ (WebKit::RemoteAudioDestinationProxy::stopRenderingIfNecessary):
+ (WebKit::RemoteAudioDestinationProxy::renderQuantum):
+ (WebKit::RemoteAudioDestinationProxy::storageChanged):
+ * WebProcess/GPU/media/RemoteAudioDestinationProxy.h:
+ (WebKit::RemoteAudioDestinationProxy::stopRenderingIfNecessary):
+ * WebProcess/GPU/media/RemoteAudioDestinationProxy.messages.in: Removed.
+
2020-12-16 Youenn Fablet <[email protected]>
REGRESSION [iOS] Flaky GPU Process crash under -[RTCVideoEncoderH264 destroyCompressionSession]
Modified: trunk/Source/WebKit/DerivedSources-input.xcfilelist (270906 => 270907)
--- trunk/Source/WebKit/DerivedSources-input.xcfilelist 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/DerivedSources-input.xcfilelist 2020-12-16 21:07:59 UTC (rev 270907)
@@ -141,7 +141,6 @@
$(PROJECT_DIR)/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.messages.in
$(PROJECT_DIR)/WebProcess/GPU/media/MediaPlayerPrivateRemote.messages.in
$(PROJECT_DIR)/WebProcess/GPU/media/MediaSourcePrivateRemote.messages.in
-$(PROJECT_DIR)/WebProcess/GPU/media/RemoteAudioDestinationProxy.messages.in
$(PROJECT_DIR)/WebProcess/GPU/media/RemoteAudioSession.messages.in
$(PROJECT_DIR)/WebProcess/GPU/media/RemoteAudioSourceProviderManager.messages.in
$(PROJECT_DIR)/WebProcess/GPU/media/RemoteCDMInstanceSession.messages.in
Modified: trunk/Source/WebKit/DerivedSources-output.xcfilelist (270906 => 270907)
--- trunk/Source/WebKit/DerivedSources-output.xcfilelist 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/DerivedSources-output.xcfilelist 2020-12-16 21:07:59 UTC (rev 270907)
@@ -138,10 +138,6 @@
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationManagerMessages.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationManagerMessages.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationManagerMessagesReplies.h
-$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationProxyMessageReceiver.cpp
-$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationProxyMessages.cpp
-$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationProxyMessages.h
-$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioDestinationProxyMessagesReplies.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioMediaStreamTrackRendererManagerMessageReceiver.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioMediaStreamTrackRendererManagerMessages.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/RemoteAudioMediaStreamTrackRendererManagerMessagesReplies.h
Modified: trunk/Source/WebKit/DerivedSources.make (270906 => 270907)
--- trunk/Source/WebKit/DerivedSources.make 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/DerivedSources.make 2020-12-16 21:07:59 UTC (rev 270907)
@@ -178,7 +178,6 @@
WebProcess/GPU/webrtc/SampleBufferDisplayLayer \
WebProcess/GPU/media/MediaPlayerPrivateRemote \
WebProcess/GPU/media/MediaSourcePrivateRemote \
- WebProcess/GPU/media/RemoteAudioDestinationProxy \
WebProcess/GPU/media/RemoteAudioSession \
WebProcess/GPU/media/RemoteAudioSourceProviderManager \
WebProcess/GPU/media/RemoteCDMInstanceSession \
Modified: trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp (270906 => 270907)
--- trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp 2020-12-16 21:07:59 UTC (rev 270907)
@@ -29,7 +29,6 @@
#if ENABLE(GPU_PROCESS) && ENABLE(WEB_AUDIO)
#include "GPUConnectionToWebProcess.h"
-#include "RemoteAudioDestinationProxyMessages.h"
#include <WebCore/AudioUtilities.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/threads/BinarySemaphore.h>
@@ -79,7 +78,7 @@
return;
}
- auto memory = SharedMemory::map(ipcHandle.handle, SharedMemory::Protection::ReadOnly);
+ auto memory = SharedMemory::map(ipcHandle.handle, SharedMemory::Protection::ReadWrite);
storage().setStorage(WTFMove(memory));
storage().setReadOnly(true);
m_ringBuffer->allocate(description, numberOfFrames);
@@ -114,9 +113,8 @@
bool isPlaying() const { return m_isPlaying; }
private:
- RemoteAudioDestination(GPUConnectionToWebProcess& connection, RemoteAudioDestinationIdentifier identifier, const String& inputDeviceId, uint32_t numberOfInputChannels, uint32_t numberOfOutputChannels, float sampleRate, float hardwareSampleRate)
- : m_connection(connection)
- , m_id(identifier)
+ RemoteAudioDestination(GPUConnectionToWebProcess&, RemoteAudioDestinationIdentifier identifier, const String& inputDeviceId, uint32_t numberOfInputChannels, uint32_t numberOfOutputChannels, float sampleRate, float hardwareSampleRate)
+ : m_id(identifier)
#if PLATFORM(COCOA)
, m_audioOutputUnitAdaptor(*this)
, m_ringBuffer(makeUniqueRef<WebCore::CARingBuffer>(makeUniqueRef<SharedRingBufferStorage>()))
@@ -147,13 +145,10 @@
status = noErr;
}
- m_connection.connection().send(Messages::RemoteAudioDestinationProxy::RequestBuffer(sampleTime, hostTime, numberOfFrames), m_id.toUInt64());
-
return status;
}
#endif
- GPUConnectionToWebProcess& m_connection;
RemoteAudioDestinationIdentifier m_id;
RefPtr<RemoteAudioDestination> m_protectThisDuringGracefulShutdown;
Modified: trunk/Source/WebKit/Platform/SharedMemory.h (270906 => 270907)
--- trunk/Source/WebKit/Platform/SharedMemory.h 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/Platform/SharedMemory.h 2020-12-16 21:07:59 UTC (rev 270907)
@@ -142,6 +142,10 @@
HANDLE handle() const { return m_handle; }
#endif
+#if PLATFORM(COCOA)
+ Protection protection() const { return m_protection; }
+#endif
+
// Return the system page size in bytes.
static unsigned systemPageSize();
Modified: trunk/Source/WebKit/Shared/Cocoa/SharedRingBufferStorage.cpp (270906 => 270907)
--- trunk/Source/WebKit/Shared/Cocoa/SharedRingBufferStorage.cpp 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/Shared/Cocoa/SharedRingBufferStorage.cpp 2020-12-16 21:07:59 UTC (rev 270907)
@@ -59,7 +59,7 @@
setStorage(nullptr);
}
-auto SharedRingBufferStorage::sharedFrameBounds() -> FrameBounds*
+auto SharedRingBufferStorage::sharedFrameBounds() const -> FrameBounds*
{
return m_storage ? reinterpret_cast<FrameBounds*>(m_storage->data()) : nullptr;
}
@@ -106,6 +106,20 @@
m_endFrame = pair.second;
}
+void SharedRingBufferStorage::setLastReadFrame(uint64_t lastReadFrame)
+{
+ if (!m_storage || m_storage->protection() != SharedMemory::Protection::ReadWrite)
+ return;
+
+ sharedFrameBounds()->lastReadFrame.store(lastReadFrame, std::memory_order_release);
+}
+
+uint64_t SharedRingBufferStorage::lastReadFrame() const
+{
+ auto* sharedBounds = sharedFrameBounds();
+ return sharedBounds ? sharedBounds->lastReadFrame.load(std::memory_order_acquire) : 0;
+}
+
void SharedRingBufferStorage::flush()
{
m_startFrame = m_endFrame = 0;
Modified: trunk/Source/WebKit/Shared/Cocoa/SharedRingBufferStorage.h (270906 => 270907)
--- trunk/Source/WebKit/Shared/Cocoa/SharedRingBufferStorage.h 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/Shared/Cocoa/SharedRingBufferStorage.h 2020-12-16 21:07:59 UTC (rev 270907)
@@ -59,6 +59,8 @@
uint64_t currentEndFrame() const final { return m_endFrame; }
void updateFrameBounds() final;
void flush() final;
+ void setLastReadFrame(uint64_t) final;
+ uint64_t lastReadFrame() const final;
private:
static constexpr unsigned boundsBufferSize { 32 };
@@ -65,9 +67,10 @@
struct FrameBounds {
std::pair<uint64_t, uint64_t> boundsBuffer[boundsBufferSize];
Atomic<unsigned> boundsBufferIndex { 0 };
+ Atomic<uint64_t> lastReadFrame { 0 };
};
- FrameBounds* sharedFrameBounds();
+ FrameBounds* sharedFrameBounds() const;
Function<void(SharedMemory*)> m_storageChangedHandler;
RefPtr<SharedMemory> m_storage;
Modified: trunk/Source/WebKit/SourcesCocoa.txt (270906 => 270907)
--- trunk/Source/WebKit/SourcesCocoa.txt 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/SourcesCocoa.txt 2020-12-16 21:07:59 UTC (rev 270907)
@@ -690,7 +690,6 @@
MessageArgumentDescriptions.cpp @no-unify
MessageNames.cpp
RemoteAudioDestinationManagerMessageReceiver.cpp
-RemoteAudioDestinationProxyMessageReceiver.cpp
RemoteAudioSessionMessageReceiver.cpp
RemoteAudioSessionProxyMessageReceiver.cpp
RemoteAudioMediaStreamTrackRendererManagerMessageReceiver.cpp
Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (270906 => 270907)
--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2020-12-16 21:07:59 UTC (rev 270907)
@@ -4879,7 +4879,6 @@
9B5BEC252400F4A90070C6EF /* WebMediaStrategy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebMediaStrategy.cpp; sourceTree = "<group>"; };
9B5BEC28240101580070C6EF /* RemoteAudioDestinationProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteAudioDestinationProxy.h; sourceTree = "<group>"; };
9B5BEC29240101580070C6EF /* RemoteAudioDestinationProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteAudioDestinationProxy.cpp; sourceTree = "<group>"; };
- 9B5BEC2E2401018C0070C6EF /* RemoteAudioDestinationProxy.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = RemoteAudioDestinationProxy.messages.in; sourceTree = "<group>"; };
9BC59D6C1EFCCCB6001E8D09 /* CallbackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallbackID.h; sourceTree = "<group>"; };
9BC59D6D1EFCDC6D001E8D09 /* OptionalCallbackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionalCallbackID.h; sourceTree = "<group>"; };
9BD8AB4925820E52005386F8 /* FontReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontReference.h; sourceTree = "<group>"; };
@@ -5939,7 +5938,6 @@
1DF29018257F202F003C28AF /* MediaSourcePrivateRemote.messages.in */,
9B5BEC29240101580070C6EF /* RemoteAudioDestinationProxy.cpp */,
9B5BEC28240101580070C6EF /* RemoteAudioDestinationProxy.h */,
- 9B5BEC2E2401018C0070C6EF /* RemoteAudioDestinationProxy.messages.in */,
CDBB49F5240D8AC60017C292 /* RemoteAudioSession.cpp */,
CDBB49F4240D8AC60017C292 /* RemoteAudioSession.h */,
CDD5356F240DD34300F7B8C4 /* RemoteAudioSession.messages.in */,
Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp (270906 => 270907)
--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.cpp 2020-12-16 21:07:59 UTC (rev 270907)
@@ -31,13 +31,16 @@
#include "GPUConnectionToWebProcess.h"
#include "Logging.h"
#include "RemoteAudioDestinationManagerMessages.h"
-#include "RemoteAudioDestinationProxyMessages.h"
#include "WebProcess.h"
#include <WebCore/AudioBus.h>
+#include <WebCore/AudioUtilities.h>
+#include <wtf/RunLoop.h>
+#include <wtf/threads/BinarySemaphore.h>
#if PLATFORM(COCOA)
#include <WebCore/CARingBuffer.h>
#include <WebCore/WebAudioBufferList.h>
+#include <mach/mach_time.h>
#endif
namespace WebKit {
@@ -44,6 +47,7 @@
// Allocate a ring buffer large enough to contain 2 seconds of audio.
constexpr size_t ringBufferSizeInSecond = 2;
+constexpr uint64_t framesAheadOfReader = 2 * WebCore::AudioUtilities::renderQuantumSize;
using AudioDestination = WebCore::AudioDestination;
using AudioIOCallback = WebCore::AudioIOCallback;
@@ -66,15 +70,35 @@
, m_inputDeviceId(inputDeviceId)
, m_numberOfInputChannels(numberOfInputChannels)
{
- auto offThreadRendering = [this, protectedThis = makeRef(*this)]() mutable {
- while (!m_threadTaskQueue.isKilled()) {
- if (auto task = m_threadTaskQueue.waitForMessage())
- task();
- }
+ connectToGPUProcess();
+}
+
+void RemoteAudioDestinationProxy::startRenderingThread()
+{
+ ASSERT(!m_renderThread);
+
+ BinarySemaphore semaphore;
+ auto offThreadRendering = [this, protectedThis = makeRef(*this), &semaphore]() mutable {
+ m_dispatchToRenderThread = [runLoop = makeRef(RunLoop::current())](Function<void()>&& task) {
+ runLoop->dispatch(WTFMove(task));
+ };
+ semaphore.signal();
+ RunLoop::run();
};
m_renderThread = Thread::create("RemoteAudioDestinationProxy render thread", WTFMove(offThreadRendering), ThreadType::Audio, Thread::QOS::UserInteractive);
+ m_renderThread->detach();
+ semaphore.wait();
+}
- connectToGPUProcess();
+void RemoteAudioDestinationProxy::stopRenderingThreadIfNecessary()
+{
+ if (!m_renderThread)
+ return;
+
+ m_dispatchToRenderThread([] {
+ RunLoop::current().stop();
+ });
+ m_renderThread = nullptr;
}
void RemoteAudioDestinationProxy::connectToGPUProcess()
@@ -93,7 +117,6 @@
return;
}
- connection.connection().addThreadMessageReceiver(Messages::RemoteAudioDestinationProxy::messageReceiverName(), this, destinationID.toUInt64());
m_destinationID = destinationID;
#if PLATFORM(COCOA)
@@ -108,7 +131,6 @@
RemoteAudioDestinationProxy::~RemoteAudioDestinationProxy()
{
auto& connection = WebProcess::singleton().ensureGPUProcessConnection();
- connection.connection().removeThreadMessageReceiver(Messages::RemoteAudioDestinationProxy::messageReceiverName(), m_destinationID.toUInt64());
connection.connection().sendWithAsyncReply(
Messages::RemoteAudioDestinationManager::DeleteAudioDestination(m_destinationID), [] {
@@ -115,66 +137,83 @@
// Can't remove this from proxyMap() here because the object would have been already deleted.
});
- m_threadTaskQueue.kill();
- m_renderThread->waitForCompletion();
+ RELEASE_ASSERT(!m_renderThread);
+ RELEASE_ASSERT(!m_dispatchToRenderThread);
}
void RemoteAudioDestinationProxy::start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&& completionHandler)
{
WebProcess::singleton().ensureGPUProcessConnection().connection().sendWithAsyncReply(Messages::RemoteAudioDestinationManager::StartAudioDestination(m_destinationID), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), dispatchToRenderThread = WTFMove(dispatchToRenderThread)](bool isPlaying) mutable {
+ if (m_dispatchToRenderThread)
+ return completionHandler(true); // Already rendering. Can happen when start() gets called multiple times without stopping in between.
+
m_dispatchToRenderThread = WTFMove(dispatchToRenderThread);
setIsPlaying(isPlaying);
- completionHandler(isPlaying);
+ if (!isPlaying)
+ return completionHandler(false);
+ startRendering([completionHandler = WTFMove(completionHandler)]() mutable {
+ completionHandler(true);
+ });
});
}
+void RemoteAudioDestinationProxy::startRendering(CompletionHandler<void()>&& completionHandler)
+{
+ ASSERT(isMainThread());
+
+ if (!m_dispatchToRenderThread)
+ startRenderingThread();
+
+ m_dispatchToRenderThread([this, protectedThis = makeRef(*this), sampleRate = hardwareSampleRate(), completionHandler = WTFMove(completionHandler)]() mutable {
+ m_sampleRate = sampleRate;
+ renderQuantum();
+ // To avoid the need for an IPC message from the GPUProcess for each rendering quantum, we use a timer to trigger the rendering of each quantum.
+ m_renderingTimer = makeUnique<RunLoop::Timer<RemoteAudioDestinationProxy>>(RunLoop::current(), this, &RemoteAudioDestinationProxy::renderQuantum);
+ m_renderingTimer->startRepeating(Seconds { WebCore::AudioUtilities::renderQuantumSize / static_cast<double>(sampleRate) });
+
+ RunLoop::main().dispatch(WTFMove(completionHandler));
+ });
+}
+
void RemoteAudioDestinationProxy::stop(CompletionHandler<void(bool)>&& completionHandler)
{
WebProcess::singleton().ensureGPUProcessConnection().connection().sendWithAsyncReply(Messages::RemoteAudioDestinationManager::StopAudioDestination(m_destinationID), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](bool isPlaying) mutable {
setIsPlaying(isPlaying);
- auto dispatchToRenderThread = std::exchange(m_dispatchToRenderThread, nullptr);
- auto callCompletionHandler = [completionHandler = WTFMove(completionHandler), isPlaying]() mutable {
+ stopRenderingIfNecessary([completionHandler = WTFMove(completionHandler), isPlaying]() mutable {
completionHandler(!isPlaying);
- };
+ });
+ });
+}
- if (dispatchToRenderThread) {
- // Do a round-trip to the worklet thread to make sure we call the completion handler after
- // the last rendering quantum has been processed by the worklet thread.
- dispatchToRenderThread([callCompletionHandler = WTFMove(callCompletionHandler)]() mutable {
- callOnMainThread(WTFMove(callCompletionHandler));
- });
- } else
- callCompletionHandler();
+void RemoteAudioDestinationProxy::stopRenderingIfNecessary(CompletionHandler<void()>&& completionHandler)
+{
+ ASSERT(isMainThread());
+ if (!m_dispatchToRenderThread)
+ return completionHandler();
+
+ m_dispatchToRenderThread([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
+ m_renderingTimer = nullptr;
+ RunLoop::main().dispatch(WTFMove(completionHandler));
});
+ stopRenderingThreadIfNecessary();
+ m_dispatchToRenderThread = nullptr;
}
-#if PLATFORM(COCOA)
-void RemoteAudioDestinationProxy::requestBuffer(double sampleTime, uint64_t hostTime, uint64_t framesToRender)
+void RemoteAudioDestinationProxy::renderQuantum()
{
ASSERT(!isMainThread());
- if (!hasEnoughFrames(framesToRender))
- return;
+#if PLATFORM(COCOA)
+ m_audioBufferList->setSampleCount(WebCore::AudioUtilities::renderQuantumSize);
- auto startFrame = m_currentFrame;
- m_audioBufferList->setSampleCount(framesToRender);
-
- AudioDestinationCocoa::render(sampleTime, hostTime, framesToRender, m_audioBufferList->list());
-
- m_currentFrame += framesToRender;
-
- m_ringBuffer->store(m_audioBufferList->list(), framesToRender, startFrame);
-}
+ // Try to stay a few rendering quantums ahead of the reader.
+ auto lastReadFrame = m_ringBuffer->lastReadFrame();
+ while (lastReadFrame >= m_currentFrame || (m_currentFrame - lastReadFrame) < framesAheadOfReader) {
+ AudioDestinationCocoa::render(m_currentFrame / static_cast<double>(m_sampleRate), mach_absolute_time(), WebCore::AudioUtilities::renderQuantumSize, m_audioBufferList->list());
+ m_ringBuffer->store(m_audioBufferList->list(), WebCore::AudioUtilities::renderQuantumSize, m_currentFrame);
+ m_currentFrame += WebCore::AudioUtilities::renderQuantumSize;
+ }
#endif
-
-// IPC::Connection::ThreadMessageReceiver
-void RemoteAudioDestinationProxy::dispatchToThread(Function<void()>&& task)
-{
- if (m_dispatchToRenderThread) {
- m_dispatchToRenderThread(WTFMove(task));
- return;
- }
- m_threadTaskQueue.append(WTFMove(task));
}
#if PLATFORM(COCOA)
@@ -182,7 +221,7 @@
{
SharedMemory::Handle handle;
if (storage)
- storage->createHandle(handle, SharedMemory::Protection::ReadOnly);
+ storage->createHandle(handle, SharedMemory::Protection::ReadWrite);
// FIXME: Send the actual data size with IPCHandle.
#if OS(DARWIN) || OS(WINDOWS)
Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.h (270906 => 270907)
--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.h 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.h 2020-12-16 21:07:59 UTC (rev 270907)
@@ -57,8 +57,7 @@
#else
: public WebCore::AudioDestination
#endif
- , public GPUProcessConnection::Client
- , public IPC::Connection::ThreadMessageReceiver {
+ , public GPUProcessConnection::Client {
WTF_MAKE_NONCOPYABLE(RemoteAudioDestinationProxy);
public:
using AudioIOCallback = WebCore::AudioIOCallback;
@@ -70,16 +69,16 @@
RemoteAudioDestinationProxy(AudioIOCallback&, const String& inputDeviceId, unsigned numberOfInputChannels, unsigned numberOfOutputChannels, float sampleRate);
~RemoteAudioDestinationProxy();
- void didReceiveMessageFromGPUProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
-
-#if PLATFORM(COCOA)
- void requestBuffer(double sampleTime, uint64_t hostTime, uint64_t numberOfFrames);
-#endif
-
private:
void start(Function<void(Function<void()>&&)>&& dispatchToRenderThread, CompletionHandler<void(bool)>&&) final;
void stop(CompletionHandler<void(bool)>&&) final;
+ void startRenderingThread();
+ void stopRenderingThreadIfNecessary();
+ void startRendering(CompletionHandler<void()>&&);
+ void stopRenderingIfNecessary(CompletionHandler<void()>&& = [] { });
+ void renderQuantum();
+
void connectToGPUProcess();
// GPUProcessConnection::Client.
@@ -97,14 +96,6 @@
void storageChanged(SharedMemory*);
#endif
- // IPC::MessageReceiver
- void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
-
- // IPC::Connection::ThreadMessageReceiver
- void dispatchToThread(Function<void()>&&) final;
- void refMessageReceiver() final { WebCore::AudioDestination::ref(); }
- void derefMessageReceiver() final { WebCore::AudioDestination::deref(); }
-
RemoteAudioDestinationIdentifier m_destinationID;
#if PLATFORM(COCOA)
@@ -121,7 +112,9 @@
Function<void(Function<void()>&&)> m_dispatchToRenderThread;
RefPtr<Thread> m_renderThread;
- CrossThreadQueue<Function<void()>> m_threadTaskQueue;
+
+ std::unique_ptr<RunLoop::Timer<RemoteAudioDestinationProxy>> m_renderingTimer;
+ float m_sampleRate { 0 };
};
} // namespace WebKit
Deleted: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.messages.in (270906 => 270907)
--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.messages.in 2020-12-16 20:57:12 UTC (rev 270906)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioDestinationProxy.messages.in 2020-12-16 21:07:59 UTC (rev 270907)
@@ -1,32 +0,0 @@
-# Copyright (C) 2020 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.
-
-#if ENABLE(GPU_PROCESS) && ENABLE(WEB_AUDIO)
-
-messages -> RemoteAudioDestinationProxy NotRefCounted {
-#if PLATFORM(COCOA)
- RequestBuffer(double sampleTime, uint64_t hostTime, uint64_t numberOfFrames)
-#endif
-}
-
-#endif