Title: [216024] trunk/Source/WebCore
Revision
216024
Author
jer.no...@apple.com
Date
2017-05-01 14:06:39 -0700 (Mon, 01 May 2017)

Log Message

Add audio device change notifications to AudioSession.
https://bugs.webkit.org/show_bug.cgi?id=171403

Reviewed by Eric Carlson.

Add notifications to AudioSession which fire when the current input and output audio devices
change. Also add a notification when audio services are lost (which will only fire on iOS).
Take this opportunity to make the existing hardwareMutedStateDidChange() notification be
platform agnostic, to move the outputDeviceSupportsLowPowerMode() code from AudioHardwareListener,
and to do a few more clean-ups of the AudioSession code.

* WebCore.xcodeproj/project.pbxproj:
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement):
(WebCore::HTMLMediaElement::~HTMLMediaElement):
* html/HTMLMediaElement.h:
* platform/audio/AudioSession.cpp:
(WebCore::AudioSession::AudioSession):
* platform/audio/AudioSession.h:
(WebCore::AudioSession::Observer::hardwareMutedStateDidChange):
(WebCore::AudioSession::Observer::audioInputDeviceChanged):
(WebCore::AudioSession::Observer::audioOutputDeviceChanged):
(WebCore::AudioSession::Observer::audioServicesLost):
(WebCore::AudioSession::Observer::audioServicesReset):
(WebCore::AudioSession::MutedStateObserver::~MutedStateObserver): Deleted.
* platform/audio/ios/AudioSessionIOS.mm:
(WebCore::AudioSessionPrivate::AudioSessionPrivate):
(WebCore::AudioSession::AudioSession):
(WebCore::AudioSession::setCategoryOverride):
(WebCore::AudioSession::categoryOverride):
(WebCore::AudioSession::isMuted):
(WebCore::AudioSession::outputDeviceSupportsLowPowerMode):
(WebCore::AudioSession::addObserver):
(WebCore::AudioSession::removeObserver):
* platform/audio/mac/AudioSessionMac.mm: Renamed from Source/WebCore/platform/audio/mac/AudioSessionMac.cpp.
(WebCore::defaultDevice):
(WebCore::AudioSessionPrivate::AudioSessionPrivate):
(WebCore::AudioSession::AudioSession):
(WebCore::AudioSession::~AudioSession):
(WebCore::AudioSession::category):
(WebCore::AudioSession::setCategory):
(WebCore::AudioSession::categoryOverride):
(WebCore::AudioSession::setCategoryOverride):
(WebCore::AudioSession::sampleRate):
(WebCore::AudioSession::bufferSize):
(WebCore::AudioSession::numberOfOutputChannels):
(WebCore::AudioSession::tryToSetActive):
(WebCore::AudioSession::preferredBufferSize):
(WebCore::AudioSession::setPreferredBufferSize):
(WebCore::AudioSession::isMuted):
(WebCore::currentDeviceSupportsLowPowerBufferSize):
(WebCore::AudioSession::outputDeviceSupportsLowPowerMode):
(WebCore::AudioSession::addObserver):
(WebCore::AudioSession::removeObserver):

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (216023 => 216024)


