1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h"
12bc669ace8f09d73e95f923253ecdadd366f9b7f1pbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <unistd.h>             // getpid()
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define WEBRTC_CA_RETURN_ON_ERR(expr)                                     \
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    do {                                                                \
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = expr;                                                     \
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr) {                                             \
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            logCAMsg(kTraceError, kTraceAudioDevice, _id,    \
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "Error in " #expr, (const char *)&err);                 \
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;                                                  \
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }                                                               \
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } while(0)
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define WEBRTC_CA_LOG_ERR(expr)                                           \
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    do {                                                                \
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = expr;                                                     \
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr) {                                             \
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            logCAMsg(kTraceError, kTraceAudioDevice, _id,    \
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "Error in " #expr, (const char *)&err);                 \
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }                                                               \
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } while(0)
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#define WEBRTC_CA_LOG_WARN(expr)                                           \
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    do {                                                                 \
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = expr;                                                      \
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr) {                                              \
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            logCAMsg(kTraceWarning, kTraceAudioDevice, _id,  \
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "Error in " #expr, (const char *)&err);                  \
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }                                                                \
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } while(0)
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
4664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::AudioMixerManagerMac(const int32_t id) :
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _id(id),
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceID(kAudioObjectUnknown),
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceID(kAudioObjectUnknown),
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _noInputChannels(0),
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _noOutputChannels(0)
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "%s constructed", __FUNCTION__);
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioMixerManagerMac::~AudioMixerManagerMac()
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "%s destructed", __FUNCTION__);
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Close();
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete &_critSect;
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//	                                PUBLIC METHODS
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
7264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::Close()
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 __FUNCTION__);
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CloseSpeaker();
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CloseMicrophone();
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
8664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::CloseSpeaker()
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 __FUNCTION__);
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceID = kAudioObjectUnknown;
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _noOutputChannels = 0;
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
9964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::CloseMicrophone()
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 __FUNCTION__);
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceID = kAudioObjectUnknown;
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _noInputChannels = 0;
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::OpenSpeaker(AudioDeviceID deviceID)
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::OpenSpeaker(id=%d)", deviceID);
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    pid_t hogPid = -1;
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputDeviceID = deviceID;
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check which process, if any, has hogged the device.
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyHogMode,
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeOutput, 0 };
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    size = sizeof(hogPid);
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID,
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            &propertyAddress, 0, NULL, &size, &hogPid));
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hogPid == -1)
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " No process has hogged the input device");
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // getpid() is apparently "always successful"
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (hogPid == getpid())
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Our process has hogged the input device");
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Another process (pid = %d) has hogged the input device",
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     static_cast<int> (hogPid));
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // get number of channels from stream format
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Get the stream format, to be able to read the number of channels.
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioStreamBasicDescription streamFormat;
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    size = sizeof(AudioStreamBasicDescription);
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(&streamFormat, 0, size);
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID,
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            &propertyAddress, 0, NULL, &size, &streamFormat));
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _noOutputChannels = streamFormat.mChannelsPerFrame;
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::OpenMicrophone(AudioDeviceID deviceID)
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::OpenMicrophone(id=%d)", deviceID);
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    pid_t hogPid = -1;
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _inputDeviceID = deviceID;
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check which process, if any, has hogged the device.
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyHogMode,
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeInput, 0 };
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    size = sizeof(hogPid);
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID,
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            &propertyAddress, 0, NULL, &size, &hogPid));
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hogPid == -1)
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " No process has hogged the input device");
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // getpid() is apparently "always successful"
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (hogPid == getpid())
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Our process has hogged the input device");
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Another process (pid = %d) has hogged the input device",
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     static_cast<int> (hogPid));
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // get number of channels from stream format
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Get the stream format, to be able to read the number of channels.
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioStreamBasicDescription streamFormat;
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    size = sizeof(AudioStreamBasicDescription);
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memset(&streamFormat, 0, size);
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID,
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            &propertyAddress, 0, NULL, &size, &streamFormat));
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _noInputChannels = streamFormat.mChannelsPerFrame;
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioMixerManagerMac::SpeakerIsInitialized() const
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s",
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 __FUNCTION__);
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_outputDeviceID != kAudioObjectUnknown);
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioMixerManagerMac::MicrophoneIsInitialized() const
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s",
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 __FUNCTION__);
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_inputDeviceID != kAudioObjectUnknown);
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
23664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SetSpeakerVolume(uint32_t volume)
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::SetSpeakerVolume(volume=%u)", volume);
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool success = false;
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 - 1.0, convert from 0 -255
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const Float32 vol = (Float32)(volume / 255.0);
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(vol <= 1.0 && vol >= 0.0);
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master volume control?
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = {
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput,
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            0 };
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(vol);
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID,
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, size, &vol));
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noOutputChannels; i++)
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err == noErr && isSettable)
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            size = sizeof(vol);
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID,
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    &propertyAddress, 0, NULL, size, &vol));
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        success = true;
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!success)
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Unable to set a volume on any output channel");
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
30264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SpeakerVolume(uint32_t& volume) const
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    unsigned int channels = 0;
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Float32 channelVol = 0;
316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Float32 vol = 0;
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the device have a master volume control?
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = {
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput,
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            0 };
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID,
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hasProperty)
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(vol);
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID,
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, &size, &vol));
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // vol 0.0 to 1.0 -> convert to 0 - 255
33264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org        volume = static_cast<uint32_t> (vol * 255 + 0.5);
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Otherwise get the average volume across channels.
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        vol = 0;
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (UInt32 i = 1; i <= _noOutputChannels; i++)
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            channelVol = 0;
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            propertyAddress.mElement = i;
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            hasProperty = AudioObjectHasProperty(_outputDeviceID,
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (hasProperty)
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                size = sizeof(channelVol);
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID,
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        &propertyAddress, 0, NULL, &size, &channelVol));
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                vol += channelVol;
350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                channels++;
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (channels == 0)
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Unable to get a volume on any channel");
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(channels > 0);
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // vol 0.0 to 1.0 -> convert to 0 - 255
36364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org        volume = static_cast<uint32_t> (255 * vol / channels + 0.5);
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "     AudioMixerManagerMac::SpeakerVolume() => vol=%i", vol);
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
37264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
37364a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::MaxSpeakerVolume(uint32_t& maxVolume) const
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 to 1.0
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // we convert that to 0 - 255
385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    maxVolume = 255;
386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
39064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
39164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::MinSpeakerVolume(uint32_t& minVolume) const
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 to 1.0
402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // we convert that to 0 - 255
403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    minVolume = 0;
404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
40864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
40964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::SpeakerVolumeStepSize(uint16_t& stepSize) const
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 to 1.0
420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // we convert that to 0 - 255
421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stepSize = 1;
422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
42664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SpeakerVolumeIsAvailable(bool& available)
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master volume control?
438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = {
440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput,
441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            0 };
442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noOutputChannels; i++)
453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr || !isSettable)
459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            available = false;
461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Volume cannot be set for output channel %d, err=%d",
463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         i, err);
464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = true;
469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
47264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SpeakerMuteIsAvailable(bool& available)
473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master mute control?
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute,
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeOutput, 0 };
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noOutputChannels; i++)
498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr || !isSettable)
504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            available = false;
506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Mute cannot be set for output channel %d, err=%d",
508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         i, err);
509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = true;
514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
51764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SetSpeakerMute(bool enable)
518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::SetSpeakerMute(enable=%u)", enable);
521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 mute = enable ? 1 : 0;
534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool success = false;
535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the render device have a master mute control?
537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute,
539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeOutput, 0 };
540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(mute);
546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID,
547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, size, &mute));
548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noOutputChannels; i++)
554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress,
558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err == noErr && isSettable)
560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            size = sizeof(mute);
562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID,
563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    &propertyAddress, 0, NULL, size, &mute));
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        success = true;
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!success)
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Unable to set mute on any input channel");
572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
57864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SpeakerMute(bool& enabled) const
579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    unsigned int channels = 0;
591b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 channelMuted = 0;
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 muted = 0;
593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the device have a master volume control?
595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute,
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeOutput, 0 };
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID,
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hasProperty)
601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(muted);
603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID,
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, &size, &muted));
605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // 1 means muted
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = static_cast<bool> (muted);
608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Otherwise check if all channels are muted.
611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (UInt32 i = 1; i <= _noOutputChannels; i++)
612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            muted = 0;
614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            propertyAddress.mElement = i;
615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            hasProperty = AudioObjectHasProperty(_outputDeviceID,
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (hasProperty)
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                size = sizeof(channelMuted);
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID,
621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        &propertyAddress, 0, NULL, &size, &channelMuted));
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                muted = (muted && channelMuted);
624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                channels++;
625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (channels == 0)
629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Unable to get mute for any channel");
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(channels > 0);
636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // 1 means muted
637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = static_cast<bool> (muted);
638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "     AudioMixerManagerMac::SpeakerMute() => enabled=%d, enabled");
642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
64664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::StereoPlayoutIsAvailable(bool& available)
647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_outputDeviceID == kAudioObjectUnknown)
649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = (_noOutputChannels == 2);
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
65964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::StereoRecordingIsAvailable(bool& available)
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = (_noInputChannels == 2);
669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
67264a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::MicrophoneMuteIsAvailable(bool& available)
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master mute control?
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute,
686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeInput, 0 };
687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noInputChannels; i++)
698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr || !isSettable)
704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            available = false;
706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Mute cannot be set for output channel %d, err=%d",
708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         i, err);
709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = true;
714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
71764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SetMicrophoneMute(bool enable)
718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::SetMicrophoneMute(enable=%u)", enable);
721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 mute = enable ? 1 : 0;
734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool success = false;
735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master mute control?
737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute,
739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeInput, 0 };
740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(mute);
746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID,
747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, size, &mute));
748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noInputChannels; i++)
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err == noErr && isSettable)
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            size = sizeof(mute);
762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID,
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    &propertyAddress, 0, NULL, size, &mute));
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        success = true;
766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!success)
769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Unable to set mute on any input channel");
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
77864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::MicrophoneMute(bool& enabled) const
779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    unsigned int channels = 0;
791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 channelMuted = 0;
792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 muted = 0;
793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the device have a master volume control?
795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute,
797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kAudioDevicePropertyScopeInput, 0 };
798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean hasProperty = AudioObjectHasProperty(_inputDeviceID,
799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hasProperty)
801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(muted);
803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID,
804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, &size, &muted));
805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // 1 means muted
807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = static_cast<bool> (muted);
808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Otherwise check if all channels are muted.
811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (UInt32 i = 1; i <= _noInputChannels; i++)
812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            muted = 0;
814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            propertyAddress.mElement = i;
815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            hasProperty = AudioObjectHasProperty(_inputDeviceID,
816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (hasProperty)
818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                size = sizeof(channelMuted);
820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID,
821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        &propertyAddress, 0, NULL, &size, &channelMuted));
822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                muted = (muted && channelMuted);
824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                channels++;
825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (channels == 0)
829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Unable to get mute for any channel");
832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(channels > 0);
836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // 1 means muted
837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        enabled = static_cast<bool> (muted);
838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "     AudioMixerManagerMac::MicrophoneMute() => enabled=%d",
842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 enabled);
843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
84764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::MicrophoneBoostIsAvailable(bool& available)
848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = false; // No AudioObjectPropertySelector value for Mic Boost
857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
86164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SetMicrophoneBoost(bool enable)
862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::SetMicrophoneBoost(enable=%u)", enable);
865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Ensure that the selected microphone has a valid boost control.
876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool available(false);
877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MicrophoneBoostIsAvailable(available);
878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!available)
879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  it is not possible to enable microphone boost");
882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // It is assumed that the call above fails!
886b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
88964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::MicrophoneBoost(bool& enabled) const
890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Microphone boost cannot be enabled on this platform!
900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    enabled = false;
901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
90564a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::MicrophoneVolumeIsAvailable(bool& available)
906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master volume control?
917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress
919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress = { kAudioDevicePropertyVolumeScalar,
920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                kAudioDevicePropertyScopeInput, 0 };
921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        available = true;
927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noInputChannels; i++)
932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err != noErr || !isSettable)
938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            available = false;
940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Volume cannot be set for input channel %d, err=%d",
942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         i, err);
943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    available = true;
948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
95164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t AudioMixerManagerMac::SetMicrophoneVolume(uint32_t volume)
952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AudioMixerManagerMac::SetMicrophoneVolume(volume=%u)", volume);
955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped lock(&_critSect);
957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
963b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool success = false;
968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 - 1.0, convert from 0 - 255
970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const Float32 vol = (Float32)(volume / 255.0);
971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(vol <= 1.0 && vol >= 0.0);
973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the capture device have a master volume control?
975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress
977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress = { kAudioDevicePropertyVolumeScalar,
978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                kAudioDevicePropertyScopeInput, 0 };
979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean isSettable = false;
980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        &isSettable);
982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (err == noErr && isSettable)
983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(vol);
985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID,
986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, size, &vol));
987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise try to set each channel.
992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (UInt32 i = 1; i <= _noInputChannels; i++)
993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress.mElement = i;
995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        isSettable = false;
996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress,
997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            &isSettable);
998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (err == noErr && isSettable)
999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            size = sizeof(vol);
1001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID,
1002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    &propertyAddress, 0, NULL, size, &vol));
1003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        success = true;
1005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1006b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!success)
1008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " Unable to set a level on any input channel");
1011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1013b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
101764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
101864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::MicrophoneVolume(uint32_t& volume) const
1019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
1022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
1025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    OSStatus err = noErr;
1029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    UInt32 size = 0;
1030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    unsigned int channels = 0;
1031b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Float32 channelVol = 0;
1032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Float32 volFloat32 = 0;
1033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Does the device have a master volume control?
1035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // If so, use it exclusively.
1036b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioObjectPropertyAddress
1037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        propertyAddress = { kAudioDevicePropertyVolumeScalar,
1038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                kAudioDevicePropertyScopeInput, 0 };
1039b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Boolean hasProperty = AudioObjectHasProperty(_inputDeviceID,
1040b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
1041b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hasProperty)
1042b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1043b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        size = sizeof(volFloat32);
1044b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID,
1045b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                &propertyAddress, 0, NULL, &size, &volFloat32));
1046b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1047b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // vol 0.0 to 1.0 -> convert to 0 - 255
104864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org        volume = static_cast<uint32_t> (volFloat32 * 255 + 0.5);
1049b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else
1050b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1051b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Otherwise get the average volume across channels.
1052b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        volFloat32 = 0;
1053b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        for (UInt32 i = 1; i <= _noInputChannels; i++)
1054b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1055b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            channelVol = 0;
1056b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            propertyAddress.mElement = i;
1057b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            hasProperty = AudioObjectHasProperty(_inputDeviceID,
1058b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 &propertyAddress);
1059b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (hasProperty)
1060b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
1061b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                size = sizeof(channelVol);
1062b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID,
1063b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        &propertyAddress, 0, NULL, &size, &channelVol));
1064b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1065b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                volFloat32 += channelVol;
1066b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                channels++;
1067b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
1068b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1069b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1070b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (channels == 0)
1071b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1072b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1073b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         " Unable to get a level on any channel");
1074b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
1075b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1076b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1077b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(channels > 0);
1078b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // vol 0.0 to 1.0 -> convert to 0 - 255
107964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org        volume = static_cast<uint32_t>
1080b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            (255 * volFloat32 / channels + 0.5);
1081b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1082b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1083b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1084b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "     AudioMixerManagerMac::MicrophoneVolume() => vol=%u",
1085b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 volume);
1086b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1087b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1088b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1089b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
109064a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
109164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::MaxMicrophoneVolume(uint32_t& maxVolume) const
1092b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1093b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1094b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
1095b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1096b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1097b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
1098b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1099b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 to 1.0
1102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // we convert that to 0 - 255
1103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    maxVolume = 255;
1104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
110864a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
110964a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::MinMicrophoneVolume(uint32_t& minVolume) const
1110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
1113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
1116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 to 1.0
1120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // we convert that to 0 - 10
1121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    minVolume = 0;
1122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
112664a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgint32_t
112764a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.orgAudioMixerManagerMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const
1128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_inputDeviceID == kAudioObjectUnknown)
1131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
1132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "  device ID has not been set");
1134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
1135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // volume range is 0.0 to 1.0
1138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // we convert that to 0 - 10
1139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stepSize = 1;
1140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
1145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//                                 Private Methods
1146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ============================================================================
1147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// CoreAudio errors are best interpreted as four character strings.
1149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioMixerManagerMac::logCAMsg(const TraceLevel level,
1150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    const TraceModule module,
115164a144ff1bf67bc85942721aab04c98757b83e3bpbos@webrtc.org                                    const int32_t id, const char *msg,
1152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    const char *err)
1153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
1154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(msg != NULL);
1155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(err != NULL);
1156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1157d7e904161d5c59c61cbf094b16bca6e79ada713aandrew@webrtc.org#ifdef WEBRTC_ARCH_BIG_ENDIAN
1158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(level, module, id, "%s: %.4s", msg, err);
1159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else
1160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // We need to flip the characters in this case.
1161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(level, module, id, "%s: %.1s%.1s%.1s%.1s", msg, err + 3, err
1162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        + 2, err + 1, err);
1163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
1164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11663b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org}  // namespace webrtc
1167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// EOF
1168