Unreviewed, rolling out r216024.
authorryanhaddad@apple.com <ryanhaddad@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 May 2017 01:07:44 +0000 (01:07 +0000)
committerryanhaddad@apple.com <ryanhaddad@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 2 May 2017 01:07:44 +0000 (01:07 +0000)
This change caused ios-simulator LayoutTests to exit early
with assertion failures.

Reverted changeset:

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

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@216050 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/platform/audio/AudioSession.cpp
Source/WebCore/platform/audio/AudioSession.h
Source/WebCore/platform/audio/ios/AudioSessionIOS.mm
Source/WebCore/platform/audio/mac/AudioSessionMac.cpp [moved from Source/WebCore/platform/audio/mac/AudioSessionMac.mm with 55% similarity]

index 0a40267..e5b1cb6 100644 (file)
@@ -1,3 +1,16 @@
+2017-05-01  Ryan Haddad  <ryanhaddad@apple.com>
+
+        Unreviewed, rolling out r216024.
+
+        This change caused ios-simulator LayoutTests to exit early
+        with assertion failures.
+
+        Reverted changeset:
+
+        "Add audio device change notifications to AudioSession."
+        https://bugs.webkit.org/show_bug.cgi?id=171403
+        http://trac.webkit.org/changeset/216024
+
 2017-05-01  Timothy Horton  <timothy_horton@apple.com>
 
         Expose viewport-fit instead of clip-to-safe-area
index 3581ad7..54680aa 100644 (file)
                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.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD54DE4917469C6D005E5B36 /* AudioSessionMac.mm */; };
+               CD54DE4B17469C6D005E5B36 /* AudioSessionMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */; };
                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 */; };
                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.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioSessionMac.mm; sourceTree = "<group>"; };
+               CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioSessionMac.cpp; 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>"; };
                                073B87631E43859D0071C0EC /* AudioSampleBufferList.h */,
                                073B87651E43859D0071C0EC /* AudioSampleDataSource.h */,
                                073B87641E43859D0071C0EC /* AudioSampleDataSource.mm */,
-                               CD54DE4917469C6D005E5B36 /* AudioSessionMac.mm */,
+                               CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */,
                                073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */,
                                073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */,
                                CDC734121977896C0046BFC5 /* CARingBuffer.cpp */,
                                FD8C46EB154608E700A5910C /* AudioScheduledSourceNode.cpp in Sources */,
                                CDA79824170A258300D45C55 /* AudioSession.cpp in Sources */,
                                CDA79827170A279100D45C55 /* AudioSessionIOS.mm in Sources */,
-                               CD54DE4B17469C6D005E5B36 /* AudioSessionMac.mm in Sources */,
+                               CD54DE4B17469C6D005E5B36 /* AudioSessionMac.cpp in Sources */,
                                CD8A7BBB197735FE00CBD643 /* AudioSourceProviderAVFObjC.mm in Sources */,
                                FDB052DF1561A42C00B500D6 /* AudioSummingJunction.cpp in Sources */,
                                BE88E0D81715D2A200658D98 /* AudioTrack.cpp in Sources */,
index ee1d0cb..89f8edb 100644 (file)
@@ -511,8 +511,8 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
 
     registerWithDocument(document);
 
-#if USE(AUDIO_SESSION)
-    AudioSession::sharedSession().addObserver(*this);
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+    AudioSession::sharedSession().addMutedStateObserver(this);
 #endif
 }
 
@@ -528,8 +528,8 @@ HTMLMediaElement::~HTMLMediaElement()
     setShouldDelayLoadEvent(false);
     unregisterWithDocument(document());
 
-#if USE(AUDIO_SESSION)
-    AudioSession::sharedSession().removeObserver(*this);
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+    AudioSession::sharedSession().removeMutedStateObserver(this);
 #endif
 
 #if ENABLE(VIDEO_TRACK)
