blob: 5c5ca355b9a6267f2ea9b552225cf0f250c3845c [file] [log] [blame]
// Copyright (c) 2013 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 "base/bind.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/mac/mac_util.h"
#include "base/message_loop/message_loop.h"
#include "base/pending_task.h"
#include "media/audio/mac/audio_low_latency_output_mac.h"
namespace media {
// Property address to monitor for device changes.
const AudioObjectPropertyAddress
AudioDeviceListenerMac::kDeviceChangePropertyAddress = {
kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
// Callback from the system when the default device changes; this must be called
// on the MessageLoop that created the AudioManager.
// static
OSStatus AudioDeviceListenerMac::OnDefaultDeviceChanged(
AudioObjectID object, UInt32 num_addresses,
const AudioObjectPropertyAddress addresses[], void* context) {
if (object != kAudioObjectSystemObject)
return noErr;
for (UInt32 i = 0; i < num_addresses; ++i) {
if (addresses[i].mSelector == kDeviceChangePropertyAddress.mSelector &&
addresses[i].mScope == kDeviceChangePropertyAddress.mScope &&
addresses[i].mElement == kDeviceChangePropertyAddress.mElement &&
context) {
static_cast<AudioDeviceListenerMac*>(context)->listener_cb_.Run();
break;
}
}
return noErr;
}
AudioDeviceListenerMac::AudioDeviceListenerMac(
const base::Closure& listener_cb) {
OSStatus result = AudioObjectAddPropertyListener(
kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
&AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
if (result != noErr) {
OSSTATUS_DLOG(ERROR, result)
<< "AudioObjectAddPropertyListener() failed!";
return;
}
listener_cb_ = listener_cb;
}
AudioDeviceListenerMac::~AudioDeviceListenerMac() {
DCHECK(thread_checker_.CalledOnValidThread());
if (listener_cb_.is_null())
return;
// Since we're running on the same CFRunLoop, there can be no outstanding
// callbacks in flight.
OSStatus result = AudioObjectRemovePropertyListener(
kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
&AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
<< "AudioObjectRemovePropertyListener() failed!";
}
} // namespace media