Title: [215201] trunk/Source
Revision
215201
Author
commit-qu...@webkit.org
Date
2017-04-10 14:24:13 -0700 (Mon, 10 Apr 2017)

Log Message

Add CoreAudioCaptureSource.
https://bugs.webkit.org/show_bug.cgi?id=170112
rdar://problem/30293338

Patch by Jeremy Jones <jere...@apple.com> on 2017-04-10
Source/WebCore:

Reviewed by Eric Carlson.

No new tests because this provides the same funcitonality as AVAudioCaptureSource.
Funcionality is covered by existing test cases.

Add CoreAudioCaptureSource for audio capture. And use it by default in AVCaptureDeviceManager.
Add UseAVFoundationAudioCapture setting to switch back to AVFoundation for audio capture.

* WebCore.xcodeproj/project.pbxproj:
* page/Settings.cpp:
(WebCore::Settings::useAVFoundationAudioCapture):
(WebCore::Settings::setUseAVFoundationAudioCapture):
* page/Settings.h:
* platform/mediastream/mac/AVCaptureDeviceManager.h:
* platform/mediastream/mac/AVCaptureDeviceManager.mm:
(WebCore::AVCaptureDeviceManager::setUseAVFoundationAudioCapture):
* platform/mediastream/mac/CoreAudioCaptureSource.cpp: Added.
(WebCore::CoreAudioCaptureSource::create):
(WebCore::CoreAudioCaptureSource::factory):
(WebCore::CoreAudioCaptureSource::CoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::~CoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::preferredSampleRate):
(WebCore::CoreAudioCaptureSource::preferredIOBufferDuration):
(WebCore::CoreAudioCaptureSource::configureMicrophoneProc):
(WebCore::CoreAudioCaptureSource::configureSpeakerProc):
(WebCore::CoreAudioCaptureSource::addMicrophoneDataConsumer):
(WebCore::CoreAudioCaptureSource::removeMicrophoneDataConsumer):
(WebCore::CoreAudioCaptureSource::addEchoCancellationSource):
(WebCore::CoreAudioCaptureSource::removeEchoCancellationSource):
(WebCore::CoreAudioCaptureSource::checkTimestamps):
(WebCore::CoreAudioCaptureSource::provideSpeakerData):
(WebCore::CoreAudioCaptureSource::speakerCallback):
(WebCore::CoreAudioCaptureSource::processMicrophoneSamples):
(WebCore::CoreAudioCaptureSource::microphoneCallback):
(WebCore::CoreAudioCaptureSource::defaultOutputDevice):
(WebCore::CoreAudioCaptureSource::defaultInputDevice):
(WebCore::CoreAudioCaptureSource::setupAudioUnits):
(WebCore::CoreAudioCaptureSource::startProducingData):
(WebCore::CoreAudioCaptureSource::stopProducingData):
(WebCore::CoreAudioCaptureSource::suspend):
(WebCore::CoreAudioCaptureSource::resume):
(WebCore::CoreAudioCaptureSource::capabilities):
(WebCore::CoreAudioCaptureSource::settings):
* platform/mediastream/mac/CoreAudioCaptureSource.h: Added.
* platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp:
(WebCore::RealtimeMediaSourceCenterMac::RealtimeMediaSourceCenterMac):
(WebCore::RealtimeMediaSourceCenterMac::defaultAudioFactory):

Source/WebKit/mac:

Reviewed by Eric Carlson.

Add UseAVFoundationAudioCapture preference to switch back from the new default of CoreAudio.

* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences useAVFoundationAudioCapture]):
(-[WebPreferences setUseAVFoundationAudioCapture:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):

Source/WebKit2:

Reviewed by Tim Horton.

Add UseAVFoundationAudioCapture preference to switch back from the new default of CoreAudio.

* Shared/WebPreferencesDefinitions.h:
* UIProcess/API/C/WKPreferences.cpp:
(WKPreferencesSetUseAVFoundationAudioCapture):
(WKPreferencesGetUseAVFoundationAudioCapture):
* UIProcess/API/C/WKPreferencesRefPrivate.h:
* UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp:
(WebKit::UserMediaCaptureManagerProxy::createMediaSourceForCaptureDeviceWithConstraints):
* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::syncWithWebCorePrefs):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::updatePreferences):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (215200 => 215201)


--- trunk/Source/WebCore/ChangeLog	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/ChangeLog	2017-04-10 21:24:13 UTC (rev 215201)
@@ -1,3 +1,57 @@
+2017-04-10  Jeremy Jones  <jere...@apple.com>
+
+        Add CoreAudioCaptureSource.
+        https://bugs.webkit.org/show_bug.cgi?id=170112
+        rdar://problem/30293338
+
+        Reviewed by Eric Carlson.
+
+        No new tests because this provides the same funcitonality as AVAudioCaptureSource. 
+        Funcionality is covered by existing test cases.
+
+        Add CoreAudioCaptureSource for audio capture. And use it by default in AVCaptureDeviceManager.
+        Add UseAVFoundationAudioCapture setting to switch back to AVFoundation for audio capture.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/Settings.cpp:
+        (WebCore::Settings::useAVFoundationAudioCapture):
+        (WebCore::Settings::setUseAVFoundationAudioCapture):
+        * page/Settings.h:
+        * platform/mediastream/mac/AVCaptureDeviceManager.h:
+        * platform/mediastream/mac/AVCaptureDeviceManager.mm:
+        (WebCore::AVCaptureDeviceManager::setUseAVFoundationAudioCapture):
+        * platform/mediastream/mac/CoreAudioCaptureSource.cpp: Added.
+        (WebCore::CoreAudioCaptureSource::create):
+        (WebCore::CoreAudioCaptureSource::factory):
+        (WebCore::CoreAudioCaptureSource::CoreAudioCaptureSource):
+        (WebCore::CoreAudioCaptureSource::~CoreAudioCaptureSource):
+        (WebCore::CoreAudioCaptureSource::preferredSampleRate):
+        (WebCore::CoreAudioCaptureSource::preferredIOBufferDuration):
+        (WebCore::CoreAudioCaptureSource::configureMicrophoneProc):
+        (WebCore::CoreAudioCaptureSource::configureSpeakerProc):
+        (WebCore::CoreAudioCaptureSource::addMicrophoneDataConsumer):
+        (WebCore::CoreAudioCaptureSource::removeMicrophoneDataConsumer):
+        (WebCore::CoreAudioCaptureSource::addEchoCancellationSource):
+        (WebCore::CoreAudioCaptureSource::removeEchoCancellationSource):
+        (WebCore::CoreAudioCaptureSource::checkTimestamps):
+        (WebCore::CoreAudioCaptureSource::provideSpeakerData):
+        (WebCore::CoreAudioCaptureSource::speakerCallback):
+        (WebCore::CoreAudioCaptureSource::processMicrophoneSamples):
+        (WebCore::CoreAudioCaptureSource::microphoneCallback):
+        (WebCore::CoreAudioCaptureSource::defaultOutputDevice):
+        (WebCore::CoreAudioCaptureSource::defaultInputDevice):
+        (WebCore::CoreAudioCaptureSource::setupAudioUnits):
+        (WebCore::CoreAudioCaptureSource::startProducingData):
+        (WebCore::CoreAudioCaptureSource::stopProducingData):
+        (WebCore::CoreAudioCaptureSource::suspend):
+        (WebCore::CoreAudioCaptureSource::resume):
+        (WebCore::CoreAudioCaptureSource::capabilities):
+        (WebCore::CoreAudioCaptureSource::settings):
+        * platform/mediastream/mac/CoreAudioCaptureSource.h: Added.
+        * platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp:
+        (WebCore::RealtimeMediaSourceCenterMac::RealtimeMediaSourceCenterMac):
+        (WebCore::RealtimeMediaSourceCenterMac::defaultAudioFactory):
+
 2017-04-10  Youenn Fablet  <you...@apple.com>
 
         Wrap legacy MediaStream API in runtime flag

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (215200 => 215201)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-04-10 21:24:13 UTC (rev 215201)
@@ -73,7 +73,7 @@
 		070334E9145A1F36008D8D45 /* JSTrackCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 070334E8145A1F35008D8D45 /* JSTrackCustom.cpp */; };
 		070363E0181A1CDC00C074A5 /* AVAudioCaptureSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 070363D8181A1CDC00C074A5 /* AVAudioCaptureSource.h */; };
 		070363E1181A1CDC00C074A5 /* AVAudioCaptureSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 070363D9181A1CDC00C074A5 /* AVAudioCaptureSource.mm */; };
