audio_device_listener_mac.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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.h"
13#include "base/pending_task.h"
14#include "media/audio/mac/audio_low_latency_output_mac.h"
15
16namespace media {
17
18// Property address to monitor for device changes.
19const AudioObjectPropertyAddress
20AudioDeviceListenerMac::kDeviceChangePropertyAddress = {
21  kAudioHardwarePropertyDefaultOutputDevice,
22  kAudioObjectPropertyScopeGlobal,
23  kAudioObjectPropertyElementMaster
24};
25
26// Callback from the system when the default device changes; this must be called
27// on the MessageLoop that created the AudioManager.
28// static
29OSStatus AudioDeviceListenerMac::OnDefaultDeviceChanged(
30    AudioObjectID object, UInt32 num_addresses,
31    const AudioObjectPropertyAddress addresses[], void* context) {
32  if (object != kAudioObjectSystemObject)
33    return noErr;
34
35  for (UInt32 i = 0; i < num_addresses; ++i) {
36    if (addresses[i].mSelector == kDeviceChangePropertyAddress.mSelector &&
37        addresses[i].mScope == kDeviceChangePropertyAddress.mScope &&
38        addresses[i].mElement == kDeviceChangePropertyAddress.mElement &&
39        context) {
40      AudioDeviceListenerMac* p_this =
41          static_cast<AudioDeviceListenerMac*>(context);
42      DCHECK(p_this->thread_checker_.CalledOnValidThread());
43      p_this->listener_cb_.Run();
44      break;
45    }
46  }
47
48  return noErr;
49}
50
51AudioDeviceListenerMac::AudioDeviceListenerMac(
52    const base::Closure& listener_cb) {
53  OSStatus result = AudioObjectAddPropertyListener(
54      kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
55      &AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
56
57  if (result != noErr) {
58    OSSTATUS_DLOG(ERROR, result)
59        << "AudioObjectAddPropertyListener() failed!";
60    return;
61  }
62
63  listener_cb_ = listener_cb;
64}
65
66AudioDeviceListenerMac::~AudioDeviceListenerMac() {
67  DCHECK(thread_checker_.CalledOnValidThread());
68  if (listener_cb_.is_null())
69    return;
70
71  // Since we're running on the same CFRunLoop, there can be no outstanding
72  // callbacks in flight.
73  OSStatus result = AudioObjectRemovePropertyListener(
74      kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
75      &AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
76  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
77      << "AudioObjectRemovePropertyListener() failed!";
78}
79
80}  // namespace media
81