Introduce a mock implementation of CoreAudioSharedUnit
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Nov 2019 00:50:51 +0000 (00:50 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Nov 2019 00:50:51 +0000 (00:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204290

Reviewed by Eric Carlson.

Introduce BaseAudioSharedUnit as a base class to CoreAudioSharedUnit.
Make CoreAudioCaptureSource use either CoreAudioSharedUnit singleton or an override.
Implement a MockAudioSharedUnit and use the override to implement mock audio capture sources.

Remove some code from CoreAudioCaptureSource related to reference data, which is not used currently.

Covered by existing tests.

* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
* platform/mediastream/mac/BaseAudioSharedUnit.cpp: Added.
(WebCore::BaseAudioSharedUnit::addClient):
(WebCore::BaseAudioSharedUnit::removeClient):
(WebCore::BaseAudioSharedUnit::forEachClient const):
(WebCore::BaseAudioSharedUnit::clearClients):
(WebCore::BaseAudioSharedUnit::startProducingData):
(WebCore::BaseAudioSharedUnit::resume):
(WebCore::BaseAudioSharedUnit::prepareForNewCapture):
(WebCore::BaseAudioSharedUnit::captureFailed):
(WebCore::BaseAudioSharedUnit::stopProducingData):
(WebCore::BaseAudioSharedUnit::suspend):
(WebCore::BaseAudioSharedUnit::audioSamplesAvailable):
* platform/mediastream/mac/BaseAudioSharedUnit.h: Added.
(WebCore::BaseAudioSharedUnit::delaySamples):
(WebCore::BaseAudioSharedUnit::isSuspended const):
(WebCore::BaseAudioSharedUnit::volume const):
(WebCore::BaseAudioSharedUnit::sampleRate const):
(WebCore::BaseAudioSharedUnit::enableEchoCancellation const):
(WebCore::BaseAudioSharedUnit::setVolume):
(WebCore::BaseAudioSharedUnit::setSampleRate):
(WebCore::BaseAudioSharedUnit::setEnableEchoCancellation):
(WebCore::BaseAudioSharedUnit::sampleRateCapacities const):
(WebCore::BaseAudioSharedUnit::hasClients const):
(WebCore::BaseAudioSharedUnit::setSuspended):
* platform/mediastream/mac/CoreAudioCaptureSource.cpp:
(WebCore::CoreAudioSharedUnit::unit):
(WebCore::CoreAudioSharedUnit::CoreAudioSharedUnit):
(WebCore::CoreAudioSharedUnit::setupAudioUnit):
(WebCore::CoreAudioSharedUnit::configureMicrophoneProc):
(WebCore::CoreAudioSharedUnit::configureSpeakerProc):
(WebCore::CoreAudioSharedUnit::provideSpeakerData):
(WebCore::CoreAudioSharedUnit::processMicrophoneSamples):
(WebCore::initializeCoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::create):
(WebCore::CoreAudioCaptureSource::createForTesting):
(WebCore::CoreAudioCaptureSource::unit):
(WebCore::CoreAudioCaptureSourceFactory::devicesChanged):
(WebCore::CoreAudioCaptureSource::CoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::initializeToStartProducingData):
(WebCore::CoreAudioCaptureSource::~CoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::startProducingData):
(WebCore::CoreAudioCaptureSource::stopProducingData):
(WebCore::CoreAudioCaptureSource::capabilities):
(WebCore::CoreAudioCaptureSource::settingsDidChange):
(WebCore::CoreAudioCaptureSource::scheduleReconfiguration):
(WebCore::CoreAudioCaptureSource::beginInterruption):
(WebCore::CoreAudioCaptureSource::endInterruption):
(WebCore::CoreAudioCaptureSource::interrupted const):
(WebCore::CoreAudioCaptureSource::delaySamples):
* platform/mediastream/mac/CoreAudioCaptureSource.h:
* platform/mediastream/mac/MockAudioSharedUnit.h: Added.
* platform/mediastream/mac/MockAudioSharedUnit.mm: Added.
(WebCore::MockRealtimeAudioSource::create):
(WebCore::MockAudioSharedUnit::singleton):
(WebCore::MockAudioSharedUnit::MockAudioSharedUnit):
(WebCore::MockAudioSharedUnit::hasAudioUnit const):
(WebCore::MockAudioSharedUnit::setCaptureDevice):
(WebCore::MockAudioSharedUnit::reconfigureAudioUnit):
(WebCore::MockAudioSharedUnit::cleanupAudioUnit):
(WebCore::MockAudioSharedUnit::startInternal):
(WebCore::MockAudioSharedUnit::stopInternal):
(WebCore::MockAudioSharedUnit::isProducingData const):
(WebCore::MockAudioSharedUnit::tick):
(WebCore::MockAudioSharedUnit::delaySamples):
(WebCore::MockAudioSharedUnit::reconfigure):
(WebCore::MockAudioSharedUnit::emitSampleBuffers):
(WebCore::MockAudioSharedUnit::render):
* platform/mediastream/mac/MockRealtimeAudioSourceMac.h: Removed.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252660 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/SourcesCocoa.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp [new file with mode: 0644]
Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.h [new file with mode: 0644]
Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp
Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h
Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.h [new file with mode: 0644]
Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.mm [moved from Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm with 60% similarity]
Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h [deleted file]

index f7801cb..cd501b2 100644 (file)
@@ -1,3 +1,89 @@
+2019-11-19  Youenn Fablet  <youenn@apple.com>
+
+        Introduce a mock implementation of CoreAudioSharedUnit
+        https://bugs.webkit.org/show_bug.cgi?id=204290
+
+        Reviewed by Eric Carlson.
+
+        Introduce BaseAudioSharedUnit as a base class to CoreAudioSharedUnit.
+        Make CoreAudioCaptureSource use either CoreAudioSharedUnit singleton or an override.
+        Implement a MockAudioSharedUnit and use the override to implement mock audio capture sources.
+
+        Remove some code from CoreAudioCaptureSource related to reference data, which is not used currently.
+
+        Covered by existing tests.
+
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/mediastream/mac/BaseAudioSharedUnit.cpp: Added.
+        (WebCore::BaseAudioSharedUnit::addClient):
+        (WebCore::BaseAudioSharedUnit::removeClient):
+        (WebCore::BaseAudioSharedUnit::forEachClient const):
+        (WebCore::BaseAudioSharedUnit::clearClients):
+        (WebCore::BaseAudioSharedUnit::startProducingData):
+        (WebCore::BaseAudioSharedUnit::resume):
+        (WebCore::BaseAudioSharedUnit::prepareForNewCapture):
+        (WebCore::BaseAudioSharedUnit::captureFailed):
+        (WebCore::BaseAudioSharedUnit::stopProducingData):
+        (WebCore::BaseAudioSharedUnit::suspend):
+        (WebCore::BaseAudioSharedUnit::audioSamplesAvailable):
+        * platform/mediastream/mac/BaseAudioSharedUnit.h: Added.
+        (WebCore::BaseAudioSharedUnit::delaySamples):
+        (WebCore::BaseAudioSharedUnit::isSuspended const):
+        (WebCore::BaseAudioSharedUnit::volume const):
+        (WebCore::BaseAudioSharedUnit::sampleRate const):
+        (WebCore::BaseAudioSharedUnit::enableEchoCancellation const):
+        (WebCore::BaseAudioSharedUnit::setVolume):
+        (WebCore::BaseAudioSharedUnit::setSampleRate):
+        (WebCore::BaseAudioSharedUnit::setEnableEchoCancellation):
+        (WebCore::BaseAudioSharedUnit::sampleRateCapacities const):
+        (WebCore::BaseAudioSharedUnit::hasClients const):
+        (WebCore::BaseAudioSharedUnit::setSuspended):
+        * platform/mediastream/mac/CoreAudioCaptureSource.cpp:
+        (WebCore::CoreAudioSharedUnit::unit):
+        (WebCore::CoreAudioSharedUnit::CoreAudioSharedUnit):
+        (WebCore::CoreAudioSharedUnit::setupAudioUnit):
+        (WebCore::CoreAudioSharedUnit::configureMicrophoneProc):
+        (WebCore::CoreAudioSharedUnit::configureSpeakerProc):
+        (WebCore::CoreAudioSharedUnit::provideSpeakerData):
+        (WebCore::CoreAudioSharedUnit::processMicrophoneSamples):
+        (WebCore::initializeCoreAudioCaptureSource):
+        (WebCore::CoreAudioCaptureSource::create):
+        (WebCore::CoreAudioCaptureSource::createForTesting):
+        (WebCore::CoreAudioCaptureSource::unit):
+        (WebCore::CoreAudioCaptureSourceFactory::devicesChanged):
+        (WebCore::CoreAudioCaptureSource::CoreAudioCaptureSource):
+        (WebCore::CoreAudioCaptureSource::initializeToStartProducingData):
+        (WebCore::CoreAudioCaptureSource::~CoreAudioCaptureSource):
+        (WebCore::CoreAudioCaptureSource::startProducingData):
+        (WebCore::CoreAudioCaptureSource::stopProducingData):
+        (WebCore::CoreAudioCaptureSource::capabilities):
+        (WebCore::CoreAudioCaptureSource::settingsDidChange):
+        (WebCore::CoreAudioCaptureSource::scheduleReconfiguration):
+        (WebCore::CoreAudioCaptureSource::beginInterruption):
+        (WebCore::CoreAudioCaptureSource::endInterruption):
+        (WebCore::CoreAudioCaptureSource::interrupted const):
+        (WebCore::CoreAudioCaptureSource::delaySamples):
+        * platform/mediastream/mac/CoreAudioCaptureSource.h:
+        * platform/mediastream/mac/MockAudioSharedUnit.h: Added.
+        * platform/mediastream/mac/MockAudioSharedUnit.mm: Added.
+        (WebCore::MockRealtimeAudioSource::create):
+        (WebCore::MockAudioSharedUnit::singleton):
+        (WebCore::MockAudioSharedUnit::MockAudioSharedUnit):
+        (WebCore::MockAudioSharedUnit::hasAudioUnit const):
+        (WebCore::MockAudioSharedUnit::setCaptureDevice):
+        (WebCore::MockAudioSharedUnit::reconfigureAudioUnit):
+        (WebCore::MockAudioSharedUnit::cleanupAudioUnit):
+        (WebCore::MockAudioSharedUnit::startInternal):
+        (WebCore::MockAudioSharedUnit::stopInternal):
+        (WebCore::MockAudioSharedUnit::isProducingData const):
+        (WebCore::MockAudioSharedUnit::tick):
+        (WebCore::MockAudioSharedUnit::delaySamples):
+        (WebCore::MockAudioSharedUnit::reconfigure):
+        (WebCore::MockAudioSharedUnit::emitSampleBuffers):
+        (WebCore::MockAudioSharedUnit::render):
+        * platform/mediastream/mac/MockRealtimeAudioSourceMac.h: Removed.
+
 2019-11-19  Ross Kirsling  <ross.kirsling@sony.com>
 
         Unreviewed non-unified build fixes.
index f1c3346..98c3eb1 100644 (file)
@@ -547,6 +547,7 @@ rendering/RenderThemeIOS.mm
 rendering/RenderThemeMac.mm
 rendering/TextAutoSizing.cpp
 
+platform/mediastream/mac/BaseAudioSharedUnit.cpp
 platform/mediastream/mac/CoreAudioCaptureDevice.cpp
 platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp
 platform/mediastream/mac/CoreAudioCaptureSource.cpp
@@ -563,7 +564,7 @@ platform/mediastream/mac/WindowDisplayCaptureSourceMac.mm
 
 platform/audio/mac/AudioSampleDataSource.mm
 
-platform/mediastream/mac/MockRealtimeAudioSourceMac.mm
+platform/mediastream/mac/MockAudioSharedUnit.mm
 platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm
 
 platform/mediastream/libwebrtc/LibWebRTCProviderCocoa.cpp
index 840c2b0..96a156b 100644 (file)
                073B87631E43859D0071C0EC /* AudioSampleBufferList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioSampleBufferList.h; sourceTree = "<group>"; };
                073B87641E43859D0071C0EC /* AudioSampleDataSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioSampleDataSource.mm; sourceTree = "<group>"; };
                073B87651E43859D0071C0EC /* AudioSampleDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioSampleDataSource.h; sourceTree = "<group>"; };
-               0744ECEB1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeAudioSourceMac.h; sourceTree = "<group>"; };
-               0744ECEC1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MockRealtimeAudioSourceMac.mm; sourceTree = "<group>"; };
+               0744ECEB1E0C4AE5000D0944 /* MockAudioSharedUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockAudioSharedUnit.h; sourceTree = "<group>"; };
+               0744ECEC1E0C4AE5000D0944 /* MockAudioSharedUnit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MockAudioSharedUnit.mm; sourceTree = "<group>"; };
                0746D30A2146EA37003DDF84 /* ImageTransferSessionVT.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ImageTransferSessionVT.mm; sourceTree = "<group>"; };
                0746D30C2146EA38003DDF84 /* ImageTransferSessionVT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageTransferSessionVT.h; sourceTree = "<group>"; };
                074E82B818A69F0E007EF54C /* PlatformTimeRanges.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformTimeRanges.cpp; sourceTree = "<group>"; };
                417612AE1E3A993B00C3D81D /* LibWebRTCPeerConnectionBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCPeerConnectionBackend.h; path = libwebrtc/LibWebRTCPeerConnectionBackend.h; sourceTree = "<group>"; };
                4176900322FCD8F200B1576D /* MediaSourceRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSourceRegistry.h; sourceTree = "<group>"; };
                4176900422FCD8F200B1576D /* MediaSourceRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaSourceRegistry.cpp; sourceTree = "<group>"; };
+               4177F51C2382544000C04486 /* BaseAudioSharedUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BaseAudioSharedUnit.cpp; sourceTree = "<group>"; };
+               4177F51E2382545E00C04486 /* BaseAudioSharedUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseAudioSharedUnit.h; sourceTree = "<group>"; };
                417DA4CE13734326007C57FB /* Internals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Internals.h; sourceTree = "<group>"; };
                417DA4CF13734326007C57FB /* Internals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Internals.cpp; sourceTree = "<group>"; };
                417DA6D013734E02007C57FB /* libWebCoreTestSupport.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libWebCoreTestSupport.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                                070363DB181A1CDC00C074A5 /* AVCaptureDeviceManager.mm */,
                                070363DE181A1CDC00C074A5 /* AVVideoCaptureSource.h */,
                                070363DF181A1CDC00C074A5 /* AVVideoCaptureSource.mm */,
+                               4177F51C2382544000C04486 /* BaseAudioSharedUnit.cpp */,
+                               4177F51E2382545E00C04486 /* BaseAudioSharedUnit.h */,
                                3F8020311E9E381D00DEC61D /* CoreAudioCaptureDevice.cpp */,
                                3F8020321E9E381D00DEC61D /* CoreAudioCaptureDevice.h */,
                                3F8020331E9E381D00DEC61D /* CoreAudioCaptureDeviceManager.cpp */,
                                07A6D8491FEB700C006441DE /* DisplayCaptureManagerCocoa.h */,
                                07A6D8471FEB700B006441DE /* DisplayCaptureSourceCocoa.cpp */,
                                07A6D84A1FEB700D006441DE /* DisplayCaptureSourceCocoa.h */,
-                               0744ECEB1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.h */,
-                               0744ECEC1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.mm */,
+                               0744ECEB1E0C4AE5000D0944 /* MockAudioSharedUnit.h */,
+                               0744ECEC1E0C4AE5000D0944 /* MockAudioSharedUnit.mm */,
                                07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */,
                                07EE76EE1BEA619800F89133 /* MockRealtimeVideoSourceMac.mm */,
                                41103AAA1E39790A00769F14 /* RealtimeIncomingAudioSourceCocoa.cpp */,
diff --git a/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp b/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp
new file mode 100644 (file)
index 0000000..b886942
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 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. ``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
+ * 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 "BaseAudioSharedUnit.h"
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "CoreAudioCaptureSource.h"
+#include "Logging.h"
+
+namespace WebCore {
+
+void BaseAudioSharedUnit::addClient(CoreAudioCaptureSource& client)
+{
+    auto locker = holdLock(m_clientsLock);
+    m_clients.add(&client);
+}
+
+void BaseAudioSharedUnit::removeClient(CoreAudioCaptureSource& client)
+{
+    auto locker = holdLock(m_clientsLock);
+    m_clients.remove(&client);
+}
+
+void BaseAudioSharedUnit::forEachClient(const Function<void(CoreAudioCaptureSource&)>& apply) const
+{
+    Vector<CoreAudioCaptureSource*> clientsCopy;
+    {
+        auto locker = holdLock(m_clientsLock);
+        clientsCopy = copyToVector(m_clients);
+    }
+    for (auto* client : clientsCopy) {
+        auto locker = holdLock(m_clientsLock);
+        // Make sure the client has not been destroyed.
+        if (!m_clients.contains(client))
+            continue;
+        apply(*client);
+    }
+}
+
+void BaseAudioSharedUnit::clearClients()
+{
+    auto locker = holdLock(m_clientsLock);
+    m_clients.clear();
+}
+
+void BaseAudioSharedUnit::startProducingData()
+{
+    ASSERT(isMainThread());
+
+    if (++m_producingCount != 1)
+        return;
+
+    if (isProducingData())
+        return;
+
+    if (hasAudioUnit()) {
+        cleanupAudioUnit();
+        ASSERT(!hasAudioUnit());
+    }
+
+    if (startInternal())
+        captureFailed();
+}
+
+OSStatus BaseAudioSharedUnit::resume()
+{
+    ASSERT(isMainThread());
+    ASSERT(m_suspended);
+    ASSERT(!isProducingData());
+
+    m_suspended = false;
+
+    if (!hasAudioUnit())
+        return 0;
+
+    startInternal();
+
+    return 0;
+}
+
+void BaseAudioSharedUnit::prepareForNewCapture()
+{
+    if (!m_suspended)
+        return;
+    m_suspended = false;
+
+    if (!m_producingCount)
+        return;
+
+    RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::prepareForNewCapture, notifying suspended sources of capture failure");
+    captureFailed();
+}
+
+void BaseAudioSharedUnit::captureFailed()
+{
+    RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::captureFailed - capture failed");
+    forEachClient([](auto& client) {
+        client.captureFailed();
+    });
+
+    m_producingCount = 0;
+
+    clearClients();
+
+    stopInternal();
+    cleanupAudioUnit();
+}
+
+void BaseAudioSharedUnit::stopProducingData()
+{
+    ASSERT(isMainThread());
+    ASSERT(m_producingCount);
+
+    if (m_producingCount && --m_producingCount)
+        return;
+
+    stopInternal();
+    cleanupAudioUnit();
+}
+
+OSStatus BaseAudioSharedUnit::suspend()
+{
+    ASSERT(isMainThread());
+
+    m_suspended = true;
+    stopInternal();
+
+    return 0;
+}
+
+void BaseAudioSharedUnit::audioSamplesAvailable(const MediaTime& time, const PlatformAudioData& data, const AudioStreamDescription& description, size_t numberOfFrames)
+{
+    forEachClient([&](auto& client) {
+        if (client.isProducingData())
+            client.audioSamplesAvailable(time, data, description, numberOfFrames);
+    });
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.h b/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.h
new file mode 100644 (file)
index 0000000..f6d23b5
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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. ``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
+ * 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(MEDIA_STREAM)
+
+#include <pal/cf/CoreMediaSoftLink.h>
+#include <wtf/Function.h>
+#include <wtf/HashSet.h>
+#include <wtf/RecursiveLockAdapter.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class CoreAudioCaptureSource;
+
+class BaseAudioSharedUnit {
+public:
+    virtual ~BaseAudioSharedUnit() = default;
+
+    void startProducingData();
+    void stopProducingData();
+    virtual bool isProducingData() const = 0;
+
+    virtual void delaySamples(Seconds) { }
+
+    void prepareForNewCapture();
+
+    OSStatus resume();
+    OSStatus suspend();
+
+    bool isSuspended() const { return m_suspended; }
+
+    double volume() const { return m_volume; }
+    int sampleRate() const { return m_sampleRate; }
+    bool enableEchoCancellation() const { return m_enableEchoCancellation; }
+
+    void setVolume(double volume) { m_volume = volume; }
+    void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
+    void setEnableEchoCancellation(bool enableEchoCancellation) { m_enableEchoCancellation = enableEchoCancellation; }
+
+    void addClient(CoreAudioCaptureSource&);
+    void removeClient(CoreAudioCaptureSource&);
+    void clearClients();
+
+    virtual bool hasAudioUnit() const = 0;
+    virtual void setCaptureDevice(String&&, uint32_t) = 0;
+    virtual OSStatus reconfigureAudioUnit() = 0;
+
+    virtual CapabilityValueOrRange sampleRateCapacities() const = 0;
+
+protected:
+    void forEachClient(const Function<void(CoreAudioCaptureSource&)>&) const;
+    bool hasClients() const { return !m_clients.isEmpty(); }
+    void captureFailed();
+
+    virtual void cleanupAudioUnit() = 0;
+    virtual OSStatus startInternal() = 0;
+    virtual void stopInternal() = 0;
+
+    void setSuspended(bool value) { m_suspended = value; }
+
+    void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t /*numberOfFrames*/);
+
+private:
+    bool m_enableEchoCancellation { true };
+    double m_volume { 1 };
+    int m_sampleRate;
+    bool m_suspended { false };
+
+    int32_t m_producingCount { 0 };
+
+    HashSet<CoreAudioCaptureSource*> m_clients;
+    mutable RecursiveLock m_clientsLock;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
index 7905b98..94e1d64 100644 (file)
@@ -31,6 +31,7 @@
 #include "AudioSampleBufferList.h"
 #include "AudioSampleDataSource.h"
 #include "AudioSession.h"
+#include "BaseAudioSharedUnit.h"
 #include "CoreAudioCaptureDevice.h"
 #include "CoreAudioCaptureDeviceManager.h"
 #include "Logging.h"
@@ -69,51 +70,31 @@ CoreAudioCaptureSourceFactory& CoreAudioCaptureSourceFactory::singleton()
 const UInt32 outputBus = 0;
 const UInt32 inputBus = 1;
 
-class CoreAudioSharedUnit {
+class CoreAudioSharedUnit final : public BaseAudioSharedUnit {
 public:
-    static CoreAudioSharedUnit& singleton();
+    static CoreAudioSharedUnit& unit();
+    static BaseAudioSharedUnit& singleton()  { return unit(); }
     CoreAudioSharedUnit();
 
-    void addClient(CoreAudioCaptureSource&);
-    void removeClient(CoreAudioCaptureSource&);
-
-    void startProducingData();
-    void stopProducingData();
-    bool isProducingData() { return m_ioUnitStarted; }
-
-    OSStatus suspend();
-    OSStatus resume();
-
-    bool isSuspended() const { return m_suspended; }
-
-    OSStatus setupAudioUnit();
-    void cleanupAudioUnit();
-    OSStatus reconfigureAudioUnit();
-
-    void addEchoCancellationSource(AudioSampleDataSource&);
-    void removeEchoCancellationSource(AudioSampleDataSource&);
+    void devicesChanged(const Vector<CaptureDevice>&);
 
+private:
     static size_t preferredIOBufferSize();
 
+    CapabilityValueOrRange sampleRateCapacities() const final { return CapabilityValueOrRange(8000, 96000); }
     const CAAudioStreamDescription& microphoneFormat() const { return m_microphoneProcFormat; }
 
-    double volume() const { return m_volume; }
-    int sampleRate() const { return m_sampleRate; }
-    bool enableEchoCancellation() const { return m_enableEchoCancellation; }
-
-    void setVolume(double volume) { m_volume = volume; }
-    void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
-    void setEnableEchoCancellation(bool enableEchoCancellation) { m_enableEchoCancellation = enableEchoCancellation; }
-
-    bool hasAudioUnit() const { return m_ioUnit; }
+    bool hasAudioUnit() const final { return m_ioUnit; }
+    void setCaptureDevice(String&&, uint32_t) final;
+    OSStatus reconfigureAudioUnit() final;
 
-    void setCaptureDevice(String&&, uint32_t);
-
-    void devicesChanged(const Vector<CaptureDevice>&);
+    OSStatus setupAudioUnit();
+    void cleanupAudioUnit() final;
 
-    void prepareForNewCapture();
+    OSStatus startInternal() final;
+    void stopInternal() final;
+    bool isProducingData() const final { return m_ioUnitStarted; }
 
-private:
     OSStatus configureSpeakerProc();
     OSStatus configureMicrophoneProc();
     OSStatus defaultOutputDevice(uint32_t*);
@@ -125,28 +106,16 @@ private:
     static OSStatus speakerCallback(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
     OSStatus provideSpeakerData(AudioUnitRenderActionFlags&, const AudioTimeStamp&, UInt32, UInt32, AudioBufferList*);
 
-    OSStatus startInternal();
-    void stopInternal();
-
     void unduck();
 
     void verifyIsCapturing();
     void devicesChanged();
-    void captureFailed();
-
-    void forEachClient(const Function<void(CoreAudioCaptureSource&)>& apply) const;
-
-    HashSet<CoreAudioCaptureSource*> m_clients;
-    mutable RecursiveLock m_clientsLock;
 
     AudioUnit m_ioUnit { nullptr };
 
     // Only read/modified from the IO thread.
     Vector<Ref<AudioSampleDataSource>> m_activeSources;
 
-    enum QueueAction { Add, Remove };
-    Vector<std::pair<QueueAction, Ref<AudioSampleDataSource>>> m_pendingSources;
-
 #if PLATFORM(MAC)
     uint32_t m_captureDeviceID { 0 };
 #endif
@@ -163,11 +132,6 @@ private:
     bool m_ioUnitInitialized { false };
     bool m_ioUnitStarted { false };
 
-    Lock m_pendingSourceQueueLock;
-    Lock m_internalStateLock;
-
-    int32_t m_producingCount { 0 };
-
     mutable std::unique_ptr<RealtimeMediaSourceCapabilities> m_capabilities;
     mutable Optional<RealtimeMediaSourceSettings> m_currentSettings;
 
@@ -183,15 +147,9 @@ private:
     uint64_t m_microphoneProcsCalled { 0 };
     uint64_t m_microphoneProcsCalledLastTime { 0 };
     Timer m_verifyCapturingTimer;
-
-    bool m_enableEchoCancellation { true };
-    double m_volume { 1 };
-    int m_sampleRate;
-
-    bool m_suspended { false };
 };
 
-CoreAudioSharedUnit& CoreAudioSharedUnit::singleton()
+CoreAudioSharedUnit& CoreAudioSharedUnit::unit()
 {
     static NeverDestroyed<CoreAudioSharedUnit> singleton;
     return singleton;
@@ -200,35 +158,7 @@ CoreAudioSharedUnit& CoreAudioSharedUnit::singleton()
 CoreAudioSharedUnit::CoreAudioSharedUnit()
     : m_verifyCapturingTimer(*this, &CoreAudioSharedUnit::verifyIsCapturing)
 {
-    m_sampleRate = AudioSession::sharedSession().sampleRate();
-}
-
-void CoreAudioSharedUnit::addClient(CoreAudioCaptureSource& client)
-{
-    auto locker = holdLock(m_clientsLock);
-    m_clients.add(&client);
-}
-
-void CoreAudioSharedUnit::removeClient(CoreAudioCaptureSource& client)
-{
-    auto locker = holdLock(m_clientsLock);
-    m_clients.remove(&client);
-}
-
-void CoreAudioSharedUnit::forEachClient(const Function<void(CoreAudioCaptureSource&)>& apply) const
-{
-    Vector<CoreAudioCaptureSource*> clientsCopy;
-    {
-        auto locker = holdLock(m_clientsLock);
-        clientsCopy = copyToVector(m_clients);
-    }
-    for (auto* client : clientsCopy) {
-        auto locker = holdLock(m_clientsLock);
-        // Make sure the client has not been destroyed.
-        if (!m_clients.contains(client))
-            continue;
-        apply(*client);
-    }
+    setSampleRate(AudioSession::sharedSession().sampleRate());
 }
 
 void CoreAudioSharedUnit::setCaptureDevice(String&& persistentID, uint32_t captureDeviceID)
@@ -257,23 +187,6 @@ void CoreAudioSharedUnit::devicesChanged(const Vector<CaptureDevice>& devices)
     captureFailed();
 }
 
-void CoreAudioSharedUnit::addEchoCancellationSource(AudioSampleDataSource& source)
-{
-    if (!source.setOutputFormat(m_speakerProcFormat)) {
-        RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::addEchoCancellationSource: source %p configureOutput failed", &source);
-        return;
-    }
-
-    std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
-    m_pendingSources.append({ QueueAction::Add, source });
-}
-
-void CoreAudioSharedUnit::removeEchoCancellationSource(AudioSampleDataSource& source)
-{
-    std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
-    m_pendingSources.append({ QueueAction::Remove, source });
-}
-
 size_t CoreAudioSharedUnit::preferredIOBufferSize()
 {
     return AudioSession::sharedSession().bufferSize();
@@ -284,7 +197,7 @@ OSStatus CoreAudioSharedUnit::setupAudioUnit()
     if (m_ioUnit)
         return 0;
 
-    ASSERT(!m_clients.isEmpty());
+    ASSERT(hasClients());
 
     mach_timebase_info_data_t timebaseInfo;
     mach_timebase_info(&timebaseInfo);
@@ -314,7 +227,7 @@ OSStatus CoreAudioSharedUnit::setupAudioUnit()
         return err;
     }
 
-    if (!m_enableEchoCancellation) {
+    if (!enableEchoCancellation()) {
         uint32_t param = 0;
         err = AudioUnitSetProperty(m_ioUnit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, inputBus, &param, sizeof(param));
         if (err) {
@@ -364,7 +277,7 @@ OSStatus CoreAudioSharedUnit::setupAudioUnit()
         return err;
     }
     m_ioUnitInitialized = true;
-    m_suspended = false;
+    setSuspended(false);
 
     unduck();
 
@@ -396,7 +309,7 @@ OSStatus CoreAudioSharedUnit::configureMicrophoneProc()
         return err;
     }
 
-    microphoneProcFormat.mSampleRate = m_sampleRate;
+    microphoneProcFormat.mSampleRate = sampleRate();
     err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &microphoneProcFormat, size);
     if (err) {
         RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to set output stream format, error %d (%.4s)", this, (int)err, (char*)&err);
@@ -427,7 +340,7 @@ OSStatus CoreAudioSharedUnit::configureSpeakerProc()
         return err;
     }
 
-    speakerProcFormat.mSampleRate = m_sampleRate;
+    speakerProcFormat.mSampleRate = sampleRate();
     err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &speakerProcFormat, size);
     if (err) {
         RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to get input stream format, error %d (%.4s)", this, (int)err, (char*)&err);
@@ -463,25 +376,6 @@ OSStatus CoreAudioSharedUnit::provideSpeakerData(AudioUnitRenderActionFlags& /*i
         return kAudio_ParamError;
     }
 
-    // Add/remove sources from the queue, but only if we get the lock immediately. Otherwise try
-    // again on the next callback.
-    {
-        std::unique_lock<Lock> lock(m_pendingSourceQueueLock, std::try_to_lock);
-        if (lock.owns_lock()) {
-            for (auto& pair : m_pendingSources) {
-                if (pair.first == QueueAction::Add)
-                    m_activeSources.append(pair.second.copyRef());
-                else {
-                    auto removeSource = pair.second.copyRef();
-                    m_activeSources.removeFirstMatching([&removeSource](auto& source) {
-                        return source.ptr() == removeSource.ptr();
-                    });
-                }
-            }
-            m_pendingSources.clear();
-        }
-    }
-
     if (m_activeSources.isEmpty())
         return 0;
 
@@ -534,13 +428,10 @@ OSStatus CoreAudioSharedUnit::processMicrophoneSamples(AudioUnitRenderActionFlag
     m_latestMicTimeStamp = sampleTime;
     m_microphoneSampleBuffer->setTimes(adjustedHostTime, sampleTime);
 
-    if (m_volume != 1.0)
-        m_microphoneSampleBuffer->applyGain(m_volume);
+    if (volume() != 1.0)
+        m_microphoneSampleBuffer->applyGain(volume());
 
-    forEachClient([&](auto& client) {
-        if (client.isProducingData())
-            client.audioSamplesAvailable(MediaTime(sampleTime, m_microphoneProcFormat.sampleRate()), m_microphoneSampleBuffer->bufferList(), m_microphoneProcFormat, inNumberFrames);
-    });
+    audioSamplesAvailable(MediaTime(sampleTime, m_microphoneProcFormat.sampleRate()), m_microphoneSampleBuffer->bufferList(), m_microphoneProcFormat, inNumberFrames);
     return noErr;
 }
 
@@ -603,54 +494,6 @@ OSStatus CoreAudioSharedUnit::reconfigureAudioUnit()
     return err;
 }
 
-void CoreAudioSharedUnit::startProducingData()
-{
-    ASSERT(isMainThread());
-
-    if (++m_producingCount != 1)
-        return;
-
-    if (m_ioUnitStarted)
-        return;
-
-    if (m_ioUnit) {
-        cleanupAudioUnit();
-        ASSERT(!m_ioUnit);
-    }
-
-    if (startInternal())
-        captureFailed();
-}
-
-OSStatus CoreAudioSharedUnit::resume()
-{
-    ASSERT(isMainThread());
-    ASSERT(m_suspended);
-    ASSERT(!m_ioUnitStarted);
-
-    m_suspended = false;
-
-    if (!m_ioUnit)
-        return 0;
-
-    startInternal();
-
-    return 0;
-}
-
-void CoreAudioSharedUnit::prepareForNewCapture()
-{
-    if (!m_suspended)
-        return;
-    m_suspended = false;
-
-    if (!m_producingCount)
-        return;
-
-    RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::prepareForNewCapture, notifying suspended sources of capture failure");
-    captureFailed();
-}
-
 OSStatus CoreAudioSharedUnit::startInternal()
 {
     OSStatus err;
@@ -701,46 +544,6 @@ void CoreAudioSharedUnit::verifyIsCapturing()
     captureFailed();
 }
 
-void CoreAudioSharedUnit::captureFailed()
-{
-    RELEASE_LOG_ERROR(WebRTC, "CoreAudioSharedUnit::captureFailed - capture failed");
-    forEachClient([](auto& client) {
-        client.captureFailed();
-    });
-
-    m_producingCount = 0;
-
-    {
-        auto locker = holdLock(m_clientsLock);
-        m_clients.clear();
-    }
-
-    stopInternal();
-    cleanupAudioUnit();
-}
-
-void CoreAudioSharedUnit::stopProducingData()
-{
-    ASSERT(isMainThread());
-    ASSERT(m_producingCount);
-
-    if (m_producingCount && --m_producingCount)
-        return;
-
-    stopInternal();
-    cleanupAudioUnit();
-}
-
-OSStatus CoreAudioSharedUnit::suspend()
-{
-    ASSERT(isMainThread());
-
-    m_suspended = true;
-    stopInternal();
-
-    return 0;
-}
-
 void CoreAudioSharedUnit::stopInternal()
 {
     m_verifyCapturingTimer.stop();
@@ -785,6 +588,21 @@ OSStatus CoreAudioSharedUnit::defaultOutputDevice(uint32_t* deviceID)
     return err;
 }
 
+static CaptureSourceOrError initializeCoreAudioCaptureSource(Ref<CoreAudioCaptureSource>&& source, const MediaConstraints* constraints)
+{
+#if PLATFORM(IOS_FAMILY)
+    // We ensure that we unsuspend ourselves on the constructor as a capture source
+    // is created when getUserMedia grants access which only happens when the process is foregrounded.
+    CoreAudioSharedUnit::singleton().prepareForNewCapture();
+#endif
+
+    if (constraints) {
+        if (auto result = source->applyConstraints(*constraints))
+            return WTFMove(result->badConstraint);
+    }
+    return CaptureSourceOrError(WTFMove(source));
+}
+
 CaptureSourceOrError CoreAudioCaptureSource::create(String&& deviceID, String&& hashSalt, const MediaConstraints* constraints)
 {
 #if PLATFORM(MAC)
@@ -800,12 +618,25 @@ CaptureSourceOrError CoreAudioCaptureSource::create(String&& deviceID, String&&
 
     auto source = adoptRef(*new CoreAudioCaptureSource(WTFMove(deviceID), String { device->label() }, WTFMove(hashSalt), 0));
 #endif
+    return initializeCoreAudioCaptureSource(WTFMove(source), constraints);
+}
 
-    if (constraints) {
-        if (auto result = source->applyConstraints(*constraints))
-            return WTFMove(result->badConstraint);
-    }
-    return CaptureSourceOrError(WTFMove(source));
+CaptureSourceOrError CoreAudioCaptureSource::createForTesting(String&& deviceID, String&& label, String&& hashSalt, const MediaConstraints* constraints, BaseAudioSharedUnit& overrideUnit)
+{
+    auto source = adoptRef(*new CoreAudioCaptureSource(WTFMove(deviceID), WTFMove(label), WTFMove(hashSalt), 0));
+
+    source->m_overrideUnit = &overrideUnit;
+    return initializeCoreAudioCaptureSource(WTFMove(source), constraints);
+}
+
+BaseAudioSharedUnit& CoreAudioCaptureSource::unit()
+{
+    return m_overrideUnit ? *m_overrideUnit : CoreAudioSharedUnit::singleton();
+}
+
+const BaseAudioSharedUnit& CoreAudioCaptureSource::unit() const
+{
+    return m_overrideUnit ? *m_overrideUnit : CoreAudioSharedUnit::singleton();
 }
 
 void CoreAudioCaptureSourceFactory::beginInterruption()
@@ -875,18 +706,17 @@ CaptureDeviceManager& CoreAudioCaptureSourceFactory::audioCaptureDeviceManager()
 
 void CoreAudioCaptureSourceFactory::devicesChanged(const Vector<CaptureDevice>& devices)
 {
-    CoreAudioSharedUnit::singleton().devicesChanged(devices);
+    CoreAudioSharedUnit::unit().devicesChanged(devices);
 }
 
 CoreAudioCaptureSource::CoreAudioCaptureSource(String&& deviceID, String&& label, String&& hashSalt, uint32_t captureDeviceID)
     : RealtimeMediaSource(RealtimeMediaSource::Type::Audio, WTFMove(label), WTFMove(deviceID), WTFMove(hashSalt))
     , m_captureDeviceID(captureDeviceID)
 {
-#if PLATFORM(IOS_FAMILY)
-    // We ensure that we unsuspend ourselves on the constructor as a capture source
-    // is created when getUserMedia grants access which only happens when the process is foregrounded.
-    CoreAudioSharedUnit::singleton().prepareForNewCapture();
-#endif
+    auto& unit = this->unit();
+    initializeEchoCancellation(unit.enableEchoCancellation());
+    initializeSampleRate(unit.sampleRate());
+    initializeVolume(unit.volume());
 }
 
 void CoreAudioCaptureSource::initializeToStartProducingData()
@@ -897,7 +727,7 @@ void CoreAudioCaptureSource::initializeToStartProducingData()
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
     m_isReadyToStart = true;
 
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
     unit.setCaptureDevice(String { persistentID() }, m_captureDeviceID);
 
     initializeEchoCancellation(unit.enableEchoCancellation());
@@ -913,19 +743,7 @@ CoreAudioCaptureSource::~CoreAudioCaptureSource()
     CoreAudioCaptureSourceFactory::singleton().unsetCoreAudioActiveSource(*this);
 #endif
 
-    CoreAudioSharedUnit::singleton().removeClient(*this);
-}
-
-void CoreAudioCaptureSource::addEchoCancellationSource(AudioSampleDataSource& source)
-{
-    ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
-    CoreAudioSharedUnit::singleton().addEchoCancellationSource(source);
-}
-
-void CoreAudioCaptureSource::removeEchoCancellationSource(AudioSampleDataSource& source)
-{
-    ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
-    CoreAudioSharedUnit::singleton().removeEchoCancellationSource(source);
+    unit().removeClient(*this);
 }
 
 void CoreAudioCaptureSource::startProducingData()
@@ -934,7 +752,7 @@ void CoreAudioCaptureSource::startProducingData()
     CoreAudioCaptureSourceFactory::singleton().setCoreAudioActiveSource(*this);
 #endif
 
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
 
     auto isSuspended = unit.isSuspended();
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER, isSuspended);
@@ -950,7 +768,7 @@ void CoreAudioCaptureSource::startProducingData()
 
 void CoreAudioCaptureSource::stopProducingData()
 {
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
 
     auto isSuspended = unit.isSuspended();
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER, isSuspended);
@@ -970,7 +788,7 @@ const RealtimeMediaSourceCapabilities& CoreAudioCaptureSource::capabilities()
         capabilities.setDeviceId(hashedId());
         capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
         capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
-        capabilities.setSampleRate(CapabilityValueOrRange(8000, 96000));
+        capabilities.setSampleRate(unit().sampleRateCapacities());
         m_capabilities = WTFMove(capabilities);
     }
     return m_capabilities.value();
@@ -1001,11 +819,11 @@ const RealtimeMediaSourceSettings& CoreAudioCaptureSource::settings()
 void CoreAudioCaptureSource::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
 {
     if (settings.contains(RealtimeMediaSourceSettings::Flag::EchoCancellation)) {
-        CoreAudioSharedUnit::singleton().setEnableEchoCancellation(echoCancellation());
+        unit().setEnableEchoCancellation(echoCancellation());
         scheduleReconfiguration();
     }
     if (settings.contains(RealtimeMediaSourceSettings::Flag::SampleRate)) {
-        CoreAudioSharedUnit::singleton().setSampleRate(sampleRate());
+        unit().setSampleRate(sampleRate());
         scheduleReconfiguration();
     }
 
@@ -1017,7 +835,7 @@ void CoreAudioCaptureSource::scheduleReconfiguration()
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
 
     ASSERT(isMainThread());
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
     if (!unit.hasAudioUnit() || m_reconfigurationState != ReconfigurationState::None)
         return;
 
@@ -1038,7 +856,7 @@ void CoreAudioCaptureSource::beginInterruption()
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
 
     ASSERT(isMainThread());
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
     if (!unit.hasAudioUnit() || unit.isSuspended() || m_suspendPending)
         return;
 
@@ -1056,7 +874,7 @@ void CoreAudioCaptureSource::endInterruption()
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
 
     ASSERT(isMainThread());
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
     if (!unit.hasAudioUnit() || !unit.isSuspended() || m_resumePending)
         return;
 
@@ -1080,11 +898,12 @@ void CoreAudioCaptureSource::endInterruption()
 
 bool CoreAudioCaptureSource::interrupted() const
 {
-    auto& unit = CoreAudioSharedUnit::singleton();
-    if (unit.isSuspended())
-        return true;
+    return unit().isSuspended() ? true : RealtimeMediaSource::interrupted();
+}
 
-    return RealtimeMediaSource::interrupted();
+void CoreAudioCaptureSource::delaySamples(Seconds seconds)
+{
+    unit().delaySamples(seconds);
 }
 
 } // namespace WebCore
index adbefe7..0423f59 100644 (file)
@@ -49,24 +49,17 @@ namespace WebCore {
 
 class AudioSampleBufferList;
 class AudioSampleDataSource;
+class BaseAudioSharedUnit;
 class CaptureDeviceInfo;
 class WebAudioSourceProviderAVFObjC;
 
 class CoreAudioCaptureSource : public RealtimeMediaSource {
 public:
-
     static CaptureSourceOrError create(String&& deviceID, String&& hashSalt, const MediaConstraints*);
+    static CaptureSourceOrError createForTesting(String&& deviceID, String&& label, String&& hashSalt, const MediaConstraints*, BaseAudioSharedUnit& overrideUnit);
 
     WEBCORE_EXPORT static AudioCaptureFactory& factory();
 
-    void addEchoCancellationSource(AudioSampleDataSource&);
-    void removeEchoCancellationSource(AudioSampleDataSource&);
-
-    using MicrophoneDataCallback = WTF::Function<void(const MediaTime& sampleTime, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t sampleCount)>;
-
-    uint64_t addMicrophoneDataConsumer(MicrophoneDataCallback&&);
-    void removeMicrophoneDataConsumer(uint64_t);
-
     CMClockRef timebaseClock();
 
     void beginInterruption();
@@ -76,8 +69,11 @@ public:
 protected:
     CoreAudioCaptureSource(String&& deviceID, String&& label, String&& hashSalt, uint32_t persistentID);
     virtual ~CoreAudioCaptureSource();
+    BaseAudioSharedUnit& unit();
+    const BaseAudioSharedUnit& unit() const;
 
 private:
+    friend class BaseAudioSharedUnit;
     friend class CoreAudioSharedUnit;
     friend class CoreAudioCaptureSourceFactory;
 
@@ -85,6 +81,8 @@ private:
     void startProducingData() final;
     void stopProducingData() final;
 
+    void delaySamples(Seconds) final;
+
     Optional<Vector<int>> discreteSampleRates() const final { return { { 8000, 16000, 32000, 44100, 48000, 96000 } }; }
 
     const RealtimeMediaSourceCapabilities& capabilities() final;
@@ -115,6 +113,8 @@ private:
     bool m_suspendPending { false };
     bool m_resumePending { false };
     bool m_isReadyToStart { false };
+    
+    BaseAudioSharedUnit* m_overrideUnit { nullptr };
 };
 
 class CoreAudioCaptureSourceFactory : public AudioCaptureFactory {
diff --git a/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.h b/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.h
new file mode 100644 (file)
index 0000000..0f89616
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016-2019 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "BaseAudioSharedUnit.h"
+#include <CoreAudio/CoreAudioTypes.h>
+#include <wtf/RunLoop.h>
+#include <wtf/Vector.h>
+#include <wtf/WorkQueue.h>
+
+OBJC_CLASS AVAudioPCMBuffer;
+typedef struct OpaqueCMClock* CMClockRef;
+typedef const struct opaqueCMFormatDescription* CMFormatDescriptionRef;
+
+namespace WebCore {
+
+class WebAudioBufferList;
+class WebAudioSourceProviderAVFObjC;
+
+class MockAudioSharedUnit final : public BaseAudioSharedUnit {
+public:
+    static MockAudioSharedUnit& singleton();
+    MockAudioSharedUnit();
+
+private:
+    bool hasAudioUnit() const final;
+    void setCaptureDevice(String&&, uint32_t) final;
+    OSStatus reconfigureAudioUnit() final;
+
+    void cleanupAudioUnit() final;
+    OSStatus startInternal() final;
+    void stopInternal() final;
+    bool isProducingData() const final;
+
+    void delaySamples(Seconds) final;
+
+    CapabilityValueOrRange sampleRateCapacities() const final { return CapabilityValueOrRange(44100, 48000); }
+
+    void tick();
+
+    void render(Seconds);
+    void emitSampleBuffers(uint32_t frameCount);
+    void reconfigure();
+
+    static Seconds renderInterval() { return 60_ms; }
+
+    std::unique_ptr<WebAudioBufferList> m_audioBufferList;
+
+    uint32_t m_maximiumFrameCount;
+    uint64_t m_samplesEmitted { 0 };
+    uint64_t m_samplesRendered { 0 };
+
+    RetainPtr<CMFormatDescriptionRef> m_formatDescription;
+    AudioStreamBasicDescription m_streamFormat;
+
+    Vector<float> m_bipBopBuffer;
+    bool m_hasAudioUnit { false };
+
+    RunLoop::Timer<MockAudioSharedUnit> m_timer;
+    MonotonicTime m_startTime { MonotonicTime::nan() };
+    MonotonicTime m_lastRenderTime { MonotonicTime::nan() };
+    Seconds m_elapsedTime { 0_s };
+    MonotonicTime m_delayUntil;
+
+    Ref<WorkQueue> m_workQueue;
+    unsigned m_channelCount { 2 };
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
+
@@ -1,39 +1,38 @@
 /*
- * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2019 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.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
+ *    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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
- * OWNER OR 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
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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
+ * 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.
  */
 
+
 #import "config.h"
-#import "MockRealtimeAudioSourceMac.h"
+#import "MockAudioSharedUnit.h"
 
 #if ENABLE(MEDIA_STREAM)
 #import "AudioSampleBufferList.h"
+#import "AudioSession.h"
+#import "BaseAudioSharedUnit.h"
 #import "CAAudioStreamDescription.h"
+#import "CoreAudioCaptureSource.h"
 #import "MediaConstraints.h"
 #import "MediaSampleAVFObjC.h"
 #import "MockRealtimeMediaSourceCenter.h"
@@ -94,33 +93,110 @@ CaptureSourceOrError MockRealtimeAudioSource::create(String&& deviceID, String&&
     if (!device)
         return { };
 #endif
+    return CoreAudioCaptureSource::createForTesting(WTFMove(deviceID),  WTFMove(name), WTFMove(hashSalt), constraints, MockAudioSharedUnit::singleton());
+}
 
-    auto source = adoptRef(*new MockRealtimeAudioSourceMac(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)));
-    // FIXME: We should report error messages
-    if (constraints && source->applyConstraints(*constraints))
-        return { };
+MockAudioSharedUnit& MockAudioSharedUnit::singleton()
+{
+    static NeverDestroyed<MockAudioSharedUnit> singleton;
+    return singleton;
+}
 
-    return CaptureSourceOrError(WTFMove(source));
+MockAudioSharedUnit::MockAudioSharedUnit()
+    : m_timer(RunLoop::current(), this, &MockAudioSharedUnit::tick)
+    , m_workQueue(WorkQueue::create("MockAudioSharedUnit Capture Queue"))
+{
+    setSampleRate(AudioSession::sharedSession().sampleRate());
+    setEnableEchoCancellation(false);
 }
 
-MockRealtimeAudioSourceMac::MockRealtimeAudioSourceMac(String&& deviceID, String&& name, String&& hashSalt)
-    : MockRealtimeAudioSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
+bool MockAudioSharedUnit::hasAudioUnit() const
 {
-    ASSERT(isMainThread());
+    return m_hasAudioUnit;
 }
 
-void MockRealtimeAudioSourceMac::emitSampleBuffers(uint32_t frameCount)
+void MockAudioSharedUnit::setCaptureDevice(String&&, uint32_t)
 {
-    ASSERT(!isMainThread());
-    ASSERT(m_formatDescription);
+    reconfigureAudioUnit();
+}
 
-    CMTime startTime = CMTimeMake(m_samplesEmitted, sampleRate());
-    m_samplesEmitted += frameCount;
+OSStatus MockAudioSharedUnit::reconfigureAudioUnit()
+{
+    if (!hasAudioUnit())
+        return 0;
 
-    audioSamplesAvailable(PAL::toMediaTime(startTime), *m_audioBufferList, CAAudioStreamDescription(m_streamFormat), frameCount);
+    m_timer.stop();
+    m_startTime = MonotonicTime::nan();
+    m_workQueue->dispatch([this] {
+        reconfigure();
+        callOnMainThread([this] {
+            m_startTime = MonotonicTime::now();
+            m_timer.startRepeating(renderInterval());
+        });
+    });
+    return 0;
+}
+
+void MockAudioSharedUnit::cleanupAudioUnit()
+{
+    m_hasAudioUnit = false;
+    m_timer.stop();
+    m_startTime = MonotonicTime::nan();
+}
+
+OSStatus MockAudioSharedUnit::startInternal()
+{
+#if PLATFORM(IOS_FAMILY)
+    ASSERT(AudioSession::sharedSession().category() == AudioSession::PlayAndRecord);
+#endif
+    if (!m_hasAudioUnit)
+        m_hasAudioUnit = true;
+
+    m_startTime = MonotonicTime::now();
+    m_timer.startRepeating(renderInterval());
+    return 0;
 }
 
-void MockRealtimeAudioSourceMac::reconfigure()
+void MockAudioSharedUnit::stopInternal()
+{
+    if (!m_hasAudioUnit)
+        return;
+    m_timer.stop();
+    m_startTime = MonotonicTime::nan();
+}
+
+bool MockAudioSharedUnit::isProducingData() const
+{
+    return m_timer.isActive();
+}
+
+void MockAudioSharedUnit::tick()
+{
+    if (std::isnan(m_lastRenderTime))
+        m_lastRenderTime = MonotonicTime::now();
+
+    MonotonicTime now = MonotonicTime::now();
+
+    if (m_delayUntil) {
+        if (m_delayUntil < now)
+            return;
+        m_delayUntil = MonotonicTime();
+    }
+
+    Seconds delta = now - m_lastRenderTime;
+    m_lastRenderTime = now;
+
+    m_workQueue->dispatch([this, delta] {
+        render(delta);
+    });
+}
+
+void MockAudioSharedUnit::delaySamples(Seconds delta)
+{
+    m_delayUntil = MonotonicTime::now() + delta;
+}
+
+void MockAudioSharedUnit::reconfigure()
 {
     ASSERT(!isMainThread());
 
@@ -156,7 +232,18 @@ void MockRealtimeAudioSourceMac::reconfigure()
     addHum(BipBopVolume, BopFrequency, rate, 0, m_bipBopBuffer.data() + bopStart, bipBopSampleCount);
 }
 
-void MockRealtimeAudioSourceMac::render(Seconds delta)
+void MockAudioSharedUnit::emitSampleBuffers(uint32_t frameCount)
+{
+    ASSERT(!isMainThread());
+    ASSERT(m_formatDescription);
+
+    CMTime startTime = CMTimeMake(m_samplesEmitted, sampleRate());
+    m_samplesEmitted += frameCount;
+
+    audioSamplesAvailable(PAL::toMediaTime(startTime), *m_audioBufferList, CAAudioStreamDescription(m_streamFormat), frameCount);
+}
+
+void MockAudioSharedUnit::render(Seconds delta)
 {
     ASSERT(!isMainThread());
     if (!m_audioBufferList || !m_bipBopBuffer.size())
@@ -171,11 +258,8 @@ void MockRealtimeAudioSourceMac::render(Seconds delta)
         uint32_t bipBopCount = std::min(frameCount, bipBopRemain);
         for (auto& audioBuffer : m_audioBufferList->buffers()) {
             audioBuffer.mDataByteSize = frameCount * m_streamFormat.mBytesPerFrame;
-            if (!muted()) {
-                memcpy(audioBuffer.mData, &m_bipBopBuffer[bipBopStart], sizeof(Float32) * bipBopCount);
-                addHum(HumVolume, HumFrequency, sampleRate(), m_samplesRendered, static_cast<float*>(audioBuffer.mData), bipBopCount);
-            } else
-                memset(audioBuffer.mData, 0, sizeof(Float32) * bipBopCount);
+            memcpy(audioBuffer.mData, &m_bipBopBuffer[bipBopStart], sizeof(Float32) * bipBopCount);
+            addHum(HumVolume, HumFrequency, sampleRate(), m_samplesRendered, static_cast<float*>(audioBuffer.mData), bipBopCount);
         }
         emitSampleBuffers(bipBopCount);
         m_samplesRendered += bipBopCount;
@@ -184,17 +268,6 @@ void MockRealtimeAudioSourceMac::render(Seconds delta)
     }
 }
 
-void MockRealtimeAudioSourceMac::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
-{
-    if (settings.contains(RealtimeMediaSourceSettings::Flag::SampleRate)) {
-        m_workQueue->dispatch([this, protectedThis = makeRef(*this)] {
-            reconfigure();
-        });
-    }
-
-    MockRealtimeAudioSource::settingsDidChange(settings);
-}
-
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h b/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h
deleted file mode 100644 (file)
index 49384f4..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016-2018 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.
- * 3. Neither the name of Ericsson nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
- * OWNER OR 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.
- */
-
-#pragma once
-
-#if ENABLE(MEDIA_STREAM)
-
-#include "MockRealtimeAudioSource.h"
-#include <CoreAudio/CoreAudioTypes.h>
-#include <wtf/Vector.h>
-
-OBJC_CLASS AVAudioPCMBuffer;
-typedef struct OpaqueCMClock* CMClockRef;
-typedef const struct opaqueCMFormatDescription* CMFormatDescriptionRef;
-
-namespace WebCore {
-
-class WebAudioBufferList;
-class WebAudioSourceProviderAVFObjC;
-
-class MockRealtimeAudioSourceMac final : public MockRealtimeAudioSource {
-private:
-    friend class MockRealtimeAudioSource;
-    MockRealtimeAudioSourceMac(String&& deviceID, String&& name, String&& hashSalt);
-
-    void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) final;
-    Optional<Vector<int>> discreteSampleRates() const final { return { { 44100, 48000 } }; }
-
-    void emitSampleBuffers(uint32_t);
-    void render(Seconds) final;
-    void reconfigure();
-
-    std::unique_ptr<WebAudioBufferList> m_audioBufferList;
-
-    uint32_t m_maximiumFrameCount;
-    uint64_t m_samplesEmitted { 0 };
-    uint64_t m_samplesRendered { 0 };
-
-    RetainPtr<CMFormatDescriptionRef> m_formatDescription;
-    AudioStreamBasicDescription m_streamFormat;
-
-    Vector<float> m_bipBopBuffer;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(MEDIA_STREAM)
-