Title: [218746] trunk/Source/WebCore
Revision
218746
Author
[email protected]
Date
2017-06-23 08:40:05 -0700 (Fri, 23 Jun 2017)

Log Message

[iOS] Respond to AudioSession interruption and resume
https://bugs.webkit.org/show_bug.cgi?id=173718
<rdar://problem/32925263>

Reviewed by Youenn Fablet.

Tested manually.

* WebCore.xcodeproj/project.pbxproj: Add CoreAudioCaptureSourceIOS.mm/.h

* platform/mediastream/RealtimeMediaSource.h: Make createWeakPtr protected so derived classes
can use it.

* platform/mediastream/ios/CoreAudioCaptureSourceIOS.h: Added.
* platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm: Added.
(-[WebCoreAudioCaptureSourceIOSListener initWithCallback:]):
(-[WebCoreAudioCaptureSourceIOSListener invalidate]):
(-[WebCoreAudioCaptureSourceIOSListener handleInterruption:]):
(-[WebCoreAudioCaptureSourceIOSListener sessionMediaServicesWereReset:]):
(WebCore::CoreAudioCaptureSourceIOS::CoreAudioCaptureSourceIOS):
(WebCore::CoreAudioCaptureSourceIOS::~CoreAudioCaptureSourceIOS):

* platform/mediastream/mac/CoreAudioCaptureSource.cpp:
(WebCore::CoreAudioSharedUnit::suspended):
(WebCore::CoreAudioSharedUnit::setupAudioUnit): Clear m_suspended.
(WebCore::CoreAudioSharedUnit::suspend): Don't clear sources or uninitialize the audio unit,
suspend is temporary. Set m_suspended.
(WebCore::CoreAudioSharedUnit::resume): New, restart the audio unit.
(WebCore::CoreAudioCaptureSource::create): Create the correct object.
(WebCore::CoreAudioCaptureSource::scheduleReconfiguration): Dispatch to main thread if necessary.
(WebCore::CoreAudioCaptureSource::beginInterruption): New, suspend from main thread.
(WebCore::CoreAudioCaptureSource::endInterruption): New, resume/reconfigure from main thread.
(WebCore::CoreAudioCaptureSource::interrupted):
* platform/mediastream/mac/CoreAudioCaptureSource.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (218745 => 218746)


--- trunk/Source/WebCore/ChangeLog	2017-06-23 12:08:00 UTC (rev 218745)
+++ trunk/Source/WebCore/ChangeLog	2017-06-23 15:40:05 UTC (rev 218746)
@@ -1,3 +1,40 @@
+2017-06-23  Eric Carlson  <[email protected]>
+
+        [iOS] Respond to AudioSession interruption and resume
+        https://bugs.webkit.org/show_bug.cgi?id=173718
+        <rdar://problem/32925263>
+
+        Reviewed by Youenn Fablet.
+
+        Tested manually.
+
+        * WebCore.xcodeproj/project.pbxproj: Add CoreAudioCaptureSourceIOS.mm/.h
+
+        * platform/mediastream/RealtimeMediaSource.h: Make createWeakPtr protected so derived classes
+        can use it.
+
+        * platform/mediastream/ios/CoreAudioCaptureSourceIOS.h: Added.
+        * platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm: Added.
+        (-[WebCoreAudioCaptureSourceIOSListener initWithCallback:]):
+        (-[WebCoreAudioCaptureSourceIOSListener invalidate]):
+        (-[WebCoreAudioCaptureSourceIOSListener handleInterruption:]):
+        (-[WebCoreAudioCaptureSourceIOSListener sessionMediaServicesWereReset:]):
+        (WebCore::CoreAudioCaptureSourceIOS::CoreAudioCaptureSourceIOS):
+        (WebCore::CoreAudioCaptureSourceIOS::~CoreAudioCaptureSourceIOS):
+
+        * platform/mediastream/mac/CoreAudioCaptureSource.cpp:
+        (WebCore::CoreAudioSharedUnit::suspended): 
+        (WebCore::CoreAudioSharedUnit::setupAudioUnit): Clear m_suspended.
+        (WebCore::CoreAudioSharedUnit::suspend): Don't clear sources or uninitialize the audio unit,
+        suspend is temporary. Set m_suspended.
+        (WebCore::CoreAudioSharedUnit::resume): New, restart the audio unit.
+        (WebCore::CoreAudioCaptureSource::create): Create the correct object.
+        (WebCore::CoreAudioCaptureSource::scheduleReconfiguration): Dispatch to main thread if necessary.
+        (WebCore::CoreAudioCaptureSource::beginInterruption): New, suspend from main thread.
+        (WebCore::CoreAudioCaptureSource::endInterruption): New, resume/reconfigure from main thread.
+        (WebCore::CoreAudioCaptureSource::interrupted):
+        * platform/mediastream/mac/CoreAudioCaptureSource.h:
+
 2017-06-23  Zan Dobersek  <[email protected]>
 
         [GCrypt] Drop the AES-CFB support

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (218745 => 218746)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-06-23 12:08:00 UTC (rev 218745)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-06-23 15:40:05 UTC (rev 218746)
@@ -261,6 +261,8 @@
 		07ABEF6E1D8A1C7600F21972 /* MediaDevicesEnumerationRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 07ABEF6D1D8A1C7600F21972 /* MediaDevicesEnumerationRequest.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07AC47011952102100EE9723 /* ISOVTTCue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07AC46FF1952102100EE9723 /* ISOVTTCue.cpp */; };
 		07AC47021952102100EE9723 /* ISOVTTCue.h in Headers */ = {isa = PBXBuildFile; fileRef = 07AC47001952102100EE9723 /* ISOVTTCue.h */; };