@@ -3420,7 +3420,7 @@ void HTMLMediaElement::setMuted(bool muted)
     scheduleUpdatePlaybackControlsManager();
 }
 
-#if USE(AUDIO_SESSION)
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
 void HTMLMediaElement::hardwareMutedStateDidChange(AudioSession* session)
 {
     if (!session->isMuted())
index 16f5a7c..96e0a95 100644 (file)
@@ -51,7 +51,7 @@
 #include "VideoTrack.h"
 #endif
 
-#if USE(AUDIO_SESSION)
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
 #include "AudioSession.h"
 #endif
 
@@ -125,8 +125,8 @@ class HTMLMediaElement
     , private TextTrackClient
     , private VideoTrackClient
 #endif
-#if USE(AUDIO_SESSION)
-    , private AudioSession::Observer
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
+    , private AudioSession::MutedStateObserver
 #endif
 {
 public:
@@ -817,7 +817,7 @@ private:
 
     void pageMutedStateDidChange() override;
 
-#if USE(AUDIO_SESSION)
+#if USE(AUDIO_SESSION) && PLATFORM(MAC)
     void hardwareMutedStateDidChange(AudioSession*) final;
 #endif
 
index cc3e067..31c5d7f 100644 (file)
@@ -44,7 +44,7 @@ class AudioSessionPrivate {
 };
 
 AudioSession::AudioSession()
-    : m_private(makeUniqueRef<AudioSessionPrivate>())
+    : m_private(nullptr)
 {
     notImplemented();
 }
index e11ca8d..aa64dc3 100644 (file)
 
 #if USE(AUDIO_SESSION)
 
-#include <wtf/Forward.h>
+#include <memory>
+#include <wtf/HashSet.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/Noncopyable.h>
-#include <wtf/UniqueRef.h>
 
 namespace WebCore {
 
@@ -43,19 +44,6 @@ class AudioSession {
 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,
@@ -80,15 +68,26 @@ public:
     size_t preferredBufferSize() const;
     void setPreferredBufferSize(size_t);
 
-    bool outputDeviceSupportsLowPowerMode() const;
+    class MutedStateObserver {
+    public:
+        virtual ~MutedStateObserver() { }
+
+        virtual void hardwareMutedStateDidChange(AudioSession*) = 0;
+    };
+
+    void addMutedStateObserver(MutedStateObserver*);
+    void removeMutedStateObserver(MutedStateObserver*);
+
     bool isMuted() const;
+    void handleMutedStateChange();
 
 private:
     friend class NeverDestroyed<AudioSession>;
     AudioSession();
     ~AudioSession();
 
-    UniqueRef<AudioSessionPrivate> m_private;
+    std::unique_ptr<AudioSessionPrivate> m_private;
+    HashSet<MutedStateObserver*> m_observers;
 };
 
 }
index b1b2bf9..0216fd9 100644 (file)
 #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)
@@ -47,10 +44,6 @@ SOFT_LINK_POINTER(AVFoundation, AVAudioSessionCategoryRecord, NSString *)
 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()
@@ -60,10 +53,7 @@ SOFT_LINK_POINTER(AVFoundation, AVAudioSessionRouteChangePreviousRouteKey, NSStr
 #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
@@ -87,19 +77,17 @@ static const char* categoryName(AudioSession::CategoryType category)
 
 class AudioSessionPrivate {
 public:
-    AudioSessionPrivate(AudioSession& audioSession)
-        : weakPtrFactory(&audioSession)
-    {
-    }
-
-    WeakPtrFactory<AudioSession> weakPtrFactory;
-    AudioSession::CategoryType categoryOverride { AudioSession::None };
-    HashSet<AudioSession::Observer*> observers;
-    Vector<RetainPtr<id>> notificationCallbacks;
+    AudioSessionPrivate(AudioSession*);
+    AudioSession::CategoryType m_categoryOverride;
 };
 
+AudioSessionPrivate::AudioSessionPrivate(AudioSession*)
+    : m_categoryOverride(AudioSession::None)
+{
+}
+
 AudioSession::AudioSession()
-    : m_private(makeUniqueRef<AudioSessionPrivate>(*this))
+    : m_private(std::make_unique<AudioSessionPrivate>(this))
 {
 }
 
@@ -166,16 +154,16 @@ AudioSession::CategoryType AudioSession::category() const
 
 void AudioSession::setCategoryOverride(CategoryType category)
 {
-    if (m_private->categoryOverride == category)
+    if (m_private->m_categoryOverride == category)
         return;
 
-    m_private->categoryOverride = category;
+    m_private->m_categoryOverride = category;
     setCategory(category);
 }
 
 AudioSession::CategoryType AudioSession::categoryOverride() const
 {
-    return m_private->categoryOverride;
+    return m_private->m_categoryOverride;
 }
 
 float AudioSession::sampleRate() const
@@ -213,90 +201,6 @@ void AudioSession::setPreferredBufferSize(size_t bufferSize)
     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)
 #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 {
 
@@ -56,36 +53,18 @@ static AudioDeviceID defaultDevice()
 
 class AudioSessionPrivate {
 public:
-    AudioSessionPrivate(AudioSession& session, bool mutedState)
-        : weakPtrFactory(&session)
-        , lastMutedState(mutedState) { }
-    WeakPtrFactory<AudioSession> weakPtrFactory;
+    AudioSessionPrivate(bool mutedState)
+        : lastMutedState(mutedState) { }
     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(std::make_unique<AudioSessionPrivate>(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
@@ -222,91 +201,48 @@ bool AudioSession::isMuted() const
     }
 }
 
-static bool currentDeviceSupportsLowPowerBufferSize()
+static OSStatus handleMutePropertyChange(AudioObjectID, UInt32, const AudioObjectPropertyAddress*, void* inClientData)
 {
-    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;
+    callOnMainThread([inClientData] {
+        reinterpret_cast<AudioSession*>(inClientData)->handleMutedStateChange();
+    });
+    return noErr;
 }
 
-bool AudioSession::outputDeviceSupportsLowPowerMode() const
+void AudioSession::handleMutedStateChange()
 {
-    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)
+    if (!m_private)
         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();
-    };
+    bool isCurrentlyMuted = isMuted();
+    if (m_private->lastMutedState == isCurrentlyMuted)
+        return;
 
-    AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
-    AudioObjectAddPropertyListenerBlock(defaultDevice(), &muteAddress, dispatch_get_main_queue(), m_private->muteChangedBlock.get());
+    for (auto* observer : m_observers)
+        observer->hardwareMutedStateDidChange(this);
 
-    AudioObjectPropertyAddress inputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-    AudioObjectAddPropertyListenerBlock(defaultDevice(), &inputDeviceAddress, dispatch_get_main_queue(), m_private->audioInputDeviceChangedBlock.get());
+    m_private->lastMutedState = isCurrentlyMuted;
 }
 
-void AudioSession::removeObserver(Observer& observer)
+void AudioSession::addMutedStateObserver(MutedStateObserver* observer)
 {
-    ASSERT(m_private->observers.contains(&observer));
-    m_private->observers.remove(&observer);
+    m_observers.add(observer);
 
-    if (!m_private->observers.isEmpty())
+    if (m_observers.size() > 1)
         return;
 
     AudioObjectPropertyAddress muteAddress = { kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
-    AudioObjectRemovePropertyListenerBlock(defaultDevice(), &muteAddress, dispatch_get_main_queue(), m_private->muteChangedBlock.get());
+    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);
+    }
 
-    AudioObjectPropertyAddress inputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-    AudioObjectRemovePropertyListenerBlock(defaultDevice(), &inputDeviceAddress, dispatch_get_main_queue(), m_private->audioInputDeviceChangedBlock.get());
+    m_observers.remove(observer);
 }
 
 }