-		070363E2181A1CDC00C074A5 /* AVCaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 070363DA181A1CDC00C074A5 /* AVCaptureDeviceManager.h */; };
+		070363E2181A1CDC00C074A5 /* AVCaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 070363DA181A1CDC00C074A5 /* AVCaptureDeviceManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		070363E3181A1CDC00C074A5 /* AVCaptureDeviceManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 070363DB181A1CDC00C074A5 /* AVCaptureDeviceManager.mm */; };
 		070363E4181A1CDC00C074A5 /* AVMediaCaptureSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 070363DC181A1CDC00C074A5 /* AVMediaCaptureSource.h */; };
 		070363E5181A1CDC00C074A5 /* AVMediaCaptureSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 070363DD181A1CDC00C074A5 /* AVMediaCaptureSource.mm */; };
@@ -274,7 +274,7 @@
 		07B5A30D14687D7100A81ECE /* JSTextTrackListCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07B5A30C14687D7100A81ECE /* JSTextTrackListCustom.cpp */; };
 		07B7116D1D899E63009F0FFB /* CaptureDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116A1D899E63009F0FFB /* CaptureDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07B7116E1D899E63009F0FFB /* CaptureDeviceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07B7116B1D899E63009F0FFB /* CaptureDeviceManager.cpp */; };
-		07B7116F1D899E63009F0FFB /* CaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */; };
+		07B7116F1D899E63009F0FFB /* CaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07C046C31E42508B007201E7 /* CAAudioStreamDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */; };
 		07C046C41E42508B007201E7 /* CAAudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07C046C81E425155007201E7 /* AudioTrackPrivateMediaStreamCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C046C61E42512F007201E7 /* AudioTrackPrivateMediaStreamCocoa.h */; };
@@ -1673,6 +1673,7 @@
 		3F42B31E1881191B00278AAC /* WebVideoFullscreenControllerAVKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3F42B31C1881191B00278AAC /* WebVideoFullscreenControllerAVKit.mm */; };
 		3FBC4AF3189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3FBC4AF1189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.mm */; };
 		3FBC4AF4189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FBC4AF2189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		3FF1FA661E7350FD00C1002F /* CoreAudioCaptureSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F3BB5821E709EE400C701F2 /* CoreAudioCaptureSource.cpp */; };
 		3FF813A71DBA8640009BF001 /* PointerLockController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CFC434F192406A900A0D3B5 /* PointerLockController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		3FFFF9A8159D9A550020BBD5 /* WebKitCSSViewportRule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FFFF9A6159D9A550020BBD5 /* WebKitCSSViewportRule.cpp */; };
 		3FFFF9A9159D9A550020BBD5 /* WebKitCSSViewportRule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FFFF9A7159D9A550020BBD5 /* WebKitCSSViewportRule.h */; };
@@ -9257,6 +9258,8 @@
 		3F2B33E3165ABD3500E3987C /* WebKitCSSViewportRule.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebKitCSSViewportRule.idl; sourceTree = "<group>"; };
 		3F2B33E9165AF15500E3987C /* JSWebKitCSSViewportRule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebKitCSSViewportRule.cpp; sourceTree = "<group>"; };
 		3F2B33EA165AF15500E3987C /* JSWebKitCSSViewportRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebKitCSSViewportRule.h; sourceTree = "<group>"; };
+		3F3BB5821E709EE400C701F2 /* CoreAudioCaptureSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CoreAudioCaptureSource.cpp; sourceTree = "<group>"; };
+		3F3BB5831E709EE400C701F2 /* CoreAudioCaptureSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreAudioCaptureSource.h; sourceTree = "<group>"; };
 		3F42B31B1881191B00278AAC /* WebVideoFullscreenControllerAVKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVideoFullscreenControllerAVKit.h; sourceTree = "<group>"; };
 		3F42B31C1881191B00278AAC /* WebVideoFullscreenControllerAVKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebVideoFullscreenControllerAVKit.mm; sourceTree = "<group>"; };
 		3FBC4AF1189881560046EE38 /* WebVideoFullscreenInterfaceAVKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebVideoFullscreenInterfaceAVKit.mm; sourceTree = "<group>"; };
@@ -16117,6 +16120,8 @@
 				070363DD181A1CDC00C074A5 /* AVMediaCaptureSource.mm */,
 				070363DE181A1CDC00C074A5 /* AVVideoCaptureSource.h */,
 				070363DF181A1CDC00C074A5 /* AVVideoCaptureSource.mm */,
+				3F3BB5821E709EE400C701F2 /* CoreAudioCaptureSource.cpp */,
+				3F3BB5831E709EE400C701F2 /* CoreAudioCaptureSource.h */,
 				0744ECEB1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.h */,
 				0744ECEC1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.mm */,
 				07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */,
