Title: [252660] trunk/Source/WebCore
Revision
252660
Author
[email protected]
Date
2019-11-19 16:50:51 -0800 (Tue, 19 Nov 2019)

Log Message

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.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (252659 => 252660)


--- trunk/Source/WebCore/ChangeLog	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/ChangeLog	2019-11-20 00:50:51 UTC (rev 252660)
@@ -1,3 +1,89 @@
+2019-11-19  Youenn Fablet  <[email protected]>
+
+        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  <[email protected]>
 
         Unreviewed non-unified build fixes.

Modified: trunk/Source/WebCore/SourcesCocoa.txt (252659 => 252660)


--- trunk/Source/WebCore/SourcesCocoa.txt	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/SourcesCocoa.txt	2019-11-20 00:50:51 UTC (rev 252660)
@@ -547,6 +547,7 @@
 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/audio/mac/AudioSampleDataSource.mm
 
-platform/mediastream/mac/MockRealtimeAudioSourceMac.mm
+platform/mediastream/mac/MockAudioSharedUnit.mm
 platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm
 
 platform/mediastream/libwebrtc/LibWebRTCProviderCocoa.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (252659 => 252660)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-11-20 00:50:51 UTC (rev 252660)
@@ -5425,8 +5425,8 @@
 		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>"; };
@@ -7350,6 +7350,8 @@
 		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; };
@@ -16152,6 +16154,8 @@
 				070363DB181A1CDC00C074A5 /* AVCaptureDeviceManager.mm */,
 				070363DE181A1CDC00C074A5 /* AVVideoCaptureSource.h */,
 				070363DF181A1CDC00C074A5 /* AVVideoCaptureSource.mm */,
+				4177F51C2382544000C04486 /* BaseAudioSharedUnit.cpp */,
+				4177F51E2382545E00C04486 /* BaseAudioSharedUnit.h */,
 				3F8020311E9E381D00DEC61D /* CoreAudioCaptureDevice.cpp */,
 				3F8020321E9E381D00DEC61D /* CoreAudioCaptureDevice.h */,
 				3F8020331E9E381D00DEC61D /* CoreAudioCaptureDeviceManager.cpp */,
@@ -16162,8 +16166,8 @@
 				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 */,

Added: trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp (0 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp	2019-11-20 00:50:51 UTC (rev 252660)
@@ -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)

Added: trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.h (0 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.h	2019-11-20 00:50:51 UTC (rev 252660)
@@ -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)

Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp (252659 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp	2019-11-20 00:50:51 UTC (rev 252660)
@@ -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 @@
 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 devicesChanged(const Vector<CaptureDevice>&);
 
-    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&);
-
+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; }
+    bool hasAudioUnit() const final { return m_ioUnit; }
+    void setCaptureDevice(String&&, uint32_t) final;
+    OSStatus reconfigureAudioUnit() final;
 
-    void setVolume(double volume) { m_volume = volume; }
-    void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
-    void setEnableEchoCancellation(bool enableEchoCancellation) { m_enableEchoCancellation = enableEchoCancellation; }
+    OSStatus setupAudioUnit();
+    void cleanupAudioUnit() final;
 
-    bool hasAudioUnit() const { return m_ioUnit; }
+    OSStatus startInternal() final;
+    void stopInternal() final;
+    bool isProducingData() const final { return m_ioUnitStarted; }
 
-    void setCaptureDevice(String&&, uint32_t);
-
-    void devicesChanged(const Vector<CaptureDevice>&);
-
-    void prepareForNewCapture();
-
-private:
     OSStatus configureSpeakerProc();
     OSStatus configureMicrophoneProc();
     OSStatus defaultOutputDevice(uint32_t*);
@@ -125,28 +106,16 @@
     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 @@
     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 @@
     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,37 +158,9 @@
 CoreAudioSharedUnit::CoreAudioSharedUnit()
     : m_verifyCapturingTimer(*this, &CoreAudioSharedUnit::verifyIsCapturing)
 {
-    m_sampleRate = AudioSession::sharedSession().sampleRate();
+    setSampleRate(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);
-    }
-}
-
 void CoreAudioSharedUnit::setCaptureDevice(String&& persistentID, uint32_t captureDeviceID)
 {
     m_persistentID = WTFMove(persistentID);
@@ -257,23 +187,6 @@
     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 @@
     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 @@
         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 @@
         return err;
     }
     m_ioUnitInitialized = true;
-    m_suspended = false;
+    setSuspended(false);
 
     unduck();
 