--- trunk/Source/WebCore/ChangeLog	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/ChangeLog	2017-05-01 21:06:39 UTC (rev 216024)
@@ -1,3 +1,60 @@
+2017-05-01  Jer Noble  <jer.no...@apple.com>
+
+        Add audio device change notifications to AudioSession.
+        https://bugs.webkit.org/show_bug.cgi?id=171403
+
+        Reviewed by Eric Carlson.
+
+        Add notifications to AudioSession which fire when the current input and output audio devices
+        change. Also add a notification when audio services are lost (which will only fire on iOS).
+        Take this opportunity to make the existing hardwareMutedStateDidChange() notification be
+        platform agnostic, to move the outputDeviceSupportsLowPowerMode() code from AudioHardwareListener,
+        and to do a few more clean-ups of the AudioSession code.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement):
+        (WebCore::HTMLMediaElement::~HTMLMediaElement):
+        * html/HTMLMediaElement.h:
+        * platform/audio/AudioSession.cpp:
+        (WebCore::AudioSession::AudioSession):
+        * platform/audio/AudioSession.h:
+        (WebCore::AudioSession::Observer::hardwareMutedStateDidChange):
+        (WebCore::AudioSession::Observer::audioInputDeviceChanged):
+        (WebCore::AudioSession::Observer::audioOutputDeviceChanged):
+        (WebCore::AudioSession::Observer::audioServicesLost):
+        (WebCore::AudioSession::Observer::audioServicesReset):
+        (WebCore::AudioSession::MutedStateObserver::~MutedStateObserver): Deleted.
+        * platform/audio/ios/AudioSessionIOS.mm:
+        (WebCore::AudioSessionPrivate::AudioSessionPrivate):
+        (WebCore::AudioSession::AudioSession):
+        (WebCore::AudioSession::setCategoryOverride):
+        (WebCore::AudioSession::categoryOverride):
+        (WebCore::AudioSession::isMuted):
+        (WebCore::AudioSession::outputDeviceSupportsLowPowerMode):
+        (WebCore::AudioSession::addObserver):
+        (WebCore::AudioSession::removeObserver):
+        * platform/audio/mac/AudioSessionMac.mm: Renamed from Source/WebCore/platform/audio/mac/AudioSessionMac.cpp.
+        (WebCore::defaultDevice):
+        (WebCore::AudioSessionPrivate::AudioSessionPrivate):
+        (WebCore::AudioSession::AudioSession):
+        (WebCore::AudioSession::~AudioSession):
+        (WebCore::AudioSession::category):
+        (WebCore::AudioSession::setCategory):
+        (WebCore::AudioSession::categoryOverride):
+        (WebCore::AudioSession::setCategoryOverride):
+        (WebCore::AudioSession::sampleRate):
+        (WebCore::AudioSession::bufferSize):
+        (WebCore::AudioSession::numberOfOutputChannels):
+        (WebCore::AudioSession::tryToSetActive):
+        (WebCore::AudioSession::preferredBufferSize):
+        (WebCore::AudioSession::setPreferredBufferSize):
+        (WebCore::AudioSession::isMuted):
+        (WebCore::currentDeviceSupportsLowPowerBufferSize):
+        (WebCore::AudioSession::outputDeviceSupportsLowPowerMode):
+        (WebCore::AudioSession::addObserver):
+        (WebCore::AudioSession::removeObserver):
+
 2017-05-01  Chris Dumez  <cdu...@apple.com>
 
         Do not dispatch SVG load event in frameless documents

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (216023 => 216024)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-05-01 21:06:39 UTC (rev 216024)
@@ -6116,7 +6116,7 @@
 		CD5393D4175E018600C07123 /* JSMemoryInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5393D2175E018600C07123 /* JSMemoryInfo.h */; };
 		CD54A762180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD54A760180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.cpp */; };
 		CD54A763180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = CD54A761180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.h */; };
-		CD54DE4B17469C6D005E5B36 /* AudioSessionMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */; };
+		CD54DE4B17469C6D005E5B36 /* AudioSessionMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD54DE4917469C6D005E5B36 /* AudioSessionMac.mm */; };
 		CD5596911475B678001D0BD0 /* AudioFileReaderIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD55968F1475B678001D0BD0 /* AudioFileReaderIOS.cpp */; };
 		CD5596921475B678001D0BD0 /* AudioFileReaderIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5596901475B678001D0BD0 /* AudioFileReaderIOS.h */; };
 		CD5896E11CD2B15100B3BCC8 /* WebPlaybackControlsManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD5896DF1CD2B15100B3BCC8 /* WebPlaybackControlsManager.mm */; };
@@ -14594,7 +14594,7 @@
 		CD5393D2175E018600C07123 /* JSMemoryInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMemoryInfo.h; sourceTree = "<group>"; };
 		CD54A760180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioTrackPrivateMediaSourceAVFObjC.cpp; sourceTree = "<group>"; };
 		CD54A761180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioTrackPrivateMediaSourceAVFObjC.h; sourceTree = "<group>"; };
-		CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioSessionMac.cpp; sourceTree = "<group>"; };
+		CD54DE4917469C6D005E5B36 /* AudioSessionMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioSessionMac.mm; sourceTree = "<group>"; };
 		CD55968F1475B678001D0BD0 /* AudioFileReaderIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioFileReaderIOS.cpp; sourceTree = "<group>"; };
 		CD5596901475B678001D0BD0 /* AudioFileReaderIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioFileReaderIOS.h; sourceTree = "<group>"; };
 		CD5896DF1CD2B15100B3BCC8 /* WebPlaybackControlsManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPlaybackControlsManager.mm; sourceTree = "<group>"; };
@@ -26172,7 +26172,7 @@
 				073B87631E43859D0071C0EC /* AudioSampleBufferList.h */,
 				073B87651E43859D0071C0EC /* AudioSampleDataSource.h */,
 				073B87641E43859D0071C0EC /* AudioSampleDataSource.mm */,
-				CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */,
+				CD54DE4917469C6D005E5B36 /* AudioSessionMac.mm */,
 				073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */,
 				073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */,
 				CDC734121977896C0046BFC5 /* CARingBuffer.cpp */,
@@ -30525,7 +30525,7 @@
 				FD8C46EB154608E700A5910C /* AudioScheduledSourceNode.cpp in Sources */,
 				CDA79824170A258300D45C55 /* AudioSession.cpp in Sources */,
 				CDA79827170A279100D45C55 /* AudioSessionIOS.mm in Sources */,