@@ -30618,6 +30623,7 @@
 				E13F01F11270E19000DFBA71 /* CookieStorageMac.mm in Sources */,
 				9746AF2114F4DDE6003E7A72 /* Coordinates.cpp in Sources */,
 				443817FF1A91B2F8006E04F2 /* CoreMediaSoftLink.cpp in Sources */,
+				3FF1FA661E7350FD00C1002F /* CoreAudioCaptureSource.cpp in Sources */,
 				CD7D33471C7A16BF00041293 /* CoreVideoSoftLink.cpp in Sources */,
 				BC5EB9500E82056B00B25965 /* CounterDirectives.cpp in Sources */,
 				9392F1500AD1862300691BD4 /* CounterNode.cpp in Sources */,

Modified: trunk/Source/WebCore/page/Settings.cpp (215200 => 215201)


--- trunk/Source/WebCore/page/Settings.cpp	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/page/Settings.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -48,6 +48,10 @@
 #include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
 
+#if ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION)
+#include "AVCaptureDeviceManager.h"
+#endif
+
 #if ENABLE(MEDIA_STREAM)
 #include "MockRealtimeMediaSourceCenter.h"
 #endif
@@ -94,6 +98,7 @@
 #if ENABLE(MEDIA_STREAM)
 bool Settings::gMockCaptureDevicesEnabled = false;
 bool Settings::gMediaCaptureRequiresSecureConnection = true;
+bool Settings::gUseAVFoundationAudioCapture = false;
 #endif
 
 #if PLATFORM(WIN)
@@ -615,7 +620,20 @@
 {
     gMediaCaptureRequiresSecureConnection = mediaCaptureRequiresSecureConnection;
 }
