| 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
|
|
|