@@ -396,7 +309,7 @@
         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 @@
         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 @@
         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 @@
     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 @@
     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 @@
     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 @@
     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,14 +618,27 @@
 
     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()
 {
     if (!isMainThread()) {
@@ -875,7 +706,7 @@
 
 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)
@@ -882,11 +713,10 @@
     : 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 @@
     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,21 +743,9 @@
     CoreAudioCaptureSourceFactory::singleton().unsetCoreAudioActiveSource(*this);
 #endif
 
-    CoreAudioSharedUnit::singleton().removeClient(*this);
+    unit().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);
-}
-
 void CoreAudioCaptureSource::startProducingData()
 {
 #if PLATFORM(IOS_FAMILY)
@@ -934,7 +752,7 @@
     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::stopProducingData()
 {
-    auto& unit = CoreAudioSharedUnit::singleton();
+    auto& unit = this->unit();
 
     auto isSuspended = unit.isSuspended();
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER, isSuspended);
@@ -970,7 +788,7 @@
         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 @@
 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 @@
     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 @@
     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 @@
     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 @@
 
 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

Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h (252659 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h	2019-11-20 00:50:51 UTC (rev 252660)
@@ -49,24 +49,17 @@
 
 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 @@
 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 @@
     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 @@
     bool m_suspendPending { false };
     bool m_resumePending { false };
     bool m_isReadyToStart { false };
+    
+    BaseAudioSharedUnit* m_overrideUnit { nullptr };
 };
 
 class CoreAudioCaptureSourceFactory : public AudioCaptureFactory {

Added: trunk/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.h (0 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.h	2019-11-20 00:50:51 UTC (rev 252660)
@@ -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)
+

Copied: trunk/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.mm (from rev 252659, trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm) (0 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.mm	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockAudioSharedUnit.mm	2019-11-20 00:50:51 UTC (rev 252660)
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ */
+
+
+#import "config.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"
+#import "NotImplemented.h"
+#import "RealtimeMediaSourceSettings.h"
+#import "WebAudioBufferList.h"
+#import "WebAudioSourceProviderAVFObjC.h"
+#import <AVFoundation/AVAudioBuffer.h>
+#import <AudioToolbox/AudioConverter.h>
+#import <CoreAudio/CoreAudioTypes.h>
+
+#import <pal/cf/CoreMediaSoftLink.h>
+
+SOFT_LINK_FRAMEWORK(AudioToolbox)
+
+SOFT_LINK(AudioToolbox, AudioConverterNew, OSStatus, (const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat, AudioConverterRef* outAudioConverter), (inSourceFormat, inDestinationFormat, outAudioConverter))
+
+namespace WebCore {
+using namespace PAL;
+
+static inline size_t alignTo16Bytes(size_t size)
+{
+    return (size + 15) & ~15;
+}
+
+static const double Tau = 2 * M_PI;
+static const double BipBopDuration = 0.07;
+static const double BipBopVolume = 0.5;
+static const double BipFrequency = 1500;
+static const double BopFrequency = 500;
+static const double HumFrequency = 150;
+static const double HumVolume = 0.1;
+
+template <typename AudioSampleType>
+static void writeHum(float amplitude, float frequency, float sampleRate, AudioSampleType *p, uint64_t count)
+{
+    float humPeriod = sampleRate / frequency;
+    for (uint64_t i = 0; i < count; ++i)
+        *p++ = amplitude * sin(i * Tau / humPeriod);
+}
+
+template <typename AudioSampleType>
+static void addHum(float amplitude, float frequency, float sampleRate, uint64_t start, AudioSampleType *p, uint64_t count)
+{
+    float humPeriod = sampleRate / frequency;
+    for (uint64_t i = start, end = start + count; i < end; ++i) {
+        AudioSampleType a = amplitude * sin(i * Tau / humPeriod);
+        a += *p;
+        *p++ = a;
+    }
+}
+
+CaptureSourceOrError MockRealtimeAudioSource::create(String&& deviceID, String&& name, String&& hashSalt, const MediaConstraints* constraints)
+{
+#ifndef NDEBUG
+    auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
+    ASSERT(device);
+    if (!device)
+        return { };
+#endif
+    return CoreAudioCaptureSource::createForTesting(WTFMove(deviceID),  WTFMove(name), WTFMove(hashSalt), constraints, MockAudioSharedUnit::singleton());
+}
+
+MockAudioSharedUnit& MockAudioSharedUnit::singleton()
+{
+    static NeverDestroyed<MockAudioSharedUnit> singleton;
+    return singleton;
+}
+
+MockAudioSharedUnit::MockAudioSharedUnit()
+    : m_timer(RunLoop::current(), this, &MockAudioSharedUnit::tick)
+    , m_workQueue(WorkQueue::create("MockAudioSharedUnit Capture Queue"))
+{
+    setSampleRate(AudioSession::sharedSession().sampleRate());
+    setEnableEchoCancellation(false);
+}
+
+bool MockAudioSharedUnit::hasAudioUnit() const
+{
+    return m_hasAudioUnit;
+}
+
+void MockAudioSharedUnit::setCaptureDevice(String&&, uint32_t)
+{
+    reconfigureAudioUnit();
+}
+
+OSStatus MockAudioSharedUnit::reconfigureAudioUnit()
+{
+    if (!hasAudioUnit())
+        return 0;
+
+    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 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());
+
+    auto rate = sampleRate();
+    ASSERT(rate);
+
+    m_maximiumFrameCount = WTF::roundUpToPowerOfTwo(renderInterval().seconds() * rate * 2);
+    ASSERT(m_maximiumFrameCount);
+
+    const int bytesPerFloat = sizeof(Float32);
+    const int bitsPerByte = 8;
+    const int channelCount = m_channelCount;
+    const bool isFloat = true;
+    const bool isBigEndian = false;
+    const bool isNonInterleaved = true;
+    FillOutASBDForLPCM(m_streamFormat, rate, channelCount, bitsPerByte * bytesPerFloat, bitsPerByte * bytesPerFloat, isFloat, isBigEndian, isNonInterleaved);
+
+    m_audioBufferList = makeUnique<WebAudioBufferList>(m_streamFormat, m_streamFormat.mBytesPerFrame * m_maximiumFrameCount);
+
+    CMFormatDescriptionRef formatDescription;
+    CMAudioFormatDescriptionCreate(NULL, &m_streamFormat, 0, NULL, 0, NULL, NULL, &formatDescription);
+    m_formatDescription = adoptCF(formatDescription);
+
+    size_t sampleCount = 2 * rate;
+    m_bipBopBuffer.resize(sampleCount);
+    m_bipBopBuffer.fill(0);
+
+    size_t bipBopSampleCount = ceil(BipBopDuration * rate);
+    size_t bipStart = 0;
+    size_t bopStart = rate;
+
+    addHum(BipBopVolume, BipFrequency, rate, 0, m_bipBopBuffer.data() + bipStart, bipBopSampleCount);
+    addHum(BipBopVolume, BopFrequency, rate, 0, m_bipBopBuffer.data() + bopStart, bipBopSampleCount);
+}
+
+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())
+        reconfigure();
+
+    uint32_t totalFrameCount = alignTo16Bytes(delta.seconds() * sampleRate());
+    uint32_t frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
+
+    while (frameCount) {
+        uint32_t bipBopStart = m_samplesRendered % m_bipBopBuffer.size();
+        uint32_t bipBopRemain = m_bipBopBuffer.size() - bipBopStart;
+        uint32_t bipBopCount = std::min(frameCount, bipBopRemain);
+        for (auto& audioBuffer : m_audioBufferList->buffers()) {
+            audioBuffer.mDataByteSize = frameCount * m_streamFormat.mBytesPerFrame;
+            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;
+        totalFrameCount -= bipBopCount;
+        frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

Deleted: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h (252659 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.h	2019-11-20 00:50:51 UTC (rev 252660)
@@ -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)
-

Deleted: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm (252659 => 252660)


--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm	2019-11-20 00:50:07 UTC (rev 252659)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm	2019-11-20 00:50:51 UTC (rev 252660)
@@ -1,200 +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 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.
- *
- * 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.
- */
-
-#import "config.h"
-#import "MockRealtimeAudioSourceMac.h"
-
-#if ENABLE(MEDIA_STREAM)
-#import "AudioSampleBufferList.h"
-#import "CAAudioStreamDescription.h"
-#import "MediaConstraints.h"
-#import "MediaSampleAVFObjC.h"
-#import "MockRealtimeMediaSourceCenter.h"
-#import "NotImplemented.h"
-#import "RealtimeMediaSourceSettings.h"
-#import "WebAudioBufferList.h"
-#import "WebAudioSourceProviderAVFObjC.h"
-#import <AVFoundation/AVAudioBuffer.h>
-#import <AudioToolbox/AudioConverter.h>
-#import <CoreAudio/CoreAudioTypes.h>
-
-#import <pal/cf/CoreMediaSoftLink.h>
-
-SOFT_LINK_FRAMEWORK(AudioToolbox)
-
-SOFT_LINK(AudioToolbox, AudioConverterNew, OSStatus, (const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat, AudioConverterRef* outAudioConverter), (inSourceFormat, inDestinationFormat, outAudioConverter))
-
-namespace WebCore {
-using namespace PAL;
-
-static inline size_t alignTo16Bytes(size_t size)
-{
-    return (size + 15) & ~15;
-}
-
-static const double Tau = 2 * M_PI;
-static const double BipBopDuration = 0.07;
-static const double BipBopVolume = 0.5;
-static const double BipFrequency = 1500;
-static const double BopFrequency = 500;
-static const double HumFrequency = 150;
-static const double HumVolume = 0.1;
-
-template <typename AudioSampleType>
-static void writeHum(float amplitude, float frequency, float sampleRate, AudioSampleType *p, uint64_t count)
-{
-    float humPeriod = sampleRate / frequency;
-    for (uint64_t i = 0; i < count; ++i)
-        *p++ = amplitude * sin(i * Tau / humPeriod);
-}
-
-template <typename AudioSampleType>
-static void addHum(float amplitude, float frequency, float sampleRate, uint64_t start, AudioSampleType *p, uint64_t count)
-{
-    float humPeriod = sampleRate / frequency;
-    for (uint64_t i = start, end = start + count; i < end; ++i) {
-        AudioSampleType a = amplitude * sin(i * Tau / humPeriod);
-        a += *p;
-        *p++ = a;
-    }
-}
-
-CaptureSourceOrError MockRealtimeAudioSource::create(String&& deviceID, String&& name, String&& hashSalt, const MediaConstraints* constraints)
-{
-#ifndef NDEBUG
-    auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
-    ASSERT(device);
-    if (!device)
-        return { };
-#endif
-
-    auto source = adoptRef(*new MockRealtimeAudioSourceMac(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)));
-    // FIXME: We should report error messages
-    if (constraints && source->applyConstraints(*constraints))
-        return { };
-
-    return CaptureSourceOrError(WTFMove(source));
-}
-
-MockRealtimeAudioSourceMac::MockRealtimeAudioSourceMac(String&& deviceID, String&& name, String&& hashSalt)
-    : MockRealtimeAudioSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
-{
-    ASSERT(isMainThread());
-}
-
-void MockRealtimeAudioSourceMac::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 MockRealtimeAudioSourceMac::reconfigure()
-{
-    ASSERT(!isMainThread());
-
-    auto rate = sampleRate();
-    ASSERT(rate);
-
-    m_maximiumFrameCount = WTF::roundUpToPowerOfTwo(renderInterval().seconds() * rate * 2);
-    ASSERT(m_maximiumFrameCount);
-
-    const int bytesPerFloat = sizeof(Float32);
-    const int bitsPerByte = 8;
-    const int channelCount = m_channelCount;
-    const bool isFloat = true;
-    const bool isBigEndian = false;
-    const bool isNonInterleaved = true;
-    FillOutASBDForLPCM(m_streamFormat, rate, channelCount, bitsPerByte * bytesPerFloat, bitsPerByte * bytesPerFloat, isFloat, isBigEndian, isNonInterleaved);
-
-    m_audioBufferList = makeUnique<WebAudioBufferList>(m_streamFormat, m_streamFormat.mBytesPerFrame * m_maximiumFrameCount);
-
-    CMFormatDescriptionRef formatDescription;
-    CMAudioFormatDescriptionCreate(NULL, &m_streamFormat, 0, NULL, 0, NULL, NULL, &formatDescription);
-    m_formatDescription = adoptCF(formatDescription);
-
-    size_t sampleCount = 2 * rate;
-    m_bipBopBuffer.resize(sampleCount);
-    m_bipBopBuffer.fill(0);
-
-    size_t bipBopSampleCount = ceil(BipBopDuration * rate);
-    size_t bipStart = 0;
-    size_t bopStart = rate;
-
-    addHum(BipBopVolume, BipFrequency, rate, 0, m_bipBopBuffer.data() + bipStart, bipBopSampleCount);
-    addHum(BipBopVolume, BopFrequency, rate, 0, m_bipBopBuffer.data() + bopStart, bipBopSampleCount);
-}
-
-void MockRealtimeAudioSourceMac::render(Seconds delta)
-{
-    ASSERT(!isMainThread());
-    if (!m_audioBufferList || !m_bipBopBuffer.size())
-        reconfigure();
-
-    uint32_t totalFrameCount = alignTo16Bytes(delta.seconds() * sampleRate());
-    uint32_t frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
-
-    while (frameCount) {
-        uint32_t bipBopStart = m_samplesRendered % m_bipBopBuffer.size();
-        uint32_t bipBopRemain = m_bipBopBuffer.size() - bipBopStart;
-        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);
-        }
-        emitSampleBuffers(bipBopCount);
-        m_samplesRendered += bipBopCount;
-        totalFrameCount -= bipBopCount;
-        frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
-    }
-}
-
-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)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to