Index: media/audio/mac/audio_device_listener_mac.cc |
diff --git a/media/audio/mac/audio_device_listener_mac.cc b/media/audio/mac/audio_device_listener_mac.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3bae85df7f036447526bb183cf1d388c0599b1e3 |
--- /dev/null |
+++ b/media/audio/mac/audio_device_listener_mac.cc |
@@ -0,0 +1,98 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/audio/mac/audio_device_listener_mac.h" |
+ |
+#include <CoreAudio/CoreAudio.h> |
+#include <vector> |
+ |
+#include "base/logging.h" |
+#include "base/mac/mac_logging.h" |
+#include "base/synchronization/lock.h" |
+ |
+namespace { |
+ |
+class ListenerManager { |
+ public: |
+ ListenerManager(); |
+ void AddListener(media::AudioDeviceListenerMac* listener); |
+ void RemoveListener(media::AudioDeviceListenerMac* listener); |
+ |
+ private: |
+ // Callback from system when the default device changes. This can be called |
+ // either on the main thread or on a audio thread managed by the system |
+ // (depending on what kAudioHardwarePropertyRunLoop is set to). |
+ static OSStatus OnDefaultDeviceChanged( |
+ AudioObjectID object, |
+ UInt32 size, |
+ const AudioObjectPropertyAddress addresses[], |
+ void* context); |
+ |
+ std::vector<media::AudioDeviceListenerMac*> listeners_; |
+ base::Lock listener_lock_; |
+}; |
+ |
+ListenerManager::ListenerManager() { |
+ AudioObjectPropertyAddress property = { |
+ kAudioHardwarePropertyDefaultOutputDevice, |
+ kAudioObjectPropertyScopeGlobal, |
+ kAudioObjectPropertyElementMaster |
+ }; |
+ OSStatus result = AudioObjectAddPropertyListener( |
+ kAudioObjectSystemObject, |
+ &property, |
+ &ListenerManager::OnDefaultDeviceChanged, |
+ this); |
+ OSSTATUS_DCHECK(result == noErr, result); |
+} |
+ |
+void ListenerManager::AddListener(media::AudioDeviceListenerMac* listener) { |
+ base::AutoLock auto_lock(listener_lock_); |
+ listeners_.push_back(listener); |
+} |
+ |
+void ListenerManager::RemoveListener(media::AudioDeviceListenerMac* listener) { |
+ base::AutoLock auto_lock(listener_lock_); |
+ listeners_.erase(std::find(listeners_.begin(), listeners_.end(), listener)); |
+} |
+ |
+// static |
+OSStatus ListenerManager::OnDefaultDeviceChanged( |
+ AudioObjectID object, |
+ UInt32 size, |
+ const AudioObjectPropertyAddress addresses[], |
+ void* context) { |
+ ListenerManager* manager = static_cast<ListenerManager*>(context); |
+ base::AutoLock auto_lock(manager->listener_lock_); |
+ for (std::vector<media::AudioDeviceListenerMac*>::iterator it = |
+ manager->listeners_.begin(); it != manager->listeners_.end(); ++it) { |
+ (*it)->OnDefaultDeviceChanged(); |
+ } |
+ return noErr; |
+} |
+ |
+ListenerManager* g_listener_manager = NULL; |
+ |
+} // namespace |
+ |
+namespace media { |
+ |
+AudioDeviceListenerMac::AudioDeviceListenerMac(const base::Closure& listener_cb) |
+ : listener_cb_(listener_cb) { |
+ if (!g_listener_manager) |
+ g_listener_manager = new ListenerManager; |
+ g_listener_manager->AddListener(this); |
+} |
+ |
+AudioDeviceListenerMac::~AudioDeviceListenerMac() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(g_listener_manager); |
+ g_listener_manager->RemoveListener(this); |
+} |
+ |
+void AudioDeviceListenerMac::OnDefaultDeviceChanged() { |
+ listener_cb_.Run(); |
+} |
+ |
+} // namespace media |