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, ¶m, 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, µphoneProcFormat, 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)