audio_device_listener_mac.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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#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      static_cast<AudioDeviceListenerMac*>(context)->listener_cb_.Run();
41      break;
42    }
43  }
44
45  return noErr;
46}
47
48AudioDeviceListenerMac::AudioDeviceListenerMac(
49    const base::Closure& listener_cb) {
50  OSStatus result = AudioObjectAddPropertyListener(
51      kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
52      &AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
53
54  if (result != noErr) {
55    OSSTATUS_DLOG(ERROR, result)
56        << "AudioObjectAddPropertyListener() failed!";
57    return;
58  }
59
60  listener_cb_ = listener_cb;
61}
62
63AudioDeviceListenerMac::~AudioDeviceListenerMac() {
64  DCHECK(thread_checker_.CalledOnValidThread());
65  if (listener_cb_.is_null())
66    return;
67
68  // Since we're running on the same CFRunLoop, there can be no outstanding
69  // callbacks in flight.
70  OSStatus result = AudioObjectRemovePropertyListener(
71      kAudioObjectSystemObject, &kDeviceChangePropertyAddress,
72      &AudioDeviceListenerMac::OnDefaultDeviceChanged, this);
73  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
74      << "AudioObjectRemovePropertyListener() failed!";
75}
76
77}  // namespace media
78