+
+bool Settings::useAVFoundationAudioCapture()
+{
+    return gUseAVFoundationAudioCapture;
+}
+
+void Settings::setUseAVFoundationAudioCapture(bool useAVFoundationAudioCapture)
+{
+    gUseAVFoundationAudioCapture = useAVFoundationAudioCapture;
+#if USE(AVFOUNDATION)
+    AVCaptureDeviceManager::setUseAVFoundationAudioCapture(useAVFoundationAudioCapture);
 #endif
+}
+#endif
 
 void Settings::setScrollingPerformanceLoggingEnabled(bool enabled)
 {

Modified: trunk/Source/WebCore/page/Settings.h (215200 => 215201)


--- trunk/Source/WebCore/page/Settings.h	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/page/Settings.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -310,6 +310,9 @@
 
     bool mediaCaptureRequiresSecureConnection() const;
     WEBCORE_EXPORT static void setMediaCaptureRequiresSecureConnection(bool);
+
+    static bool useAVFoundationAudioCapture();
+    WEBCORE_EXPORT static void setUseAVFoundationAudioCapture(bool);
 #endif
 
 #if ENABLE(APPLE_PAY)
@@ -415,6 +418,7 @@
     String m_mediaDeviceIdentifierStorageDirectory;
     static bool gMockCaptureDevicesEnabled;
     static bool gMediaCaptureRequiresSecureConnection;
+    static bool gUseAVFoundationAudioCapture;
 #endif
 
 #if ENABLE(APPLE_PAY)

Modified: trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h (215200 => 215201)


--- trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -45,6 +45,8 @@
 class AVCaptureDeviceManager final : public CaptureDeviceManager {
     friend class NeverDestroyed<AVCaptureDeviceManager>;
 public:
+    WEBCORE_EXPORT static void setUseAVFoundationAudioCapture(bool);
+
     Vector<CaptureDevice>& captureDevices() final;
 
     static AVCaptureDeviceManager& singleton();

Modified: trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm (215200 => 215201)


--- trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm	2017-04-10 21:24:13 UTC (rev 215201)
@@ -32,6 +32,7 @@
 #import "AVMediaCaptureSource.h"
 #import "AVVideoCaptureSource.h"
 #import "AudioSourceProvider.h"
+#import "CoreAudioCaptureSource.h"
 #import "Logging.h"
 #import "MediaConstraints.h"
 #import "RealtimeMediaSource.h"
@@ -92,6 +93,19 @@
 
 namespace WebCore {
 
+void AVCaptureDeviceManager::setUseAVFoundationAudioCapture(bool enabled)
+{
+    static bool active = false;
+    if (active == enabled)
+        return;
+
+    active = enabled;
+    if (active)
+        RealtimeMediaSourceCenter::singleton().setAudioFactory(AVAudioCaptureSource::factory());
+    else
+        RealtimeMediaSourceCenter::singleton().setAudioFactory(CoreAudioCaptureSource::factory());
+}
+
 Vector<CaptureDevice>& AVCaptureDeviceManager::captureDevices()
 {
     if (!isAvailable())

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


--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2017 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 "CoreAudioCaptureSource.h"
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "AudioSampleBufferList.h"
+#include "AudioSampleDataSource.h"
+#include "Logging.h"
+#include "MediaTimeAVFoundation.h"
+#include <AudioToolbox/AudioConverter.h>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreMedia/CMSync.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#include <wtf/NeverDestroyed.h>
+#include "CoreMediaSoftLink.h"
+
+namespace WebCore {
+
+class CoreAudioCaptureSourceFactory : public RealtimeMediaSource::CaptureFactory {
+public:
+    RefPtr<RealtimeMediaSource> createMediaSourceForCaptureDeviceWithConstraints(const CaptureDevice& captureDevice, const MediaConstraints* constraints, String& invalidConstraint) final {
+        return CoreAudioCaptureSource::create(captureDevice, constraints, invalidConstraint);
+    }
+};
+
+const UInt32 outputBus = 0;
+const UInt32 inputBus = 1;
+
+RefPtr<CoreAudioCaptureSource> CoreAudioCaptureSource::create(const CaptureDevice& deviceInfo, const MediaConstraints* constraints, String& invalidConstraint)
+{
+    auto source = adoptRef(new CoreAudioCaptureSource(deviceInfo));
+    if (constraints) {
+        auto result = source->applyConstraints(*constraints);
+        if (result) {
+            invalidConstraint = result.value().first;
+            return nullptr;
+        }
+    }
+
+    return source;
+}
+
+
+RealtimeMediaSource::CaptureFactory& CoreAudioCaptureSource::factory()
+{
+    static NeverDestroyed<CoreAudioCaptureSourceFactory> factory;
+    return factory.get();
+}
+
+
+CoreAudioCaptureSource::CoreAudioCaptureSource(const CaptureDevice& deviceInfo)
+    : RealtimeMediaSource(emptyString(), RealtimeMediaSource::Type::Audio, deviceInfo.label())
+    , m_captureDeviceID(0)
+{
+    // FIXME: use deviceInfo to set the m_captureDeviceID
+
+    setPersistentID(deviceInfo.persistentId());
+    setMuted(true);
+
+    m_currentSettings.setVolume(1.0);
+    m_currentSettings.setSampleRate(preferredSampleRate());
+    m_currentSettings.setDeviceId(id());
+    m_currentSettings.setEchoCancellation(true);
+
+    mach_timebase_info_data_t timebaseInfo;
+    mach_timebase_info(&timebaseInfo);
+    m_DTSConversionRatio = 1e-9 * static_cast<double>(timebaseInfo.numer) / static_cast<double>(timebaseInfo.denom);
+}
+
+CoreAudioCaptureSource::~CoreAudioCaptureSource()
+{
+    suspend();
+
+    std::lock_guard<Lock> lock(m_internalStateLock);
+
+    if (m_ioUnit)
+        AudioComponentInstanceDispose(m_ioUnit);
+
+    m_ioUnitName = emptyString();
+
+    m_microphoneSampleBuffer = nullptr;
+    m_speakerSampleBuffer = nullptr;
+
+    m_speakerProcsCalled = 0;
+    m_microphoneProcsCalled  = 0;
+    m_latestMicTimeStamp = 0;
+
+    m_activeSources.clear();
+    m_pendingSources.clear();
+
+    m_speakerSampleBuffer = nullptr;
+
+    m_ioUnitInitialized = false;
+    m_ioUnitStarted  = false;
+}
+
+double CoreAudioCaptureSource::preferredSampleRate()
+{
+    // FIXME: Get the preferred rate dynamically, kAUVoiceIOProperty_PreferredHWSampleRate/ [[AVAudioSession sharedInstance] preferredSampleRate]
+    static const float preferredRate = 24000.;
+    return preferredRate;
+}
+
+double CoreAudioCaptureSource::preferredIOBufferDuration()
+{
+    // FIXME: Get the preferred duration dynamically - kAUVoiceIOProperty_PreferredHWBlockSizeInSeconds / [[AVAudioSession sharedInstance] preferredIOBufferDuration]
+    static const float preferredDuration = 0.02;
+    return preferredDuration;
+}
+
+OSStatus CoreAudioCaptureSource::configureMicrophoneProc()
+{
+    AURenderCallbackStruct callback = { microphoneCallback, this };
+    auto err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, inputBus, &callback, sizeof(callback));
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::configureMicrophoneProc(%p) unable to set vpio unit mic proc, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    AudioStreamBasicDescription microphoneProcFormat = { };
+
+    UInt32 size = sizeof(microphoneProcFormat);
+    err = AudioUnitGetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &microphoneProcFormat, &size);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::configureMicrophoneProc(%p) unable to get output stream format, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    m_microphoneSampleBuffer = AudioSampleBufferList::create(microphoneProcFormat, preferredIOBufferDuration() * microphoneProcFormat.mSampleRate * 2);
+    m_microphoneProcFormat = microphoneProcFormat;
+
+    return err;
+}
+
+OSStatus CoreAudioCaptureSource::configureSpeakerProc()
+{
+    AURenderCallbackStruct callback = { speakerCallback, this };
+    auto err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, outputBus, &callback, sizeof(callback));
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::configureSpeakerProc(%p) unable to set vpio unit speaker proc, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    AudioStreamBasicDescription speakerProcFormat = { };
+
+    UInt32 size = sizeof(speakerProcFormat);
+    err  = AudioUnitGetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &speakerProcFormat, &size);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::configureSpeakerProc(%p) unable to get input stream format, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    m_speakerSampleBuffer = AudioSampleBufferList::create(speakerProcFormat, preferredIOBufferDuration() * speakerProcFormat.mSampleRate * 2);
+    m_speakerProcFormat = speakerProcFormat;
+
+    return err;
+}
+
+uint64_t CoreAudioCaptureSource::addMicrophoneDataConsumer(MicrophoneDataCallback&& callback)
+{
+    std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
+    m_microphoneDataCallbacks.add(++m_nextMicrophoneDataCallbackID, callback);
+
+    return m_nextMicrophoneDataCallbackID;
+}
+
+void CoreAudioCaptureSource::removeMicrophoneDataConsumer(uint64_t callbackID)
+{
+    std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
+    m_microphoneDataCallbacks.remove(callbackID);
+}    
+
+void CoreAudioCaptureSource::addEchoCancellationSource(AudioSampleDataSource& source)
+{
+    if (!source.setOutputFormat(m_speakerProcFormat)) {
+        LOG(Media, "CoreAudioCaptureSource::addEchoCancellationSource: source %p configureOutput failed", &source);
+        return;
+    }
+
+    std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
+    m_pendingSources.append({ QueueAction::Add, source });
+}
+
+void CoreAudioCaptureSource::removeEchoCancellationSource(AudioSampleDataSource& source)
+{
+    std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
+    m_pendingSources.append({ QueueAction::Remove, source });
+}
+
+void CoreAudioCaptureSource::checkTimestamps(const AudioTimeStamp& timeStamp, uint64_t sampleTime, double hostTime)
+{
+    if (!timeStamp.mSampleTime || sampleTime == m_latestMicTimeStamp || !hostTime)
+        LOG(Media, "CoreAudioCaptureSource::checkTimestamps: unusual timestamps, sample time = %lld, previous sample time = %lld, hostTime %f", sampleTime, m_latestMicTimeStamp, hostTime);
+}
+
+OSStatus CoreAudioCaptureSource::provideSpeakerData(AudioUnitRenderActionFlags& /*ioActionFlags*/, const AudioTimeStamp& timeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames, AudioBufferList* ioData)
+{
+    // Called when the audio unit needs data to play through the speakers.
+    ++m_speakerProcsCalled;
+
+    if (m_speakerSampleBuffer->sampleCapacity() < inNumberFrames) {
+        LOG(Media, "CoreAudioCaptureSource::provideSpeakerData: speaker sample buffer size (%d) too small for amount of sample data requested (%d)!", m_speakerSampleBuffer->sampleCapacity(), (int)inNumberFrames);
+        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;
+
+    double adjustedHostTime = m_DTSConversionRatio * timeStamp.mHostTime;
+    uint64_t sampleTime = timeStamp.mSampleTime;
+    checkTimestamps(timeStamp, sampleTime, adjustedHostTime);
+
+    m_speakerSampleBuffer->reset();
+    m_speakerSampleBuffer->setTimes(adjustedHostTime, sampleTime);
+
+    AudioBufferList& bufferList = m_speakerSampleBuffer->bufferList();
+    for (uint32_t i = 0; i < bufferList.mNumberBuffers; ++i)
+        bufferList.mBuffers[i] = ioData->mBuffers[i];
+
+    bool firstSource = true;
+    for (auto& source : m_activeSources) {
+        source->pullSamples(*m_speakerSampleBuffer.get(), inNumberFrames, adjustedHostTime, sampleTime, firstSource ? AudioSampleDataSource::Copy : AudioSampleDataSource::Mix);
+        firstSource = false;
+    }
+
+    return noErr;
+}
+
+OSStatus CoreAudioCaptureSource::speakerCallback(void *inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
+{
+    ASSERT(ioActionFlags);
+    ASSERT(inTimeStamp);
+    auto dataSource = static_cast<CoreAudioCaptureSource*>(inRefCon);
+    return dataSource->provideSpeakerData(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, ioData);
+}
+
+OSStatus CoreAudioCaptureSource::processMicrophoneSamples(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& timeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* /*ioData*/)
+{
+    ++m_microphoneProcsCalled;
+
+    // Pull through the vpio unit to our mic buffer.
+    m_microphoneSampleBuffer->reset();
+    AudioBufferList& bufferList = m_microphoneSampleBuffer->bufferList();
+    auto err = AudioUnitRender(m_ioUnit, &ioActionFlags, &timeStamp, inBusNumber, inNumberFrames, &bufferList);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::processMicrophoneSamples(%p) AudioUnitRender failed with error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    double adjustedHostTime = m_DTSConversionRatio * timeStamp.mHostTime;
+    uint64_t sampleTime = timeStamp.mSampleTime;
+    checkTimestamps(timeStamp, sampleTime, adjustedHostTime);
+    m_latestMicTimeStamp = sampleTime;
+
+    m_microphoneSampleBuffer->setTimes(adjustedHostTime, sampleTime);
+
+    audioSamplesAvailable(MediaTime(sampleTime, m_microphoneProcFormat.sampleRate()), m_microphoneSampleBuffer->bufferList(), m_microphoneProcFormat, inNumberFrames);
+
+    if (m_microphoneDataCallbacks.isEmpty())
+        return 0;
+
+    for (auto& callback : m_microphoneDataCallbacks.values())
+        callback(MediaTime(sampleTime, m_microphoneProcFormat.sampleRate()), m_microphoneSampleBuffer->bufferList(), m_microphoneProcFormat, inNumberFrames);
+
+    return noErr;
+}
+
+OSStatus CoreAudioCaptureSource::microphoneCallback(void *inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
+{
+    ASSERT(ioActionFlags);
+    ASSERT(inTimeStamp);
+    CoreAudioCaptureSource* dataSource = static_cast<CoreAudioCaptureSource*>(inRefCon);
+    return dataSource->processMicrophoneSamples(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, ioData);
+}
+
+OSStatus CoreAudioCaptureSource::defaultInputDevice(uint32_t* deviceID)
+{
+    ASSERT(m_ioUnit);
+
+    UInt32 propertySize = sizeof(*deviceID);
+    auto err = AudioUnitGetProperty(m_ioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, inputBus, deviceID, &propertySize);
+    if (err)
+        LOG(Media, "CoreAudioCaptureSource::defaultInputDevice(%p) unable to get default input device ID, error %d (%.4s)", this, (int)err, (char*)&err);
+
+    return err;
+}
+
+OSStatus CoreAudioCaptureSource::setupAudioUnits()
+{
+    ASSERT(m_internalStateLock.isHeld());
+
+    if (m_ioUnit)
+        return 0;
+
+    AudioComponentDescription ioUnitDescription = { kAudioUnitType_Output, kAudioUnitSubType_VoiceProcessingIO, kAudioUnitManufacturer_Apple, 0, 0 };
+    AudioComponent ioComponent = AudioComponentFindNext(nullptr, &ioUnitDescription);
+    ASSERT(ioComponent);
+    if (!ioComponent) {
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) unable to find vpio unit component", this);
+        return -1;
+    }
+
+    CFStringRef name = nullptr;
+    AudioComponentCopyName(ioComponent, &name);
+    if (name) {
+        m_ioUnitName = name;
+        CFRelease(name);
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) created \"%s\" component", this, m_ioUnitName.utf8().data());
+    }
+
+    auto err = AudioComponentInstanceNew(ioComponent, &m_ioUnit);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) unable to open vpio unit, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+#if PLATFORM(IOS)
+    uint32_t param = 1;
+    err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, inputBus, &param, sizeof(param));
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) unable to enable vpio unit input, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    param = 1;
+    err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, outputBus, &param, sizeof(param));
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) unable to enable vpio unit output, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+#endif
+
+    if (!m_captureDeviceID) {
+        err = defaultInputDevice(&m_captureDeviceID);
+        if (err)
+            return err;
+    }
+
+    UInt32 propertySize = sizeof(m_captureDeviceID);
+    err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, inputBus, &m_captureDeviceID, propertySize);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) unable to set vpio unit capture device ID, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+
+    err = configureMicrophoneProc();
+    if (err)
+        return err;
+
+    err = AudioUnitInitialize(m_ioUnit);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::setupAudioUnits(%p) AudioUnitInitialize() failed, error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+    m_ioUnitInitialized = true;
+
+    err = configureSpeakerProc();
+    if (err)
+        return err;
+
+    return err;
+}
+
+void CoreAudioCaptureSource::startProducingData()
+{
+    std::lock_guard<Lock> lock(m_internalStateLock);
+    if (m_ioUnitStarted)
+        return;
+
+    OSStatus err;
+    if (!m_ioUnit) {
+        err = setupAudioUnits();
+        if (err)
+            return;
+    }
+
+    err = AudioOutputUnitStart(m_ioUnit);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::start(%p) AudioOutputUnitStart failed with error %d (%.4s)", this, (int)err, (char*)&err);
+        return;
+    }
+
+    m_ioUnitStarted = true;
+    setMuted(false);
+}
+
+void CoreAudioCaptureSource::stopProducingData()
+{
+    std::lock_guard<Lock> lock(m_internalStateLock);
+
+    ASSERT(m_ioUnit);
+
+    auto err = AudioOutputUnitStop(m_ioUnit);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::stop(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
+        return;
+    }
+    m_ioUnitStarted = false;
+    setMuted(true);
+}
+
+OSStatus CoreAudioCaptureSource::suspend()
+{
+    std::lock_guard<Lock> lock(m_internalStateLock);
+
+    ASSERT(m_ioUnit);
+
+    if (m_ioUnitStarted) {
+        auto err = AudioOutputUnitStop(m_ioUnit);
+        if (err) {
+            LOG(Media, "CoreAudioCaptureSource::resume(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
+            return err;
+        }
+        m_ioUnitStarted = false;
+    }
+
+    if (m_ioUnitInitialized) {
+        auto err = AudioUnitUninitialize(m_ioUnit);
+        if (err) {
+            LOG(Media, "CoreAudioCaptureSource::resume(%p) AudioUnitUninitialize failed with error %d (%.4s)", this, (int)err, (char*)&err);
+            return err;
+        }
+        m_ioUnitInitialized = false;
+    }
+
+    return 0;
+}
+
+OSStatus CoreAudioCaptureSource::resume()
+{
+    std::lock_guard<Lock> lock(m_internalStateLock);
+
+    ASSERT(m_ioUnit);
+    ASSERT(!m_ioUnitStarted);
+
+    auto err = AudioOutputUnitStart(m_ioUnit);
+    if (err) {
+        LOG(Media, "CoreAudioCaptureSource::resume(%p) AudioOutputUnitStart failed with error %d (%.4s)", this, (int)err, (char*)&err);
+        return err;
+    }
+    m_ioUnitStarted = false;
+
+    return err;
+}
+
+RefPtr<RealtimeMediaSourceCapabilities> CoreAudioCaptureSource::capabilities() const
+{
+    if (m_capabilities)
+        return m_capabilities;
+
+    m_supportedConstraints.setSupportsDeviceId(true);
+    m_supportedConstraints.setSupportsEchoCancellation(true);
+    m_supportedConstraints.setSupportsVolume(true);
+
+    // FIXME: finish this.
+    m_capabilities = RealtimeMediaSourceCapabilities::create(m_supportedConstraints);
+    m_capabilities->setDeviceId(id());
+    m_capabilities->setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
+    m_capabilities->setVolume(CapabilityValueOrRange(0.0, 1.0));
+
+    return m_capabilities;
+}
+
+const RealtimeMediaSourceSettings& CoreAudioCaptureSource::settings() const
+{
+    return m_currentSettings;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

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


--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 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 "CAAudioStreamDescription.h"
+#include "CaptureDevice.h"
+#include "RealtimeMediaSource.h"
+#include <AudioToolbox/AudioToolbox.h>
+#include <CoreAudio/CoreAudioTypes.h>
+#include <wtf/HashMap.h>
+#include <wtf/Lock.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+typedef struct OpaqueCMClock* CMClockRef;
+
+namespace WTF {
+class MediaTime;
+}
+
+namespace WebCore {
+
+class AudioSampleBufferList;
+class AudioSampleDataSource;
+class CaptureDeviceInfo;
+
+class CoreAudioCaptureSource : public RealtimeMediaSource {
+public:
+
+    static RefPtr<CoreAudioCaptureSource> create(const CaptureDevice&, const MediaConstraints*, String&);
+
+    WEBCORE_EXPORT static CaptureFactory& factory();
+
+    void addEchoCancellationSource(AudioSampleDataSource&);
+    void removeEchoCancellationSource(AudioSampleDataSource&);
+
+    using MicrophoneDataCallback = std::function<void(const MediaTime& sampleTime, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t sampleCount)>;
+
+    uint64_t addMicrophoneDataConsumer(MicrophoneDataCallback&&);
+    void removeMicrophoneDataConsumer(uint64_t);
+
+    CMClockRef timebaseClock();
+
+private:
+    CoreAudioCaptureSource(const CaptureDevice&);
+    virtual ~CoreAudioCaptureSource();
+
+    void startProducingData() final;
+    void stopProducingData() final;
+    bool isProducingData() const final { return m_ioUnitStarted; }
+
+    OSStatus suspend();
+    OSStatus resume();
+
+    RefPtr<RealtimeMediaSourceCapabilities> capabilities() const final;
+    const RealtimeMediaSourceSettings& settings() const final;
+
+    OSStatus setupAudioUnits();
+    OSStatus configureSpeakerProc();
+    OSStatus configureMicrophoneProc();
+    OSStatus defaultOutputDevice(uint32_t*);
+    OSStatus defaultInputDevice(uint32_t*);
+
+    void checkTimestamps(const AudioTimeStamp&, uint64_t, double);
+
+    static OSStatus microphoneCallback(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
+    OSStatus processMicrophoneSamples(AudioUnitRenderActionFlags&, const AudioTimeStamp&, UInt32, UInt32, AudioBufferList*);
+
+    static OSStatus speakerCallback(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
+    OSStatus provideSpeakerData(AudioUnitRenderActionFlags&, const AudioTimeStamp&, UInt32, UInt32, AudioBufferList*);
+
+    static double preferredSampleRate();
+    static double preferredIOBufferDuration();
+
+    AudioUnit m_ioUnit { nullptr };
+    String m_ioUnitName;
+
+    // Only read/modified from the IO thread.
+    Vector<Ref<AudioSampleDataSource>> m_activeSources;
+
+    enum QueueAction { Add, Remove };
+    Vector<std::pair<QueueAction, Ref<AudioSampleDataSource>>> m_pendingSources;
+
+    uint32_t m_captureDeviceID { 0 };
+
+    CAAudioStreamDescription m_microphoneProcFormat;
+    RefPtr<AudioSampleBufferList> m_microphoneSampleBuffer;
+    uint64_t m_microphoneProcsCalled { 0 };
+    uint64_t m_latestMicTimeStamp { 0 };
+
+    HashMap<uint64_t, MicrophoneDataCallback> m_microphoneDataCallbacks;
+    uint64_t m_nextMicrophoneDataCallbackID { 0 };
+
+    CAAudioStreamDescription m_speakerProcFormat;
+    RefPtr<AudioSampleBufferList> m_speakerSampleBuffer;
+    uint64_t m_speakerProcsCalled { 0 };
+
+    double m_DTSConversionRatio { 0 };
+
+    bool m_ioUnitInitialized { false };
+    bool m_ioUnitStarted { false };
+
+    Lock m_pendingSourceQueueLock;
+    Lock m_internalStateLock;
+
+    mutable RefPtr<RealtimeMediaSourceCapabilities> m_capabilities;
+    mutable RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
+    RealtimeMediaSourceSettings m_currentSettings;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp (215200 => 215201)


--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -33,9 +33,9 @@
 #if ENABLE(MEDIA_STREAM)
 #include "RealtimeMediaSourceCenterMac.h"
 
-#include "AVAudioCaptureSource.h"
 #include "AVCaptureDeviceManager.h"
 #include "AVVideoCaptureSource.h"
+#include "CoreAudioCaptureSource.h"
 #include "Logging.h"
 #include "MediaStreamPrivate.h"
 #include <wtf/MainThread.h>
@@ -63,7 +63,7 @@
     m_supportedConstraints.setSupportsDeviceId(true);
     m_supportedConstraints.setSupportsGroupId(true);
 
-    m_audioFactory = &AVAudioCaptureSource::factory();
+    m_audioFactory = &CoreAudioCaptureSource::factory();
     m_videoFactory = &AVVideoCaptureSource::factory();
 }
 
@@ -174,7 +174,7 @@
 
 RealtimeMediaSource::CaptureFactory* RealtimeMediaSourceCenterMac::defaultAudioFactory()
 {
-    return &AVAudioCaptureSource::factory();
+    return &CoreAudioCaptureSource::factory();
 }
 
 RealtimeMediaSource::CaptureFactory* RealtimeMediaSourceCenterMac::defaultVideoFactory()

Modified: trunk/Source/WebKit/mac/ChangeLog (215200 => 215201)


--- trunk/Source/WebKit/mac/ChangeLog	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit/mac/ChangeLog	2017-04-10 21:24:13 UTC (rev 215201)
@@ -1,3 +1,22 @@
+2017-04-10  Jeremy Jones  <jere...@apple.com>
+
+        Add CoreAudioCaptureSource.
+        https://bugs.webkit.org/show_bug.cgi?id=170112
+        rdar://problem/30293338
+
+        Reviewed by Eric Carlson.
+
+        Add UseAVFoundationAudioCapture preference to switch back from the new default of CoreAudio.
+
+        * WebView/WebPreferenceKeysPrivate.h:
+        * WebView/WebPreferences.mm:
+        (+[WebPreferences initialize]):
+        (-[WebPreferences useAVFoundationAudioCapture]):
+        (-[WebPreferences setUseAVFoundationAudioCapture:]):
+        * WebView/WebPreferencesPrivate.h:
+        * WebView/WebView.mm:
+        (-[WebView _preferencesChanged:]):
+
 2017-04-10  Chris Dumez  <cdu...@apple.com>
 
         Drop Timer::startOneShot() overload taking a double

Modified: trunk/Source/WebKit/mac/WebView/WebPreferenceKeysPrivate.h (215200 => 215201)


--- trunk/Source/WebKit/mac/WebView/WebPreferenceKeysPrivate.h	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit/mac/WebView/WebPreferenceKeysPrivate.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -224,6 +224,7 @@
 #define WebKitEnableInheritURIQueryComponentPreferenceKey @"WebKitEnableInheritURIQueryComponent"
 #define WebKitMediaDataLoadsAutomaticallyPreferenceKey @"WebKitMediaDataLoadsAutomatically"
 #define WebKitMockCaptureDevicesEnabledPreferenceKey @"WebKitMockCaptureDevicesEnabled"
+#define WebKitUseAVFoundationAudioCapturePreferenceKey @"WebKitUseAVFoundationAudioCaptureEnabled"
 #define WebKitEnumeratingAllNetworkInterfacesEnabledPreferenceKey @"WebKitEnumeratingAllNetworkInterfacesEnabled"
 #define WebKitICECandidateFilteringEnabledPreferenceKey @"WebKitICECandidateFilteringEnabled"
 #define WebKitMediaCaptureRequiresSecureConnectionPreferenceKey @"WebKitMediaCaptureRequiresSecureConnection"

Modified: trunk/Source/WebKit/mac/WebView/WebPreferences.mm (215200 => 215201)


--- trunk/Source/WebKit/mac/WebView/WebPreferences.mm	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit/mac/WebView/WebPreferences.mm	2017-04-10 21:24:13 UTC (rev 215201)
@@ -619,6 +619,7 @@
 #if ENABLE(MEDIA_STREAM)
         [NSNumber numberWithBool:NO], WebKitMockCaptureDevicesEnabledPreferenceKey,
         [NSNumber numberWithBool:YES], WebKitMediaCaptureRequiresSecureConnectionPreferenceKey,
+        [NSNumber numberWithBool:NO], WebKitUseAVFoundationAudioCapturePreferenceKey,
 #endif
         [NSNumber numberWithBool:YES], WebKitShadowDOMEnabledPreferenceKey,
         [NSNumber numberWithBool:YES], WebKitCustomElementsEnabledPreferenceKey,
@@ -2866,6 +2867,16 @@
     [self _setBoolValue:flag forKey:WebKitMockCaptureDevicesEnabledPreferenceKey];
 }
 
+- (BOOL)useAVFoundationAudioCapture
+{
+    return [self _boolValueForKey:WebKitUseAVFoundationAudioCapturePreferenceKey];
+}
+
+- (void)setUseAVFoundationAudioCapture:(BOOL)flag
+{
+    [self _setBoolValue:flag forKey:WebKitUseAVFoundationAudioCapturePreferenceKey];
+}
+
 - (BOOL)enumeratingAllNetworkInterfacesEnabled
 {
     return [self _boolValueForKey:WebKitEnumeratingAllNetworkInterfacesEnabledPreferenceKey];

Modified: trunk/Source/WebKit/mac/WebView/WebPreferencesPrivate.h (215200 => 215201)


--- trunk/Source/WebKit/mac/WebView/WebPreferencesPrivate.h	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit/mac/WebView/WebPreferencesPrivate.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -511,6 +511,9 @@
 - (void)setMediaCaptureRequiresSecureConnection:(BOOL)flag;
 - (BOOL)mediaCaptureRequiresSecureConnection;
 
+- (void)setUseAVFoundationAudioCapture:(BOOL)flag;
+- (BOOL)useAVFoundationAudioCapture;
+
 - (void)setShadowDOMEnabled:(BOOL)flag;
 - (BOOL)shadowDOMEnabled;
 

Modified: trunk/Source/WebKit/mac/WebView/WebView.mm (215200 => 215201)


--- trunk/Source/WebKit/mac/WebView/WebView.mm	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit/mac/WebView/WebView.mm	2017-04-10 21:24:13 UTC (rev 215201)
@@ -2964,6 +2964,7 @@
     settings.setMockCaptureDevicesEnabled([preferences mockCaptureDevicesEnabled]);
     settings.setMediaCaptureRequiresSecureConnection([preferences mediaCaptureRequiresSecureConnection]);
     RuntimeEnabledFeatures::sharedFeatures().setMediaStreamEnabled([preferences mediaStreamEnabled]);
+    settings.setUseAVFoundationAudioCapture([preferences useAVFoundationAudioCapture]);
 #endif
 
 #if ENABLE(WEB_RTC)

Modified: trunk/Source/WebKit2/ChangeLog (215200 => 215201)


--- trunk/Source/WebKit2/ChangeLog	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/ChangeLog	2017-04-10 21:24:13 UTC (rev 215201)
@@ -1,3 +1,25 @@
+2017-04-10  Jeremy Jones  <jere...@apple.com>
+
+        Add CoreAudioCaptureSource.
+        https://bugs.webkit.org/show_bug.cgi?id=170112
+        rdar://problem/30293338
+
+        Reviewed by Tim Horton.
+
+        Add UseAVFoundationAudioCapture preference to switch back from the new default of CoreAudio.
+
+        * Shared/WebPreferencesDefinitions.h:
+        * UIProcess/API/C/WKPreferences.cpp:
+        (WKPreferencesSetUseAVFoundationAudioCapture):
+        (WKPreferencesGetUseAVFoundationAudioCapture):
+        * UIProcess/API/C/WKPreferencesRefPrivate.h:
+        * UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp:
+        (WebKit::UserMediaCaptureManagerProxy::createMediaSourceForCaptureDeviceWithConstraints):
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        (WebKit::UserMediaPermissionRequestManagerProxy::syncWithWebCorePrefs):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::updatePreferences):
+
 2017-04-10  Brent Fulgham  <bfulg...@apple.com>
 
         [WK2][macOS] Block access to Apple Events before launch.

Modified: trunk/Source/WebKit2/Shared/WebPreferencesDefinitions.h (215200 => 215201)


--- trunk/Source/WebKit2/Shared/WebPreferencesDefinitions.h	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/Shared/WebPreferencesDefinitions.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -241,6 +241,7 @@
     macro(HTTPEquivEnabled, httpEquivEnabled, Bool, bool, true, "", "") \
     macro(MockCaptureDevicesEnabled, mockCaptureDevicesEnabled, Bool, bool, false, "", "") \
     macro(MediaCaptureRequiresSecureConnection, mediaCaptureRequiresSecureConnection, Bool, bool, true, "", "") \
+    macro(UseAVFoundationAudioCapture, useAVFoundationAudioCapture, Bool, bool, false, "", "") \
     macro(EnumeratingAllNetworkInterfacesEnabled, enumeratingAllNetworkInterfacesEnabled, Bool, bool, false, "", "") \
     macro(WebRTCLegacyAPIEnabled, webRTCLegacyAPIEnabled, Bool, bool, true, "", "") \
     macro(ICECandidateFilteringEnabled, iceCandidateFilteringEnabled, Bool, bool, true, "", "") \

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp (215200 => 215201)


--- trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -1601,6 +1601,16 @@
     return toImpl(preferencesRef)->mediaCaptureRequiresSecureConnection();
 }
 
+void WKPreferencesSetUseAVFoundationAudioCapture(WKPreferencesRef preferencesRef, bool enabled)
+{
+    toImpl(preferencesRef)->setUseAVFoundationAudioCapture(enabled);
+}
+
+bool WKPreferencesGetUseAVFoundationAudioCapture(WKPreferencesRef preferencesRef)
+{
+    return toImpl(preferencesRef)->useAVFoundationAudioCapture();
+}
+
 void WKPreferencesSetFetchAPIEnabled(WKPreferencesRef preferencesRef, bool flag)
 {
     toImpl(preferencesRef)->setFetchAPIEnabled(flag);

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h (215200 => 215201)


--- trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h	2017-04-10 21:24:13 UTC (rev 215201)
@@ -433,6 +433,10 @@
 WK_EXPORT void WKPreferencesSetMediaCaptureRequiresSecureConnection(WKPreferencesRef, bool);
 WK_EXPORT bool WKPreferencesGetMediaCaptureRequiresSecureConnection(WKPreferencesRef);
 
+// Defaults to false.
+WK_EXPORT void WKPreferencesSetUseAVFoundationAudioCapture(WKPreferencesRef, bool);
+WK_EXPORT bool WKPreferencesGetUseAVFoundationAudioCapture(WKPreferencesRef);
+    
 // Defaults to false
 WK_EXPORT void WKPreferencesSetFetchAPIEnabled(WKPreferencesRef, bool flag);
 WK_EXPORT bool WKPreferencesGetFetchAPIEnabled(WKPreferencesRef);

Modified: trunk/Source/WebKit2/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp (215200 => 215201)


--- trunk/Source/WebKit2/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -128,7 +128,7 @@
 void UserMediaCaptureManagerProxy::createMediaSourceForCaptureDeviceWithConstraints(uint64_t id, const CaptureDevice& device, const MediaConstraintsData& constraintsData, bool& succeeded, String& invalidConstraints)
 {
     auto constraints = MediaConstraintsImpl::create(constraintsData);
-    RefPtr<RealtimeMediaSource> source = RealtimeMediaSourceCenter::singleton().defaultAudioFactory()->createMediaSourceForCaptureDeviceWithConstraints(device, constraints.ptr(), invalidConstraints);
+    auto source = RealtimeMediaSourceCenter::singleton().audioFactory()->createMediaSourceForCaptureDeviceWithConstraints(device, constraints.ptr(), invalidConstraints);
     succeeded = !!source;
     
     if (source)

Modified: trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (215200 => 215201)


--- trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -31,6 +31,10 @@
 #include <WebCore/RealtimeMediaSource.h>
 #include <WebCore/SecurityOriginData.h>
 
+#if ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION)
+#include <WebCore/AVCaptureDeviceManager.h>
+#endif
+
 using namespace WebCore;
 
 namespace WebKit {
@@ -329,7 +333,12 @@
     // this is a noop if the preference hasn't changed since the last time this was called.
     bool mockDevicesEnabled = m_page.preferences().mockCaptureDevicesEnabled();
     WebCore::MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(mockDevicesEnabled);
+
+#if USE(AVFOUNDATION)
+    bool useAVFoundationAudioCapture = m_page.preferences().useAVFoundationAudioCapture();
+    WebCore::AVCaptureDeviceManager::setUseAVFoundationAudioCapture(useAVFoundationAudioCapture);
 #endif
+#endif
 }
 
 void UserMediaPermissionRequestManagerProxy::stopCapture()

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (215200 => 215201)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2017-04-10 21:02:16 UTC (rev 215200)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2017-04-10 21:24:13 UTC (rev 215201)
@@ -3240,6 +3240,7 @@
 #if ENABLE(MEDIA_STREAM)
     settings.setMockCaptureDevicesEnabled(store.getBoolValueForKey(WebPreferencesKey::mockCaptureDevicesEnabledKey()));
     settings.setMediaCaptureRequiresSecureConnection(store.getBoolValueForKey(WebPreferencesKey::mediaCaptureRequiresSecureConnectionKey()));
+    settings.setUseAVFoundationAudioCapture(store.getBoolValueForKey(WebPreferencesKey::useAVFoundationAudioCaptureKey()));
 #endif
 
     settings.setShouldConvertPositionStyleOnCopy(store.getBoolValueForKey(WebPreferencesKey::shouldConvertPositionStyleOnCopyKey()));
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to