-				CD54DE4B17469C6D005E5B36 /* AudioSessionMac.cpp in Sources */,
+				CD54DE4B17469C6D005E5B36 /* AudioSessionMac.mm in Sources */,
 				CD8A7BBB197735FE00CBD643 /* AudioSourceProviderAVFObjC.mm in Sources */,
 				FDB052DF1561A42C00B500D6 /* AudioSummingJunction.cpp in Sources */,
 				BE88E0D81715D2A200658D98 /* AudioTrack.cpp in Sources */,

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (216023 => 216024)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2017-05-01 21:06:39 UTC (rev 216024)
@@ -511,8 +511,8 @@
 
     registerWithDocument(document);
 
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
-    AudioSession::sharedSession().addMutedStateObserver(this);
+#if USE(AUDIO_SESSION)
+    AudioSession::sharedSession().addObserver(*this);
 #endif
 }
 
@@ -528,8 +528,8 @@
     setShouldDelayLoadEvent(false);
     unregisterWithDocument(document());
 
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
-    AudioSession::sharedSession().removeMutedStateObserver(this);
+#if USE(AUDIO_SESSION)
+    AudioSession::sharedSession().removeObserver(*this);
 #endif
 
 #if ENABLE(VIDEO_TRACK)
@@ -3420,7 +3420,7 @@
     scheduleUpdatePlaybackControlsManager();
 }
 
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+#if USE(AUDIO_SESSION)
 void HTMLMediaElement::hardwareMutedStateDidChange(AudioSession* session)
 {
     if (!session->isMuted())

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (216023 => 216024)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2017-05-01 21:06:39 UTC (rev 216024)
@@ -51,7 +51,7 @@
 #include "VideoTrack.h"
 #endif
 
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+#if USE(AUDIO_SESSION)
 #include "AudioSession.h"
 #endif
 
@@ -125,8 +125,8 @@
     , private TextTrackClient
     , private VideoTrackClient
 #endif
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
-    , private AudioSession::MutedStateObserver
+#if USE(AUDIO_SESSION)
+    , private AudioSession::Observer
 #endif
 {
 public:
@@ -817,7 +817,7 @@
 
     void pageMutedStateDidChange() override;
 
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+#if USE(AUDIO_SESSION)
     void hardwareMutedStateDidChange(AudioSession*) final;
 #endif
 

Modified: trunk/Source/WebCore/platform/audio/AudioSession.cpp (216023 => 216024)


--- trunk/Source/WebCore/platform/audio/AudioSession.cpp	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/platform/audio/AudioSession.cpp	2017-05-01 21:06:39 UTC (rev 216024)
@@ -44,7 +44,7 @@
 };
 
 AudioSession::AudioSession()
-    : m_private(nullptr)
+    : m_private(makeUniqueRef<AudioSessionPrivate>())
 {
     notImplemented();
 }

Modified: trunk/Source/WebCore/platform/audio/AudioSession.h (216023 => 216024)


--- trunk/Source/WebCore/platform/audio/AudioSession.h	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/platform/audio/AudioSession.h	2017-05-01 21:06:39 UTC (rev 216024)
@@ -30,10 +30,9 @@
 
 #if USE(AUDIO_SESSION)
 
-#include <memory>
-#include <wtf/HashSet.h>
-#include <wtf/NeverDestroyed.h>
+#include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/UniqueRef.h>
 
 namespace WebCore {
 
@@ -44,6 +43,19 @@
 public:
     WEBCORE_EXPORT static AudioSession& sharedSession();
 
+    class Observer {
+    public:
+        virtual ~Observer() = default;
+
+        virtual void hardwareMutedStateDidChange(AudioSession*) { };
+        virtual void currentAudioInputDeviceChanged() { };
+        virtual void currentAudioOutputDeviceChanged() { };
+        virtual void audioServicesLost() { };
+        virtual void audioServicesReset() { };
+    };
+    void addObserver(Observer&);
+    void removeObserver(Observer&);
+
     enum CategoryType {
         None,
         AmbientSound,
@@ -68,18 +80,8 @@
     size_t preferredBufferSize() const;
     void setPreferredBufferSize(size_t);
 
-    class MutedStateObserver {
-    public:
-        virtual ~MutedStateObserver() { }
-
-        virtual void hardwareMutedStateDidChange(AudioSession*) = 0;
-    };
-
-    void addMutedStateObserver(MutedStateObserver*);
-    void removeMutedStateObserver(MutedStateObserver*);
-
+    bool outputDeviceSupportsLowPowerMode() const;
     bool isMuted() const;
-    void handleMutedStateChange();
 
 private:
     friend class NeverDestroyed<AudioSession>;
@@ -86,8 +88,7 @@
     AudioSession();
     ~AudioSession();
 
-    std::unique_ptr<AudioSessionPrivate> m_private;
-    HashSet<MutedStateObserver*> m_observers;
+    UniqueRef<AudioSessionPrivate> m_private;
 };
 
 }

Modified: trunk/Source/WebCore/platform/audio/ios/AudioSessionIOS.mm (216023 => 216024)


--- trunk/Source/WebCore/platform/audio/ios/AudioSessionIOS.mm	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/platform/audio/ios/AudioSessionIOS.mm	2017-05-01 21:06:39 UTC (rev 216024)
@@ -32,7 +32,10 @@
 #import "SoftLinking.h"
 #import <AVFoundation/AVAudioSession.h>
 #import <objc/runtime.h>
+#import <wtf/HashSet.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/Vector.h>
+#import <wtf/WeakPtr.h>
 
 SOFT_LINK_FRAMEWORK(AVFoundation)
 SOFT_LINK_CLASS(AVFoundation, AVAudioSession)
@@ -44,6 +47,10 @@
 SOFT_LINK_POINTER(AVFoundation, AVAudioSessionCategoryPlayAndRecord, NSString *)
 SOFT_LINK_POINTER(AVFoundation, AVAudioSessionCategoryAudioProcessing, NSString *)
 SOFT_LINK_POINTER(AVFoundation, AVAudioSessionInterruptionTypeKey, NSString *)
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionRouteChangeNotification, NSString*)
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionMediaServicesWereLostNotification, NSString*)
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionMediaServicesWereResetNotification, NSString*)
+SOFT_LINK_POINTER(AVFoundation, AVAudioSessionRouteChangePreviousRouteKey, NSString*)
 
 #define AVAudioSession getAVAudioSessionClass()
 #define AVAudioSessionCategoryAmbient getAVAudioSessionCategoryAmbient()
