- Revision
- 228310
- Author
- [email protected]
- Date
- 2018-02-08 21:05:22 -0800 (Thu, 08 Feb 2018)
Log Message
CoreAudioCaptureSourceIOSListener should be a WebProcess singleton
https://bugs.webkit.org/show_bug.cgi?id=182606
<rdar://problem/37355283>
Patch by Youenn Fablet <[email protected]> on 2018-02-08
Reviewed by Eric Carlson.
Not testable right now as this relies on iOS specific Core Audio stack.
Efforts should be made to somehow mock that part and mock interruptions.
Made CoreAudioCaptureSourceFactoryIOS responsible to receive iOS interruption messages.
Before the patch, individual capture sources were receiving these messages.
When there is only one capture source per process this is fine but with more capture sources,
this is messing up things as they all share the same shared unit and we would try to interrupt it or resume it several times.
Also, if we are suspended and there is no more capture source, the shared unit will remain suspended indefinitely, as we will
not process the interruption messages.
With the patch, we always process the messages.
We still go through the active source as done now to limit the changes.
In case of no source, we go to the shared unit.
In the future, we should directly go to the shared unit and clients of the shared unit should see their state being updated.
As a way to prevent staying suspended on iOS, we unsuspend ourselves in CoreAudioCaptureSource constructor.
This is fine as this constructor is only called when getUserMedia grants access to the camera which always goes to the UIProcess.
And the UIProcess is only processing getUserMedia calls if the WebProcess is foregrounded.
* platform/mediastream/ios/CoreAudioCaptureSourceIOS.h:
* platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm:
(-[WebCoreAudioCaptureSourceIOSListener initWithCallback:]):
(WebCore::CoreAudioCaptureSourceFactoryIOS::CoreAudioCaptureSourceFactoryIOS):
(WebCore::CoreAudioCaptureSourceFactoryIOS::~CoreAudioCaptureSourceFactoryIOS):
(WebCore::CoreAudioCaptureSourceFactory::singleton):
* platform/mediastream/mac/CoreAudioCaptureSource.cpp:
(WebCore::CoreAudioCaptureSourceFactory::singleton):
(WebCore::CoreAudioCaptureSource::create):
(WebCore::CoreAudioCaptureSourceFactory::beginInterruption):
(WebCore::CoreAudioCaptureSourceFactory::endInterruption):
(WebCore::CoreAudioCaptureSourceFactory::scheduleReconfiguration):
(WebCore::CoreAudioCaptureSource::factory):
(WebCore::CoreAudioCaptureSource::CoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::~CoreAudioCaptureSource):
(WebCore::CoreAudioCaptureSource::startProducingData):
(WebCore::CoreAudioCaptureSource::scheduleReconfiguration):
(WebCore::CoreAudioCaptureSource::beginInterruption):
(WebCore::CoreAudioCaptureSource::endInterruption):
* platform/mediastream/mac/CoreAudioCaptureSource.h:
(WebCore::CoreAudioCaptureSourceFactory::setCoreAudioActiveSource):
(WebCore::CoreAudioCaptureSourceFactory::unsetCoreAudioActiveSource):
(WebCore::CoreAudioCaptureSourceFactory::coreAudioActiveSource):
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (228309 => 228310)
--- trunk/Source/WebCore/ChangeLog 2018-02-09 04:16:52 UTC (rev 228309)
+++ trunk/Source/WebCore/ChangeLog 2018-02-09 05:05:22 UTC (rev 228310)
@@ -1,3 +1,54 @@
+2018-02-08 Youenn Fablet <[email protected]>
+
+ CoreAudioCaptureSourceIOSListener should be a WebProcess singleton
+ https://bugs.webkit.org/show_bug.cgi?id=182606
+ <rdar://problem/37355283>
+
+ Reviewed by Eric Carlson.
+
+ Not testable right now as this relies on iOS specific Core Audio stack.
+ Efforts should be made to somehow mock that part and mock interruptions.
+
+ Made CoreAudioCaptureSourceFactoryIOS responsible to receive iOS interruption messages.
+ Before the patch, individual capture sources were receiving these messages.
+ When there is only one capture source per process this is fine but with more capture sources,
+ this is messing up things as they all share the same shared unit and we would try to interrupt it or resume it several times.
+
+ Also, if we are suspended and there is no more capture source, the shared unit will remain suspended indefinitely, as we will
+ not process the interruption messages.
+ With the patch, we always process the messages.
+ We still go through the active source as done now to limit the changes.
+ In case of no source, we go to the shared unit.
+ In the future, we should directly go to the shared unit and clients of the shared unit should see their state being updated.
+
+ As a way to prevent staying suspended on iOS, we unsuspend ourselves in CoreAudioCaptureSource constructor.
+ This is fine as this constructor is only called when getUserMedia grants access to the camera which always goes to the UIProcess.
+ And the UIProcess is only processing getUserMedia calls if the WebProcess is foregrounded.
+
+ * platform/mediastream/ios/CoreAudioCaptureSourceIOS.h:
+ * platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm:
+ (-[WebCoreAudioCaptureSourceIOSListener initWithCallback:]):
+ (WebCore::CoreAudioCaptureSourceFactoryIOS::CoreAudioCaptureSourceFactoryIOS):
+ (WebCore::CoreAudioCaptureSourceFactoryIOS::~CoreAudioCaptureSourceFactoryIOS):
+ (WebCore::CoreAudioCaptureSourceFactory::singleton):
+ * platform/mediastream/mac/CoreAudioCaptureSource.cpp:
+ (WebCore::CoreAudioCaptureSourceFactory::singleton):
+ (WebCore::CoreAudioCaptureSource::create):
+ (WebCore::CoreAudioCaptureSourceFactory::beginInterruption):
+ (WebCore::CoreAudioCaptureSourceFactory::endInterruption):
+ (WebCore::CoreAudioCaptureSourceFactory::scheduleReconfiguration):
+ (WebCore::CoreAudioCaptureSource::factory):
+ (WebCore::CoreAudioCaptureSource::CoreAudioCaptureSource):
+ (WebCore::CoreAudioCaptureSource::~CoreAudioCaptureSource):
+ (WebCore::CoreAudioCaptureSource::startProducingData):
+ (WebCore::CoreAudioCaptureSource::scheduleReconfiguration):
+ (WebCore::CoreAudioCaptureSource::beginInterruption):
+ (WebCore::CoreAudioCaptureSource::endInterruption):
+ * platform/mediastream/mac/CoreAudioCaptureSource.h:
+ (WebCore::CoreAudioCaptureSourceFactory::setCoreAudioActiveSource):
+ (WebCore::CoreAudioCaptureSourceFactory::unsetCoreAudioActiveSource):
+ (WebCore::CoreAudioCaptureSourceFactory::coreAudioActiveSource):
+
2018-02-08 Chris Dumez <[email protected]>
There should be a way to disable [OverrideBuiltins] behavior in a given DOMWrapperWorld
Modified: trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.h (228309 => 228310)
--- trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.h 2018-02-09 04:16:52 UTC (rev 228309)
+++ trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.h 2018-02-09 05:05:22 UTC (rev 228310)
@@ -33,13 +33,12 @@
namespace WebCore {
-class CoreAudioCaptureSourceIOS final : public CoreAudioCaptureSource {
+class CoreAudioCaptureSourceFactoryIOS final : public CoreAudioCaptureSourceFactory {
+public:
+ CoreAudioCaptureSourceFactoryIOS();
+ ~CoreAudioCaptureSourceFactoryIOS();
+
private:
- friend class CoreAudioCaptureSource;
-
- CoreAudioCaptureSourceIOS(const String& deviceID, const String& label);
- ~CoreAudioCaptureSourceIOS();
-
RetainPtr<WebCoreAudioCaptureSourceIOSListener> m_listener;
};
Modified: trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm (228309 => 228310)
--- trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm 2018-02-09 04:16:52 UTC (rev 228309)
+++ trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm 2018-02-09 05:05:22 UTC (rev 228310)
@@ -50,7 +50,7 @@
using namespace WebCore;
@interface WebCoreAudioCaptureSourceIOSListener : NSObject {
- CoreAudioCaptureSourceIOS* _callback;
+ CoreAudioCaptureSourceFactoryIOS* _callback;
}
- (void)invalidate;
@@ -59,7 +59,7 @@
@end
@implementation WebCoreAudioCaptureSourceIOSListener
-- (id)initWithCallback:(CoreAudioCaptureSourceIOS*)callback
+- (id)initWithCallback:(CoreAudioCaptureSourceFactoryIOS*)callback
{
self = [super init];
if (!self)
@@ -122,18 +122,23 @@
namespace WebCore {
-CoreAudioCaptureSourceIOS::CoreAudioCaptureSourceIOS(const String& deviceID, const String& label)
- : CoreAudioCaptureSource(deviceID, label, 0)
- , m_listener(adoptNS([[WebCoreAudioCaptureSourceIOSListener alloc] initWithCallback:this]))
+CoreAudioCaptureSourceFactoryIOS::CoreAudioCaptureSourceFactoryIOS()
+ : m_listener(adoptNS([[WebCoreAudioCaptureSourceIOSListener alloc] initWithCallback:this]))
{
}
-CoreAudioCaptureSourceIOS::~CoreAudioCaptureSourceIOS()
+CoreAudioCaptureSourceFactoryIOS::~CoreAudioCaptureSourceFactoryIOS()
{
[m_listener invalidate];
m_listener = nullptr;
}
+CoreAudioCaptureSourceFactory& CoreAudioCaptureSourceFactory::singleton()
+{
+ static NeverDestroyed<CoreAudioCaptureSourceFactoryIOS> factory;
+ return factory.get();
}
+}
+
#endif // ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp (228309 => 228310)
--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp 2018-02-09 04:16:52 UTC (rev 228309)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp 2018-02-09 05:05:22 UTC (rev 228310)
@@ -53,20 +53,13 @@
namespace WebCore {
using namespace PAL;
-class CoreAudioCaptureSourceFactory : public RealtimeMediaSource::AudioCaptureFactory
+#if PLATFORM(MAC)
+CoreAudioCaptureSourceFactory& CoreAudioCaptureSourceFactory::singleton()
{
-public:
- CaptureSourceOrError createAudioCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
- {
- return CoreAudioCaptureSource::create(device.persistentId(), constraints);
- }
-};
-
-static CoreAudioCaptureSourceFactory& coreAudioCaptureSourceFactory()
-{
static NeverDestroyed<CoreAudioCaptureSourceFactory> factory;
return factory.get();
}
+#endif
const UInt32 outputBus = 0;
const UInt32 inputBus = 1;
@@ -697,7 +690,7 @@
if (!device)
return { };
- auto source = adoptRef(*new CoreAudioCaptureSourceIOS(deviceID, device->label()));
+ auto source = adoptRef(*new CoreAudioCaptureSource(deviceID, device->label(), 0));
#endif
if (constraints) {
@@ -708,9 +701,60 @@
return CaptureSourceOrError(WTFMove(source));
}
+void CoreAudioCaptureSourceFactory::beginInterruption()
+{
+ if (!isMainThread()) {
+ callOnMainThread([this] {
+ beginInterruption();
+ });
+ return;
+ }
+ ASSERT(isMainThread());
+
+ if (auto* source = coreAudioActiveSource()) {
+ source->beginInterruption();
+ return;
+ }
+ CoreAudioSharedUnit::singleton().suspend();
+}
+
+void CoreAudioCaptureSourceFactory::endInterruption()
+{
+ if (!isMainThread()) {
+ callOnMainThread([this] {
+ endInterruption();
+ });
+ return;
+ }
+ ASSERT(isMainThread());
+
+ if (auto* source = coreAudioActiveSource()) {
+ source->endInterruption();
+ return;
+ }
+ CoreAudioSharedUnit::singleton().reconfigureAudioUnit();
+}
+
+void CoreAudioCaptureSourceFactory::scheduleReconfiguration()
+{
+ if (!isMainThread()) {
+ callOnMainThread([this] {
+ scheduleReconfiguration();
+ });
+ return;
+ }
+ ASSERT(isMainThread());
+
+ if (auto* source = coreAudioActiveSource()) {
+ source->scheduleReconfiguration();
+ return;
+ }
+ CoreAudioSharedUnit::singleton().reconfigureAudioUnit();
+}
+
RealtimeMediaSource::AudioCaptureFactory& CoreAudioCaptureSource::factory()
{
- return coreAudioCaptureSourceFactory();
+ return CoreAudioCaptureSourceFactory::singleton();
}
CoreAudioCaptureSource::CoreAudioCaptureSource(const String& deviceID, const String& label, uint32_t persistentID)
@@ -724,12 +768,19 @@
initializeVolume(unit.volume());
unit.addClient(*this);
+
+#if PLATFORM(IOS)
+ // 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.
+ if (unit.isSuspended())
+ unit.reconfigureAudioUnit();
+#endif
}
CoreAudioCaptureSource::~CoreAudioCaptureSource()
{
#if PLATFORM(IOS)
- coreAudioCaptureSourceFactory().unsetActiveSource(*this);
+ CoreAudioCaptureSourceFactory::singleton().unsetCoreAudioActiveSource(*this);
#endif
CoreAudioSharedUnit::singleton().removeClient(*this);
@@ -748,7 +799,7 @@
void CoreAudioCaptureSource::startProducingData()
{
#if PLATFORM(IOS)
- coreAudioCaptureSourceFactory().setActiveSource(*this);
+ CoreAudioCaptureSourceFactory::singleton().setCoreAudioActiveSource(*this);
#endif
auto& unit = CoreAudioSharedUnit::singleton();
@@ -844,17 +895,6 @@
void CoreAudioCaptureSource::scheduleReconfiguration()
{
- if (!isMainThread()) {
- callOnMainThread([weakThis = createWeakPtr(), this] {
- if (!weakThis)
- return;
-
- scheduleReconfiguration();
- });
-
- return;
- }
-
ASSERT(isMainThread());
auto& unit = CoreAudioSharedUnit::singleton();
if (!unit.hasAudioUnit() || m_reconfigurationState != ReconfigurationState::None)
@@ -874,17 +914,6 @@
void CoreAudioCaptureSource::beginInterruption()
{
- if (!isMainThread()) {
- callOnMainThread([weakThis = createWeakPtr(), this] {
- if (!weakThis)
- return;
-
- beginInterruption();
- });
-
- return;
- }
-
ASSERT(isMainThread());
auto& unit = CoreAudioSharedUnit::singleton();
if (!unit.hasAudioUnit() || unit.isSuspended() || m_suspendPending)
@@ -900,17 +929,6 @@
void CoreAudioCaptureSource::endInterruption()
{
- if (!isMainThread()) {
- callOnMainThread([weakThis = createWeakPtr(), this] {
- if (!weakThis)
- return;
-
- endInterruption();
- });
-
- return;
- }
-
ASSERT(isMainThread());
auto& unit = CoreAudioSharedUnit::singleton();
if (!unit.hasAudioUnit() || !unit.isSuspended() || m_resumePending)
Modified: trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h (228309 => 228310)
--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h 2018-02-09 04:16:52 UTC (rev 228309)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h 2018-02-09 05:05:22 UTC (rev 228310)
@@ -110,6 +110,29 @@
bool m_resumePending { false };
};
+class CoreAudioCaptureSourceFactory : public RealtimeMediaSource::AudioCaptureFactory {
+public:
+ static CoreAudioCaptureSourceFactory& singleton();
+
+ void beginInterruption();
+ void endInterruption();
+ void scheduleReconfiguration();
+
+#if PLATFORM(IOS)
+ void setCoreAudioActiveSource(CoreAudioCaptureSource& source) { setActiveSource(source); }
+ void unsetCoreAudioActiveSource(CoreAudioCaptureSource& source) { unsetActiveSource(source); }
+ CoreAudioCaptureSource* coreAudioActiveSource() { return static_cast<CoreAudioCaptureSource*>(activeSource()); }
+#else
+ CoreAudioCaptureSource* coreAudioActiveSource() { return nullptr; }
+#endif
+
+private:
+ CaptureSourceOrError createAudioCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
+ {
+ return CoreAudioCaptureSource::create(device.persistentId(), constraints);
+ }
+};
+
} // namespace WebCore
#endif // ENABLE(MEDIA_STREAM)