+		07AFF4221EFB144900B545B3 /* CoreAudioCaptureSourceIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 07AFF4201EFB144700B545B3 /* CoreAudioCaptureSourceIOS.h */; };
+		07AFF4231EFB144900B545B3 /* CoreAudioCaptureSourceIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07AFF4211EFB144700B545B3 /* CoreAudioCaptureSourceIOS.mm */; };
 		07B0113F1032242200FBDC33 /* AccessibilityMediaControls.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B0113E1032242200FBDC33 /* AccessibilityMediaControls.h */; };
 		07B0ABCF1032242200FBDC33 /* AccessibilityMathMLElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B0ABCE1032242200FBDC33 /* AccessibilityMathMLElement.h */; };
 		07B442D6166C70B000556CAD /* InbandTextTrackPrivateAVF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07B442D4166C70B000556CAD /* InbandTextTrackPrivateAVF.cpp */; };
@@ -7687,6 +7689,8 @@
 		07ABEF6D1D8A1C7600F21972 /* MediaDevicesEnumerationRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaDevicesEnumerationRequest.h; sourceTree = "<group>"; };
 		07AC46FF1952102100EE9723 /* ISOVTTCue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ISOVTTCue.cpp; sourceTree = "<group>"; };
 		07AC47001952102100EE9723 /* ISOVTTCue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOVTTCue.h; sourceTree = "<group>"; };
+		07AFF4201EFB144700B545B3 /* CoreAudioCaptureSourceIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreAudioCaptureSourceIOS.h; sourceTree = "<group>"; };
+		07AFF4211EFB144700B545B3 /* CoreAudioCaptureSourceIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreAudioCaptureSourceIOS.mm; sourceTree = "<group>"; };
 		07B0113E1032242200FBDC33 /* AccessibilityMediaControls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityMediaControls.h; sourceTree = "<group>"; };
 		07B0ABCE1032242200FBDC33 /* AccessibilityMathMLElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityMathMLElement.h; sourceTree = "<group>"; };
 		07B442D4166C70B000556CAD /* InbandTextTrackPrivateAVF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InbandTextTrackPrivateAVF.cpp; sourceTree = "<group>"; };
@@ -24466,6 +24470,8 @@
 				CDC675241EAEA9D400727C84 /* AVAudioSessionCaptureDevice.mm */,
 				CDC675211EAEA9B700727C84 /* AVAudioSessionCaptureDeviceManager.h */,
 				CDC675201EAEA9B700727C84 /* AVAudioSessionCaptureDeviceManager.mm */,
+				07AFF4201EFB144700B545B3 /* CoreAudioCaptureSourceIOS.h */,
+				07AFF4211EFB144700B545B3 /* CoreAudioCaptureSourceIOS.mm */,
 			);
 			path = ios;
 			sourceTree = "<group>";
