1 // Copyright 2017 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/scoped_audio_unit.h"
6
7 #include "base/mac/mac_logging.h"
8
9 namespace media {
10
11 constexpr AudioComponentDescription desc = {kAudioUnitType_Output,
12 kAudioUnitSubType_HALOutput,
13 kAudioUnitManufacturer_Apple, 0, 0};
14
DestroyAudioUnit(AudioUnit audio_unit)15 static void DestroyAudioUnit(AudioUnit audio_unit) {
16 OSStatus result = AudioUnitUninitialize(audio_unit);
17 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
18 << "AudioUnitUninitialize() failed : " << audio_unit;
19 result = AudioComponentInstanceDispose(audio_unit);
20 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
21 << "AudioComponentInstanceDispose() failed : " << audio_unit;
22 }
23
ScopedAudioUnit(AudioDeviceID device,AUElement element)24 ScopedAudioUnit::ScopedAudioUnit(AudioDeviceID device, AUElement element) {
25 AudioComponent comp = AudioComponentFindNext(0, &desc);
26 if (!comp)
27 return;
28
29 AudioUnit audio_unit;
30 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit);
31 if (result != noErr) {
32 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed.";
33 return;
34 }
35
36 const UInt32 enable_input_io = element == AUElement::INPUT ? 1 : 0;
37 result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO,
38 kAudioUnitScope_Input, AUElement::INPUT,
39 &enable_input_io, sizeof(enable_input_io));
40 if (result != noErr) {
41 OSSTATUS_DLOG(ERROR, result)
42 << "Failed to set input enable IO for audio unit.";
43 DestroyAudioUnit(audio_unit);
44 return;
45 }
46
47 const UInt32 enable_output_io = !enable_input_io;
48 result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO,
49 kAudioUnitScope_Output, AUElement::OUTPUT,
50 &enable_output_io, sizeof(enable_output_io));
51 if (result != noErr) {
52 OSSTATUS_DLOG(ERROR, result)
53 << "Failed to set output enable IO for audio unit.";
54 DestroyAudioUnit(audio_unit);
55 return;
56 }
57
58 result = AudioUnitSetProperty(
59 audio_unit, kAudioOutputUnitProperty_CurrentDevice,
60 kAudioUnitScope_Global, 0, &device, sizeof(AudioDeviceID));
61 if (result != noErr) {
62 OSSTATUS_DLOG(ERROR, result)
63 << "Failed to set current device for audio unit.";
64 DestroyAudioUnit(audio_unit);
65 return;
66 }
67
68 audio_unit_ = audio_unit;
69 }
70
~ScopedAudioUnit()71 ScopedAudioUnit::~ScopedAudioUnit() {
72 if (audio_unit_)
73 DestroyAudioUnit(audio_unit_);
74 }
75
76 } // namespace media
77