@@ -53,7 +60,10 @@
 #define AVAudioSessionCategoryPlayAndRecord getAVAudioSessionCategoryPlayAndRecord()
 #define AVAudioSessionCategoryAudioProcessing getAVAudioSessionCategoryAudioProcessing()
 #define AVAudioSessionInterruptionTypeKey getAVAudioSessionInterruptionTypeKey()
-
+#define AVAudioSessionRouteChangeNotification getAVAudioSessionRouteChangeNotification()
+#define AVAudioSessionMediaServicesWereLostNotification getAVAudioSessionMediaServicesWereLostNotification()
+#define AVAudioSessionMediaServicesWereResetNotification getAVAudioSessionMediaServicesWereResetNotification()
+#define AVAudioSessionRouteChangePreviousRouteKey getAVAudioSessionRouteChangePreviousRouteKey()
 namespace WebCore {
 
 #if !LOG_DISABLED
@@ -77,17 +87,19 @@
 
 class AudioSessionPrivate {
 public:
-    AudioSessionPrivate(AudioSession*);
-    AudioSession::CategoryType m_categoryOverride;
+    AudioSessionPrivate(AudioSession& audioSession)
+        : weakPtrFactory(&audioSession)
+    {
+    }
+
+    WeakPtrFactory<AudioSession> weakPtrFactory;
+    AudioSession::CategoryType categoryOverride { AudioSession::None };
+    HashSet<AudioSession::Observer*> observers;
+    Vector<RetainPtr<id>> notificationCallbacks;
 };
 
-AudioSessionPrivate::AudioSessionPrivate(AudioSession*)
-    : m_categoryOverride(AudioSession::None)
-{
-}
-
 AudioSession::AudioSession()
-    : m_private(std::make_unique<AudioSessionPrivate>(this))
+    : m_private(makeUniqueRef<AudioSessionPrivate>(*this))
 {
 }
 
@@ -154,16 +166,16 @@
 
 void AudioSession::setCategoryOverride(CategoryType category)
 {
-    if (m_private->m_categoryOverride == category)
+    if (m_private->categoryOverride == category)
         return;
 
-    m_private->m_categoryOverride = category;
+    m_private->categoryOverride = category;
     setCategory(category);
 }
 
 AudioSession::CategoryType AudioSession::categoryOverride() const
 {
-    return m_private->m_categoryOverride;
+    return m_private->categoryOverride;
 }
 
 float AudioSession::sampleRate() const
@@ -201,6 +213,90 @@
     ASSERT(!error);
 }
 
+bool AudioSession::isMuted() const
+{
+    return false;
 }
 