@@ -26908,6 +26914,7 @@
 				9746AF2114F4DDE6003E7A71 /* Coordinates.h in Headers */,
 				3F8020351E9E47BF00DEC61D /* CoreAudioCaptureDevice.h in Headers */,
 				3F8020371E9E47C500DEC61D /* CoreAudioCaptureDeviceManager.h in Headers */,
+				07AFF4221EFB144900B545B3 /* CoreAudioCaptureSourceIOS.h in Headers */,
 				CE1252371A15BDBE00864480 /* CoreGraphicsSPI.h in Headers */,
 				443818001A91B2F8006E04F2 /* CoreMediaSoftLink.h in Headers */,
 				4449A4051A964B0000B64AD5 /* CoreMediaSPI.h in Headers */,
@@ -31008,6 +31015,7 @@
 				3F8020361E9E47C300DEC61D /* CoreAudioCaptureDevice.cpp in Sources */,
 				3F8020381E9E47C900DEC61D /* CoreAudioCaptureDeviceManager.cpp in Sources */,
 				3FF1FA661E7350FD00C1002F /* CoreAudioCaptureSource.cpp in Sources */,
+				07AFF4231EFB144900B545B3 /* CoreAudioCaptureSourceIOS.mm in Sources */,
 				443817FF1A91B2F8006E04F2 /* CoreMediaSoftLink.cpp in Sources */,
 				CD7D33471C7A16BF00041293 /* CoreVideoSoftLink.cpp in Sources */,
 				BC5EB9500E82056B00B25965 /* CounterDirectives.cpp in Sources */,

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h (218745 => 218746)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2017-06-23 12:08:00 UTC (rev 218745)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2017-06-23 15:40:05 UTC (rev 218746)
@@ -235,10 +235,10 @@
 
     void videoSampleAvailable(MediaSample&);
     void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t);
-    
-private:
+
     WeakPtr<RealtimeMediaSource> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
 
+private:
     virtual void startProducingData() { }
     virtual void stopProducingData() { }
 

Added: trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.h (0 => 218746)


--- trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.h	2017-06-23 15:40:05 UTC (rev 218746)
@@ -0,0 +1,48 @@
+/*
+ * 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) && PLATFORM(IOS)
+
+#include "CoreAudioCaptureSource.h"
+
+OBJC_CLASS WebCoreAudioCaptureSourceIOSListener;
+
+namespace WebCore {
+
+class CoreAudioCaptureSourceIOS final : public CoreAudioCaptureSource {
+private:
+    friend class CoreAudioCaptureSource;
+
+    CoreAudioCaptureSourceIOS(const String& deviceID, const String& label);
+    ~CoreAudioCaptureSourceIOS();
+
+    RetainPtr<WebCoreAudioCaptureSourceIOSListener> m_listener;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

Added: trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm (0 => 218746)


--- trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm	2017-06-23 15:40:05 UTC (rev 218746)
@@ -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. AND ITS 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 APPLE INC. OR ITS 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 "CoreAudioCaptureSourceIOS.h"
+
+#if ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
+
+#import "Logging.h"
+#import "SoftLinking.h"
+#import <AVFoundation/AVAudioSession.h>
+#import <wtf/MainThread.h>
+
+typedef AVAudioSession AVAudioSessionType;
+
+SOFT_LINK_FRAMEWORK(AVFoundation)
+SOFT_LINK_CLASS(AVFoundation, AVAudioSession)
+
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionInterruptionNotification, NSString *)
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionInterruptionTypeKey, NSString *)
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionMediaServicesWereResetNotification, NSString *)
+
+#define AVAudioSession getAVAudioSessionClass()
+#define AVAudioSessionInterruptionNotification getAVAudioSessionInterruptionNotification()
+#define AVAudioSessionInterruptionTypeKey getAVAudioSessionInterruptionTypeKey()
+#define AVAudioSessionMediaServicesWereResetNotification getAVAudioSessionMediaServicesWereResetNotification()
+
+using namespace WebCore;
+
+@interface WebCoreAudioCaptureSourceIOSListener : NSObject {
+    CoreAudioCaptureSourceIOS* _callback;
+}
+
+- (void)invalidate;
+- (void)handleInterruption:(NSNotification*)notification;
+- (void)sessionMediaServicesWereReset:(NSNotification*)notification;
+@end
+
+@implementation WebCoreAudioCaptureSourceIOSListener
+- (id)initWithCallback:(CoreAudioCaptureSourceIOS*)callback
+{
+    self = [super init];
+    if (!self)
+        return nil;
+
+    _callback = callback;
+
+    NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+    AVAudioSessionType* session = [AVAudioSession sharedInstance];
+
+    [center addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:session];
+    [center addObserver:self selector:@selector(sessionMediaServicesWereReset:) name:AVAudioSessionMediaServicesWereResetNotification object:session];
+
+    return self;
+}
+
+- (void)invalidate
+{
+    _callback = nullptr;
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)handleInterruption:(NSNotification*)notification
+{
+    ASSERT(_callback);
+    if (!_callback)
+        return;
+
+    if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] intValue] == AVAudioSessionInterruptionTypeBegan) {
+        _callback->beginInterruption();
+        return;
+    }
+
+    if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] intValue] == AVAudioSessionInterruptionTypeEnded) {
+        NSError *error = nil;
+        [[AVAudioSession sharedInstance] setActive:YES error:&error];
+
+#if !LOG_DISABLED
+        if (error)
+            LOG(Media, "-[WebCoreAudioCaptureSourceIOSListener handleInterruption] (%p) - error = %s", self, [[error localizedDescription] UTF8String]);
+#endif
+
+        _callback->endInterruption();
+    }
+}
+
+- (void)sessionMediaServicesWereReset:(NSNotification*)notification
+{
+    UNUSED_PARAM(notification);
+    ASSERT(_callback);
+
+    if (!_callback)
+        return;
+
+    // mediaserverd crashed and was relaunched, rebuild everything. See
+    // https://developer.apple.com/library/content/qa/qa1749/_index.html.
+    _callback->scheduleReconfiguration();
+}
+@end
+
+namespace WebCore {
+
+CoreAudioCaptureSourceIOS::CoreAudioCaptureSourceIOS(const String& deviceID, const String& label)
+    : CoreAudioCaptureSource(deviceID, label, 0)
+    , m_listener(adoptNS([[WebCoreAudioCaptureSourceIOSListener alloc] initWithCallback:this]))
+{
+}
+
+CoreAudioCaptureSourceIOS::~CoreAudioCaptureSourceIOS()
+{
+    [m_listener invalidate];
+    m_listener = nullptr;
+}
+
+}
+
+#endif // ENABLE(MEDIA_STREAM) && PLATFORM(IOS)

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


--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp	2017-06-23 12:08:00 UTC (rev 218745)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.cpp	2017-06-23 15:40:05 UTC (rev 218746)
@@ -35,6 +35,7 @@
 #include "AudioSession.h"
 #include "CoreAudioCaptureDevice.h"
 #include "CoreAudioCaptureDeviceManager.h"
+#include "CoreAudioCaptureSourceIOS.h"
 #include "CoreAudioSPI.h"
 #include "Logging.h"
 #include "MediaTimeAVFoundation.h"
@@ -84,7 +85,10 @@
     bool isProducingData() { return m_ioUnitStarted; }
 
     OSStatus suspend();
+    OSStatus resume();
 
+    bool isSuspended() const { return m_suspended; }
+
     OSStatus setupAudioUnit();
     void cleanupAudioUnit();
     OSStatus reconfigureAudioUnit();
@@ -118,6 +122,9 @@
     static OSStatus speakerCallback(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
     OSStatus provideSpeakerData(AudioUnitRenderActionFlags&, const AudioTimeStamp&, UInt32, UInt32, AudioBufferList*);
 
+    void startInternal();
+    void stopInternal();
+
     Vector<std::reference_wrapper<CoreAudioCaptureSource>> m_clients;
 
     AudioUnit m_ioUnit { nullptr };
@@ -163,6 +170,8 @@
     bool m_enableEchoCancellation { true };
     double m_volume { 1 };
     int m_sampleRate;
+
+    bool m_suspended { false };
 };
 
 CoreAudioSharedUnit& CoreAudioSharedUnit::singleton()
@@ -295,6 +304,7 @@
         return err;
     }
     m_ioUnitInitialized = true;
+    m_suspended = false;
 
     uint32_t outputDevice;
     if (!defaultOutputDevice(&outputDevice))
@@ -537,6 +547,27 @@
     if (m_ioUnitStarted)
         return;
 
+    startInternal();
+}
+
+OSStatus CoreAudioSharedUnit::resume()
+{
+    ASSERT(isMainThread());
+    ASSERT(m_suspended);
+    ASSERT(!m_ioUnitStarted);
+
+    m_suspended = false;
+
+    if (!m_ioUnit)
+        return 0;
+
+    startInternal();
+
+    return 0;
+}
+
+void CoreAudioSharedUnit::startInternal()
+{
     OSStatus err;
     if (!m_ioUnit) {
         err = setupAudioUnit();
@@ -560,10 +591,26 @@
 void CoreAudioSharedUnit::stopProducingData()
 {
     ASSERT(isMainThread());
+    ASSERT(m_producingCount);
 
-    if (--m_producingCount)
+    if (m_producingCount && --m_producingCount)
         return;
 
+    stopInternal();
+}
+
+OSStatus CoreAudioSharedUnit::suspend()
+{
+    ASSERT(isMainThread());
+
+    m_suspended = true;
+    stopInternal();
+
+    return 0;
+}
+
+void CoreAudioSharedUnit::stopInternal()
+{
     if (!m_ioUnit || !m_ioUnitStarted)
         return;
 
@@ -576,36 +623,6 @@
     m_ioUnitStarted = false;
 }
 
-OSStatus CoreAudioSharedUnit::suspend()
-{
-    ASSERT(isMainThread());
-
-    m_activeSources.clear();
-    m_pendingSources.clear();
-
-    if (m_ioUnitStarted) {
-        ASSERT(m_ioUnit);
-        auto err = AudioOutputUnitStop(m_ioUnit);
-        if (err) {
-            LOG(Media, "CoreAudioSharedUnit::resume(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
-            return err;
-        }
-        m_ioUnitStarted = false;
-    }
-
-    if (m_ioUnitInitialized) {
-        ASSERT(m_ioUnit);
-        auto err = AudioUnitUninitialize(m_ioUnit);
-        if (err) {
-            LOG(Media, "CoreAudioSharedUnit::resume(%p) AudioUnitUninitialize failed with error %d (%.4s)", this, (int)err, (char*)&err);
-            return err;
-        }
-        m_ioUnitInitialized = false;
-    }
-
-    return 0;
-}
-
 OSStatus CoreAudioSharedUnit::defaultInputDevice(uint32_t* deviceID)
 {
     ASSERT(m_ioUnit);
@@ -636,23 +653,19 @@
 
 CaptureSourceOrError CoreAudioCaptureSource::create(const String& deviceID, const MediaConstraints* constraints)
 {
-    String label;
-    uint32_t persistentID = 0;
 #if PLATFORM(MAC)
     auto device = CoreAudioCaptureDeviceManager::singleton().coreAudioDeviceWithUID(deviceID);
     if (!device)
         return { };
 
-    label = device->label();
-    persistentID = device->deviceID();
+    auto source = adoptRef(*new CoreAudioCaptureSource(deviceID, device->label(), device->deviceID()));
 #elif PLATFORM(IOS)
     auto device = AVAudioSessionCaptureDeviceManager::singleton().audioSessionDeviceWithUID(deviceID);
     if (!device)
         return { };
 
-    label = device->label();
+    auto source = adoptRef(*new CoreAudioCaptureSourceIOS(deviceID, device->label()));
 #endif
-    auto source = adoptRef(*new CoreAudioCaptureSource(deviceID, label, persistentID));
 
     if (constraints) {
         auto result = source->applyConstraints(*constraints);
@@ -705,12 +718,25 @@
     coreAudioCaptureSourceFactory().setActiveSource(*this);
 #endif
 
-    CoreAudioSharedUnit::singleton().startProducingData();
+    auto& unit = CoreAudioSharedUnit::singleton();
+    if (unit.isSuspended()) {
+        m_suspendType = SuspensionType::WhilePlaying;
+        return;
+    }
+
+    unit.startProducingData();
 }
 
 void CoreAudioCaptureSource::stopProducingData()
 {
-    CoreAudioSharedUnit::singleton().stopProducingData();
+    auto& unit = CoreAudioSharedUnit::singleton();
+
+    if (unit.isSuspended()) {
+        m_suspendType = SuspensionType::WhilePaused;
+        return;
+    }
+
+    unit.stopProducingData();
 }
 
 const RealtimeMediaSourceCapabilities& CoreAudioCaptureSource::capabilities() const
@@ -784,18 +810,103 @@
 
 void CoreAudioCaptureSource::scheduleReconfiguration()
 {
+    if (!isMainThread()) {
+        callOnMainThread([weakThis = createWeakPtr(), this] {
+            if (!weakThis)
+                return;
+
+            scheduleReconfiguration();
+        });
+
+        return;
+    }
+
     ASSERT(isMainThread());
     auto& unit = CoreAudioSharedUnit::singleton();
-    if (!unit.hasAudioUnit() || m_reconfigurationOngoing)
+    if (!unit.hasAudioUnit() || m_reconfigurationState != ReconfigurationState::None)
         return;
 
-    m_reconfigurationOngoing = true;
+    m_reconfigurationState = ReconfigurationState::Ongoing;
     scheduleDeferredTask([this, &unit] {
+        if (unit.isSuspended()) {
+            m_reconfigurationState = ReconfigurationState::Required;
+            return;
+        }
+
         unit.reconfigureAudioUnit();
-        m_reconfigurationOngoing = false;
+        m_reconfigurationState = ReconfigurationState::None;
     });
 }
 
+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)
+        return;
+
+    m_suspendPending = true;
+    scheduleDeferredTask([this, &unit] {
+        m_suspendType = unit.isProducingData() ? SuspensionType::WhilePlaying : SuspensionType::WhilePaused;
+        unit.suspend();
+        m_suspendPending = false;
+    });
+}
+
+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)
+        return;
+
+    auto type = m_suspendType;
+    m_suspendType = SuspensionType::None;
+    if (type != SuspensionType::WhilePlaying && m_reconfigurationState != ReconfigurationState::Required)
+        return;
+
+    m_resumePending = true;
+    scheduleDeferredTask([this, type, &unit] {
+        if (m_reconfigurationState == ReconfigurationState::Required)
+            unit.reconfigureAudioUnit();
+        if (type == SuspensionType::WhilePlaying)
+            unit.resume();
+        m_reconfigurationState = ReconfigurationState::None;
+        m_resumePending = false;
+    });
+}
+
+bool CoreAudioCaptureSource::interrupted() const
+{
+    auto& unit = CoreAudioSharedUnit::singleton();
+    if (unit.isSuspended())
+        return true;
+
+    return RealtimeMediaSource::interrupted();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)

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


--- trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h	2017-06-23 12:08:00 UTC (rev 218745)
+++ trunk/Source/WebCore/platform/mediastream/mac/CoreAudioCaptureSource.h	2017-06-23 15:40:05 UTC (rev 218746)
@@ -51,7 +51,7 @@
 class CaptureDeviceInfo;
 class WebAudioSourceProviderAVFObjC;
 
-class CoreAudioCaptureSource final : public RealtimeMediaSource {
+class CoreAudioCaptureSource : public RealtimeMediaSource {
 public:
 
     static CaptureSourceOrError create(const String& deviceID, const MediaConstraints*);
@@ -68,15 +68,18 @@
 
     CMClockRef timebaseClock();
 
-private:
+    void beginInterruption();
+    void endInterruption();
+    void scheduleReconfiguration();
+
+protected:
     CoreAudioCaptureSource(const String& deviceID, const String& label, uint32_t persistentID);
     virtual ~CoreAudioCaptureSource();
 
+private:
     friend class CoreAudioSharedUnit;
     friend class CoreAudioCaptureSourceFactory;
 
-    void scheduleReconfiguration();
-
     bool isCaptureSource() const final { return true; }
     void startProducingData() final;
     void stopProducingData() final;
@@ -89,14 +92,22 @@
     const RealtimeMediaSourceSettings& settings() const final;
     void settingsDidChange() final;
 
+    bool interrupted() const final;
+
     uint32_t m_captureDeviceID { 0 };
 
-    bool m_isSuspended { false };
-
     mutable std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
     mutable std::optional<RealtimeMediaSourceSettings> m_currentSettings;
 
-    bool m_reconfigurationOngoing { false };
+    enum class SuspensionType { None, WhilePaused, WhilePlaying };
+    SuspensionType m_suspendType { SuspensionType::None };
+
+    enum class ReconfigurationState { None, Required, Ongoing };
+    ReconfigurationState m_reconfigurationState { ReconfigurationState::None };
+
+    bool m_reconfigurationRequired { false };
+    bool m_suspendPending { false };
+    bool m_resumePending { false };
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to