2 * Copyright (C) 2011-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "CoreAudioHardware.h"
23 #include "CoreAudioHelpers.h"
24 #include "utils/log.h"
25 #include "osx/DarwinUtils.h"
27 bool CCoreAudioHardware::GetAutoHogMode()
29 AudioObjectPropertyAddress propertyAddress;
30 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
31 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
32 propertyAddress.mSelector = kAudioHardwarePropertyHogModeIsAllowed;
35 UInt32 size = sizeof(val);
36 OSStatus ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, &val);
39 CLog::Log(LOGERROR, "CCoreAudioHardware::GetAutoHogMode: "
40 "Unable to get auto 'hog' mode. Error = %s", GetError(ret).c_str());
46 void CCoreAudioHardware::SetAutoHogMode(bool enable)
48 AudioObjectPropertyAddress propertyAddress;
49 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
50 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
51 propertyAddress.mSelector = kAudioHardwarePropertyHogModeIsAllowed;
53 UInt32 val = enable ? 1 : 0;
54 UInt32 size = sizeof(val);
55 OSStatus ret = AudioObjectSetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, size, &val);
57 CLog::Log(LOGERROR, "CCoreAudioHardware::SetAutoHogMode: "
58 "Unable to set auto 'hog' mode. Error = %s", GetError(ret).c_str());
61 void CCoreAudioHardware::ResetAudioDevices()
63 CLog::Log(LOGDEBUG, "CCoreAudioHardware::ResetAudioDevices resetting our devices to LPCM");
64 CoreAudioDeviceList list;
65 if (GetOutputDevices(&list))
67 for (CoreAudioDeviceList::iterator it = list.begin(); it != list.end(); it ++)
69 CCoreAudioDevice device = *it;
71 AudioStreamIdList streams;
72 if (device.GetStreams(&streams))
74 CLog::Log(LOGDEBUG, "CCoreAudioHardware::ResetAudioDevices %lu streams for device %s", streams.size(), device.GetName().c_str());
75 for (AudioStreamIdList::iterator ait = streams.begin(); ait != streams.end(); ait ++)
82 void CCoreAudioHardware::ResetStream(AudioStreamID streamId)
84 CCoreAudioStream stream;
85 stream.Open(streamId);
87 AudioStreamBasicDescription desc;
88 if (stream.GetPhysicalFormat(&desc))
90 if (desc.mFormatID == 'IAC3' || desc.mFormatID == kAudioFormat60958AC3)
92 CLog::Log(LOGDEBUG, "CCoreAudioHardware::ResetStream stream 0x%x is in encoded format.. setting to LPCM", (unsigned int)streamId);
94 StreamFormatList availableFormats;
95 if (stream.GetAvailablePhysicalFormats(&availableFormats))
97 for (StreamFormatList::iterator fmtIt = availableFormats.begin(); fmtIt != availableFormats.end() ; fmtIt ++)
99 AudioStreamRangedDescription fmtDesc = *fmtIt;
100 if (fmtDesc.mFormat.mFormatID == kAudioFormatLinearPCM)
102 AudioStreamBasicDescription newFmt = { 0 };
103 newFmt = fmtDesc.mFormat;
105 if (stream.SetPhysicalFormat(&newFmt))
116 AudioDeviceID CCoreAudioHardware::FindAudioDevice(const std::string &searchName)
118 AudioDeviceID deviceId = 0;
120 if (!searchName.length())
123 std::string searchNameLowerCase = searchName;
124 std::transform(searchNameLowerCase.begin(), searchNameLowerCase.end(), searchNameLowerCase.begin(), ::tolower );
125 if (searchNameLowerCase.compare("default") == 0)
127 AudioDeviceID defaultDevice = GetDefaultOutputDevice();
128 CLog::Log(LOGDEBUG, "CCoreAudioHardware::FindAudioDevice: "
129 "Returning default device [0x%04x].", (uint)defaultDevice);
130 return defaultDevice;
132 CLog::Log(LOGDEBUG, "CCoreAudioHardware::FindAudioDevice: "
133 "Searching for device - %s.", searchName.c_str());
135 // Obtain a list of all available audio devices
136 AudioObjectPropertyAddress propertyAddress;
137 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
138 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
139 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
142 OSStatus ret = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size);
145 CLog::Log(LOGERROR, "CCoreAudioHardware::FindAudioDevice: "
146 "Unable to retrieve the size of the list of available devices. Error = %s", GetError(ret).c_str());
150 size_t deviceCount = size / sizeof(AudioDeviceID);
151 AudioDeviceID* pDevices = new AudioDeviceID[deviceCount];
152 ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, pDevices);
155 CLog::Log(LOGERROR, "CCoreAudioHardware::FindAudioDevice: "
156 "Unable to retrieve the list of available devices. Error = %s", GetError(ret).c_str());
161 // Attempt to locate the requested device
162 std::string deviceName;
163 for (size_t dev = 0; dev < deviceCount; dev++)
165 CCoreAudioDevice device;
166 device.Open((pDevices[dev]));
167 deviceName = device.GetName();
168 std::transform( deviceName.begin(), deviceName.end(), deviceName.begin(), ::tolower );
169 if (searchNameLowerCase.compare(deviceName) == 0)
170 deviceId = pDevices[dev];
179 AudioDeviceID CCoreAudioHardware::GetDefaultOutputDevice()
181 AudioDeviceID deviceId = 0;
182 static AudioDeviceID lastDeviceId = 0;
184 AudioObjectPropertyAddress propertyAddress;
185 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
186 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
187 propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
189 UInt32 size = sizeof(AudioDeviceID);
190 OSStatus ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, &deviceId);
192 // outputDevice is set to 0 if there is no audio device available
193 // or if the default device is set to an encoded format
194 if (ret != noErr || !deviceId)
196 CLog::Log(LOGERROR, "CCoreAudioHardware::GetDefaultOutputDevice:"
197 " Unable to identify default output device. Error = %s", GetError(ret).c_str());
198 // if there was no error and no deviceId was returned
199 // return the last known default device
200 if (ret == noErr && !deviceId)
206 lastDeviceId = deviceId;
211 void CCoreAudioHardware::GetOutputDeviceName(std::string& name)
214 AudioDeviceID deviceId = GetDefaultOutputDevice();
218 AudioObjectPropertyAddress propertyAddress;
219 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
220 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
221 propertyAddress.mSelector = kAudioObjectPropertyName;
223 CFStringRef theDeviceName = NULL;
224 UInt32 propertySize = sizeof(CFStringRef);
225 OSStatus ret = AudioObjectGetPropertyData(deviceId, &propertyAddress, 0, NULL, &propertySize, &theDeviceName);
229 DarwinCFStringRefToUTF8String(theDeviceName, name);
231 CFRelease(theDeviceName);
235 UInt32 CCoreAudioHardware::GetOutputDevices(CoreAudioDeviceList *pList)
241 // Obtain a list of all available audio devices
242 AudioObjectPropertyAddress propertyAddress;
243 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
244 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
245 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
248 OSStatus ret = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size);
251 CLog::Log(LOGERROR, "CCoreAudioHardware::GetOutputDevices:"
252 " Unable to retrieve the size of the list of available devices. Error = %s", GetError(ret).c_str());
256 size_t deviceCount = size / sizeof(AudioDeviceID);
257 AudioDeviceID* pDevices = new AudioDeviceID[deviceCount];
258 ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, pDevices);
260 CLog::Log(LOGERROR, "CCoreAudioHardware::GetOutputDevices:"
261 " Unable to retrieve the list of available devices. Error = %s", GetError(ret).c_str());
264 for (size_t dev = 0; dev < deviceCount; dev++)
266 CCoreAudioDevice device(pDevices[dev]);
267 if (device.GetTotalOutputChannels() == 0)
270 pList->push_back(pDevices[dev]);