+bool AudioSession::outputDeviceSupportsLowPowerMode() const
+{
+    return false;
+}
+
+void AudioSession::addObserver(Observer& observer)
+{
+    ASSERT(!m_private->observers.contains(&observer));
+    m_private->observers.add(&observer);
+
+    if (m_private->observers.size() != 1)
+        return;
+
+    auto* center = [NSNotificationCenter defaultCenter];
+    auto* session = [AVAudioSession sharedInstance];
+    auto weakThis = m_private->weakPtrFactory.createWeakPtr();
+
+    ASSERT(m_private->notificationCallbacks.isEmpty());
+    m_private->notificationCallbacks = {
+        [center addObserverForName:AVAudioSessionRouteChangeNotification object:session queue:nil usingBlock:[weakThis] (NSNotification *note) {
+            callOnMainThread([weakThis, note = RetainPtr<NSNotification>(note)] {
+                if (!weakThis)
+                    return;
+
+                AVAudioSessionRouteDescription *oldRoute = [[note userInfo] valueForKey:AVAudioSessionRouteChangePreviousRouteKey];
+                AVAudioSessionRouteDescription *newRoute = [[AVAudioSession sharedInstance] currentRoute];
+
+                bool inputsChanged = [oldRoute.inputs isEqualToArray:newRoute.inputs];
+                bool outputsChanged = [oldRoute.outputs isEqualToArray:newRoute.outputs];
+                if (!inputsChanged && !outputsChanged)
+                    return;
+
+                // Protect against the observers set being mutated mid-notification:
+                auto observers = weakThis->m_private->observers;
+                for (auto& observer : observers) {
+                    if (inputsChanged)
+                        observer->currentAudioInputDeviceChanged();
+                    if (outputsChanged)
+                        observer->currentAudioOutputDeviceChanged();
+                }
+            });
+        }],
+        [center addObserverForName:AVAudioSessionMediaServicesWereLostNotification object:session queue:nil usingBlock:[weakThis] (NSNotification *) {
+            callOnMainThread([weakThis] {
+                if (!weakThis)
+                    return;
+
+                // Protect against the observers set being mutated mid-notification:
+                auto observers = weakThis->m_private->observers;
+                for (auto& observer : observers)
+                    observer->audioServicesLost();
+            });
+        }],
+        [center addObserverForName:AVAudioSessionMediaServicesWereResetNotification object:session queue:nil usingBlock:[weakThis] (NSNotification *) {
+            callOnMainThread([weakThis] {
+                if (!weakThis)
+                    return;
+
+                // Protect against the observers set being mutated mid-notification:
+                auto observers = weakThis->m_private->observers;
+                for (auto& observer : observers)
+                    observer->audioServicesReset();
+            });
+        }],
+    };
+}
+
+void AudioSession::removeObserver(Observer& observer)
+{
+    ASSERT(m_private->observers.contains(&observer));
+    m_private->observers.remove(&observer);
+
+    if (m_private->observers.size())
+        return;
+
+    for (auto& observer : m_private->notificationCallbacks)
+        [[NSNotificationCenter defaultCenter] removeObserver:observer.get()];
+}
+
+}
+
 #endif // USE(AUDIO_SESSION) && PLATFORM(IOS)

Deleted: trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.cpp (216023 => 216024)


--- trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.cpp	2017-05-01 20:40:23 UTC (rev 216023)
+++ trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.cpp	2017-05-01 21:06:39 UTC (rev 216024)
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2013 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 "AudioSession.h"
-
-#if USE(AUDIO_SESSION) && PLATFORM(MAC)
-
-#include "FloatConversion.h"
-#include "Logging.h"
-#include "NotImplemented.h"
-#include <CoreAudio/AudioHardware.h>
-#include <wtf/MainThread.h>
-
-namespace WebCore {
-
-static AudioDeviceID defaultDevice()
-{
-    AudioDeviceID deviceID = kAudioDeviceUnknown;
-    UInt32 infoSize = sizeof(deviceID);
-
-    AudioObjectPropertyAddress defaultOutputDeviceAddress = {
-        kAudioHardwarePropertyDefaultOutputDevice,
-        kAudioObjectPropertyScopeGlobal,
-        kAudioObjectPropertyElementMaster };
-    OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultOutputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID);
-    if (result)
-        return 0; // error
-    return deviceID;
-}
-
-class AudioSessionPrivate {
-public:
-    AudioSessionPrivate(bool mutedState)
-        : lastMutedState(mutedState) { }
-    bool lastMutedState;
-};
-
-AudioSession::AudioSession()
-    : m_private(std::make_unique<AudioSessionPrivate>(isMuted()))
-{
-}
-
-AudioSession::~AudioSession()
-{
-}
-
-AudioSession::CategoryType AudioSession::category() const
-{
-    notImplemented();
-    return None;
-}
-
-void AudioSession::setCategory(CategoryType)
-{
-    notImplemented();
-}
-
-AudioSession::CategoryType AudioSession::categoryOverride() const
-{
-    notImplemented();
-    return None;
-}
-
-void AudioSession::setCategoryOverride(CategoryType)
-{
-    notImplemented();
-}
-
-float AudioSession::sampleRate() const
-{
-    Float64 nominalSampleRate;
-    UInt32 nominalSampleRateSize = sizeof(Float64);
-
-    AudioObjectPropertyAddress nominalSampleRateAddress = {
-        kAudioDevicePropertyNominalSampleRate,
-        kAudioObjectPropertyScopeGlobal,
-        kAudioObjectPropertyElementMaster };
-    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &nominalSampleRateAddress, 0, 0, &nominalSampleRateSize, (void*)&nominalSampleRate);
-    if (result)
-        return 0;
-
-    return narrowPrecisionToFloat(nominalSampleRate);
-}
-
-size_t AudioSession::bufferSize() const
-{
-    UInt32 bufferSize;
-    UInt32 bufferSizeSize = sizeof(bufferSize);
-
-    AudioObjectPropertyAddress bufferSizeAddress = {
-        kAudioDevicePropertyBufferFrameSize,
-        kAudioObjectPropertyScopeGlobal,
-        kAudioObjectPropertyElementMaster };
-    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &bufferSizeAddress, 0, 0, &bufferSizeSize, &bufferSize);
-
-    if (result)
-        return 0;
-    return bufferSize;
-}
-
-size_t AudioSession::numberOfOutputChannels() const
-{
-    notImplemented();
-    return 0;
-}
-
-bool AudioSession::tryToSetActive(bool)
-{
-    notImplemented();
-    return true;
-}
-
-size_t AudioSession::preferredBufferSize() const
-{
-    UInt32 bufferSize;
-    UInt32 bufferSizeSize = sizeof(bufferSize);
-
-    AudioObjectPropertyAddress preferredBufferSizeAddress = {
-        kAudioDevicePropertyBufferFrameSizeRange,
-        kAudioObjectPropertyScopeGlobal,
-        kAudioObjectPropertyElementMaster };
-    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &preferredBufferSizeAddress, 0, 0, &bufferSizeSize, &bufferSize);
-
-    if (result)
-        return 0;
-    return bufferSize;
-}
-
-void AudioSession::setPreferredBufferSize(size_t bufferSize)
-{
-    AudioValueRange bufferSizeRange = {0, 0};
-    UInt32 bufferSizeRangeSize = sizeof(AudioValueRange);
-    AudioObjectPropertyAddress bufferSizeRangeAddress = {
-        kAudioDevicePropertyBufferFrameSizeRange,
-        kAudioObjectPropertyScopeGlobal,
-        kAudioObjectPropertyElementMaster
-    };
-    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &bufferSizeRangeAddress, 0, 0, &bufferSizeRangeSize, &bufferSizeRange);
-    if (result)
-        return;
-
-    size_t minBufferSize = static_cast<size_t>(bufferSizeRange.mMinimum);
-    size_t maxBufferSize = static_cast<size_t>(bufferSizeRange.mMaximum);
-    UInt32 bufferSizeOut = std::min(maxBufferSize, std::max(minBufferSize, bufferSize));
-
-    AudioObjectPropertyAddress preferredBufferSizeAddress = {
-        kAudioDevicePropertyBufferFrameSize,
-        kAudioObjectPropertyScopeGlobal,
-        kAudioObjectPropertyElementMaster };
-
-    result = AudioObjectSetPropertyData(defaultDevice(), &preferredBufferSizeAddress, 0, 0, sizeof(bufferSizeOut), (void*)&bufferSizeOut);
-
-#if LOG_DISABLED
-    UNUSED_PARAM(result);
-#else
-    if (result)
-        LOG(Media, "AudioSession::setPreferredBufferSize(%zu) - failed with error %d", bufferSize, static_cast<int>(result));
-    else
-        LOG(Media, "AudioSession::setPreferredBufferSize(%zu)", bufferSize);
-#endif
-}
-
-bool AudioSession::isMuted() const
-{
-    UInt32 mute = 0;
-    UInt32 muteSize = sizeof(mute);
-    AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
-    AudioObjectGetPropertyData(defaultDevice(), &muteAddress, 0, nullptr, &muteSize, &mute);
-    
-    switch (mute) {
-    case 0:
-        return false;
-    case 1:
-        return true;
-    default:
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-}
-
-static OSStatus handleMutePropertyChange(AudioObjectID, UInt32, const AudioObjectPropertyAddress*, void* inClientData)
-{
-    callOnMainThread([inClientData] {
-        reinterpret_cast<AudioSession*>(inClientData)->handleMutedStateChange();
-    });
-    return noErr;
-}
-
-void AudioSession::handleMutedStateChange()
-{
-    if (!m_private)
-        return;
-
-    bool isCurrentlyMuted = isMuted();
-    if (m_private->lastMutedState == isCurrentlyMuted)
-        return;
-
-    for (auto* observer : m_observers)
-        observer->hardwareMutedStateDidChange(this);
-
-    m_private->lastMutedState = isCurrentlyMuted;
-}
-
-void AudioSession::addMutedStateObserver(MutedStateObserver* observer)
-{
-    m_observers.add(observer);
-
-    if (m_observers.size() > 1)
-        return;
-
-    AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
-    AudioObjectAddPropertyListener(defaultDevice(), &muteAddress, handleMutePropertyChange, this);
-}
-
-void AudioSession::removeMutedStateObserver(MutedStateObserver* observer)
-{
-    if (m_observers.size() == 1) {
-        AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
-        AudioObjectRemovePropertyListener(defaultDevice(), &muteAddress, handleMutePropertyChange, this);
-    }
-
-    m_observers.remove(observer);
-}
-
-}
-
-#endif // USE(AUDIO_SESSION) && PLATFORM(MAC)

Copied: trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.mm (from rev 216023, trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.cpp) (0 => 216024)


--- trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.mm	                        (rev 0)
+++ trunk/Source/WebCore/platform/audio/mac/AudioSessionMac.mm	2017-05-01 21:06:39 UTC (rev 216024)
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2013 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 "AudioSession.h"
+
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+
+#include "FloatConversion.h"
+#include "Logging.h"
+#include "NotImplemented.h"
+#include <CoreAudio/AudioHardware.h>
+#include <wtf/BlockPtr.h>
+#include <wtf/HashSet.h>
+#include <wtf/MainThread.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+static AudioDeviceID defaultDevice()
+{
+    AudioDeviceID deviceID = kAudioDeviceUnknown;
+    UInt32 infoSize = sizeof(deviceID);
+
+    AudioObjectPropertyAddress defaultOutputDeviceAddress = {
+        kAudioHardwarePropertyDefaultOutputDevice,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+    OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultOutputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID);
+    if (result)
+        return 0; // error
+    return deviceID;
+}
+
+class AudioSessionPrivate {
+public:
+    AudioSessionPrivate(AudioSession& session, bool mutedState)
+        : weakPtrFactory(&session)
+        , lastMutedState(mutedState) { }
+    WeakPtrFactory<AudioSession> weakPtrFactory;
+    bool lastMutedState;
+    HashSet<AudioSession::Observer*> observers;
+    BlockPtr<void(UInt32, const AudioObjectPropertyAddress*)> muteChangedBlock;
+    BlockPtr<void(UInt32, const AudioObjectPropertyAddress*)> audioInputDeviceChangedBlock;
+    BlockPtr<void(UInt32, const AudioObjectPropertyAddress*)> outputDeviceChangedBlock;
+    mutable std::optional<bool> outputDeviceSupportsLowPowerMode;
+};
+
+AudioSession::AudioSession()
+    : m_private(makeUniqueRef<AudioSessionPrivate>(*this, isMuted()))
+{
+    m_private->outputDeviceChangedBlock = (AudioObjectPropertyListenerBlock)[this, weakThis = m_private->weakPtrFactory.createWeakPtr()] (UInt32, const AudioObjectPropertyAddress*) {
+        if (!weakThis)
+            return;
+
+        m_private->outputDeviceSupportsLowPowerMode = std::nullopt;
+
+        for (auto* observer : m_private->observers)
+            observer->currentAudioOutputDeviceChanged();
+    };
+}
+
+AudioSession::~AudioSession()
+{
+    AudioObjectPropertyAddress outputDeviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+    AudioObjectRemovePropertyListenerBlock(defaultDevice(), &outputDeviceAddress, dispatch_get_main_queue(), m_private->outputDeviceChangedBlock.get());
+}
+
+AudioSession::CategoryType AudioSession::category() const
+{
+    notImplemented();
+    return None;
+}
+
+void AudioSession::setCategory(CategoryType)
+{
+    notImplemented();
+}
+
+AudioSession::CategoryType AudioSession::categoryOverride() const
+{
+    notImplemented();
+    return None;
+}
+
+void AudioSession::setCategoryOverride(CategoryType)
+{
+    notImplemented();
+}
+
+float AudioSession::sampleRate() const
+{
+    Float64 nominalSampleRate;
+    UInt32 nominalSampleRateSize = sizeof(Float64);
+
+    AudioObjectPropertyAddress nominalSampleRateAddress = {
+        kAudioDevicePropertyNominalSampleRate,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &nominalSampleRateAddress, 0, 0, &nominalSampleRateSize, (void*)&nominalSampleRate);
+    if (result)
+        return 0;
+
+    return narrowPrecisionToFloat(nominalSampleRate);
+}
+
+size_t AudioSession::bufferSize() const
+{
+    UInt32 bufferSize;
+    UInt32 bufferSizeSize = sizeof(bufferSize);
+
+    AudioObjectPropertyAddress bufferSizeAddress = {
+        kAudioDevicePropertyBufferFrameSize,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &bufferSizeAddress, 0, 0, &bufferSizeSize, &bufferSize);
+
+    if (result)
+        return 0;
+    return bufferSize;
+}
+
+size_t AudioSession::numberOfOutputChannels() const
+{
+    notImplemented();
+    return 0;
+}
+
+bool AudioSession::tryToSetActive(bool)
+{
+    notImplemented();
+    return true;
+}
+
+size_t AudioSession::preferredBufferSize() const
+{
+    UInt32 bufferSize;
+    UInt32 bufferSizeSize = sizeof(bufferSize);
+
+    AudioObjectPropertyAddress preferredBufferSizeAddress = {
+        kAudioDevicePropertyBufferFrameSizeRange,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &preferredBufferSizeAddress, 0, 0, &bufferSizeSize, &bufferSize);
+
+    if (result)
+        return 0;
+    return bufferSize;
+}
+
+void AudioSession::setPreferredBufferSize(size_t bufferSize)
+{
+    AudioValueRange bufferSizeRange = {0, 0};
+    UInt32 bufferSizeRangeSize = sizeof(AudioValueRange);
+    AudioObjectPropertyAddress bufferSizeRangeAddress = {
+        kAudioDevicePropertyBufferFrameSizeRange,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster
+    };
+    OSStatus result = AudioObjectGetPropertyData(defaultDevice(), &bufferSizeRangeAddress, 0, 0, &bufferSizeRangeSize, &bufferSizeRange);
+    if (result)
+        return;
+
+    size_t minBufferSize = static_cast<size_t>(bufferSizeRange.mMinimum);
+    size_t maxBufferSize = static_cast<size_t>(bufferSizeRange.mMaximum);
+    UInt32 bufferSizeOut = std::min(maxBufferSize, std::max(minBufferSize, bufferSize));
+
+    AudioObjectPropertyAddress preferredBufferSizeAddress = {
+        kAudioDevicePropertyBufferFrameSize,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+
+    result = AudioObjectSetPropertyData(defaultDevice(), &preferredBufferSizeAddress, 0, 0, sizeof(bufferSizeOut), (void*)&bufferSizeOut);
+
+#if LOG_DISABLED
+    UNUSED_PARAM(result);
+#else
+    if (result)
+        LOG(Media, "AudioSession::setPreferredBufferSize(%zu) - failed with error %d", bufferSize, static_cast<int>(result));
+    else
+        LOG(Media, "AudioSession::setPreferredBufferSize(%zu)", bufferSize);
+#endif
+}
+
+bool AudioSession::isMuted() const
+{
+    UInt32 mute = 0;
+    UInt32 muteSize = sizeof(mute);
+    AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
+    AudioObjectGetPropertyData(defaultDevice(), &muteAddress, 0, nullptr, &muteSize, &mute);
+    
+    switch (mute) {
+    case 0:
+        return false;
+    case 1:
+        return true;
+    default:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
+static bool currentDeviceSupportsLowPowerBufferSize()
+{
+    AudioDeviceID deviceID = kAudioDeviceUnknown;
+    UInt32 descriptorSize = sizeof(deviceID);
+    AudioObjectPropertyAddress defaultOutputDeviceDescriptor = {
+        kAudioHardwarePropertyDefaultOutputDevice,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+
+    if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultOutputDeviceDescriptor, 0, 0, &descriptorSize, (void*)&deviceID))
+        return false;
+
+    UInt32 transportType = kAudioDeviceTransportTypeUnknown;
+    descriptorSize = sizeof(transportType);
+    AudioObjectPropertyAddress tranportTypeDescriptor = {
+        kAudioDevicePropertyTransportType,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster,
+    };
+
+    if (AudioObjectGetPropertyData(deviceID, &tranportTypeDescriptor, 0, 0, &descriptorSize, &transportType))
+        return false;
+
+    // Only allow low-power buffer size when using built-in output device, many external devices perform
+    // poorly with a large output buffer.
+    return kAudioDeviceTransportTypeBuiltIn == transportType;
+}
+
+bool AudioSession::outputDeviceSupportsLowPowerMode() const
+{
+    if (!m_private->outputDeviceSupportsLowPowerMode)
+        m_private->outputDeviceSupportsLowPowerMode = currentDeviceSupportsLowPowerBufferSize();
+    return m_private->outputDeviceSupportsLowPowerMode.value();
+}
+
+void AudioSession::addObserver(Observer& observer)
+{
+    ASSERT(!m_private->observers.contains(&observer));
+    m_private->observers.add(&observer);
+
+    if (m_private->observers.size() > 1)
+        return;
+
+    auto weakThis = m_private->weakPtrFactory.createWeakPtr();
+    m_private->muteChangedBlock = (AudioObjectPropertyListenerBlock)[this, weakThis] (UInt32, const AudioObjectPropertyAddress*) {
+        if (!weakThis)
+            return;
+
+        bool isCurrentlyMuted = isMuted();
+        if (m_private->lastMutedState == isCurrentlyMuted)
+            return;
+        m_private->lastMutedState = isCurrentlyMuted;
+
+        for (auto* observer : m_private->observers)
+            observer->hardwareMutedStateDidChange(this);
+    };
+
+    m_private->audioInputDeviceChangedBlock = (AudioObjectPropertyListenerBlock)[this, weakThis] (UInt32, const AudioObjectPropertyAddress*) {
+        if (!weakThis)
+            return;
+
+        for (auto* observer : m_private->observers)
+            observer->currentAudioInputDeviceChanged();
+    };
+
+    AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
+    AudioObjectAddPropertyListenerBlock(defaultDevice(), &muteAddress, dispatch_get_main_queue(), m_private->muteChangedBlock.get());
+
+    AudioObjectPropertyAddress inputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+    AudioObjectAddPropertyListenerBlock(defaultDevice(), &inputDeviceAddress, dispatch_get_main_queue(), m_private->audioInputDeviceChangedBlock.get());
+}
+
+void AudioSession::removeObserver(Observer& observer)
+{
+    ASSERT(m_private->observers.contains(&observer));
+    m_private->observers.remove(&observer);
+
+    if (!m_private->observers.isEmpty())
+        return;
+
+    AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
+    AudioObjectRemovePropertyListenerBlock(defaultDevice(), &muteAddress, dispatch_get_main_queue(), m_private->muteChangedBlock.get());
+
+    AudioObjectPropertyAddress inputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+    AudioObjectRemovePropertyListenerBlock(defaultDevice(), &inputDeviceAddress, dispatch_get_main_queue(), m_private->audioInputDeviceChangedBlock.get());
+}
+
+}
+
+#endif // USE(AUDIO_SESSION) && PLATFORM(MAC)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to