1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/audio/mac/audio_device_listener_mac.h" 6 7#include "base/bind.h" 8#include "base/files/file_path.h" 9#include "base/logging.h" 10#include "base/mac/mac_logging.h" 11#include "base/mac/mac_util.h" 12#include "base/message_loop/message_loop.h" 13#include "base/pending_task.h" 14 15namespace media { 16 17// Property address to monitor for device changes. 18const AudioObjectPropertyAddress 19AudioDeviceListenerMac::kDeviceChangePropertyAddress = { 20 kAudioHardwarePropertyDefaultOutputDevice, 21 kAudioObjectPropertyScopeGlobal, 22 kAudioObjectPropertyElementMaster 23}; 24 25// Callback from the system when the default device changes; this must be called 26// on the MessageLoop that created the AudioManager. 27// static 28OSStatus AudioDeviceListenerMac::OnDefaultDeviceChanged( 29 AudioObjectID object, UInt32 num_addresses, 30 const AudioObjectPropertyAddress addresses[], void* context) { 31 if (object != kAudioObjectSystemObject) 32 return noErr; 33 34 for (UInt32 i = 0; i < num_addresses; ++i) { 35 if (addresses[i].mSelector == kDeviceChangePropertyAddress.mSelector && 36 addresses[i].mScope == kDeviceChangePropertyAddress.mScope && 37 addresses[i].mElement == kDeviceChangePropertyAddress.mElement && 38 context) { 39 static_cast<AudioDeviceListenerMac*>(context)->listener_cb_.Run(); 40 break; 41 } 42 } 43 44 return noErr; 45} 46 47AudioDeviceListenerMac::AudioDeviceListenerMac( 48 const base::Closure& listener_cb) { 49 OSStatus result = AudioObjectAddPropertyListener( 50 kAudioObjectSystemObject, &kDeviceChangePropertyAddress, 51 &AudioDeviceListenerMac::OnDefaultDeviceChanged, this); 52 53 if (result != noErr) { 54 OSSTATUS_DLOG(ERROR, result) 55 << "AudioObjectAddPropertyListener() failed!"; 56 return; 57 } 58 59 listener_cb_ = listener_cb; 60} 61 62AudioDeviceListenerMac::~AudioDeviceListenerMac() { 63 DCHECK(thread_checker_.CalledOnValidThread()); 64 if (listener_cb_.is_null()) 65 return; 66 67 // Since we're running on the same CFRunLoop, there can be no outstanding 68 // callbacks in flight. 69 OSStatus result = AudioObjectRemovePropertyListener( 70 kAudioObjectSystemObject, &kDeviceChangePropertyAddress, 71 &AudioDeviceListenerMac::OnDefaultDeviceChanged, this); 72 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 73 << "AudioObjectRemovePropertyListener() failed!"; 74} 75 76} // namespace media 77