2 * This file is part of DisOrder
3 * Copyright (C) 2009 Richard Kettlewell
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 3 of the License, or
8 * (at your option) any later version.
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 this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file lib/coreaudio.c
19 * @brief Support for @ref BACKEND_COREAUDIO
24 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
26 #include "coreaudio.h"
29 #include <CoreFoundation/CFString.h>
30 /* evil bodge to work around broken header file */
32 #include <CoreServices/CoreServices.h>
35 /** @brief Report an error with an OSStatus */
36 void coreaudio_fatal(OSStatus err
, const char *fmt
, ...) {
41 byte_vasprintf(&msg
, fmt
, ap
);
44 disorder_fatal(0, "%s: error %d (%s, %s)",
46 GetMacOSStatusErrorString(err
),
47 GetMacOSStatusCommentString(err
));
50 /** @brief Return the default device ID */
51 static AudioDeviceID
coreaudio_use_default(void) {
56 /* TODO should we use kAudioHardwarePropertyDefaultSystemOutputDevice
57 * instead? It is listed in the enumeration but is not documented, so we
58 * leave it alone until better information is available. */
59 propertySize
= sizeof adid
;
60 status
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
,
61 &propertySize
, &adid
);
63 coreaudio_fatal(status
, "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice");
64 if(adid
== kAudioDeviceUnknown
)
65 disorder_fatal(0, "no output device");
69 /** @brief Find a device by some string
70 * @param selector Selector for property to look for
71 * @param description Property description
72 * @param devs List of device IDs
73 * @param ndevs Number of device IDs in @p devs
74 * @param resultp Where to put device ID
75 * @return 1 if found, 0 if not found
77 static int coreaudio_find_device(AudioObjectPropertySelector selector
,
78 //const char *description,
79 const AudioDeviceID
*devs
,
82 AudioDeviceID
*resultp
) {
86 for(unsigned n
= 0; n
< ndevs
; ++n
) {
88 propertySize
= sizeof name
;
89 status
= AudioDeviceGetProperty(devs
[n
], 0, FALSE
,
91 &propertySize
, &name
);
93 coreaudio_fatal(status
, "AudioDeviceGetProperty");
97 CFRange r
= { 0, CFStringGetLength(name
) };
98 CFStringGetBytes(name
, r
, kCFStringEncodingUTF8
,
99 '?', FALSE
, output
, sizeof output
,
102 info("device %u %s: %s", n
, description
, (char *)output
);
104 if(CFStringCompare(dev
, name
,
105 kCFCompareCaseInsensitive
|kCFCompareNonliteral
)
106 == kCFCompareEqualTo
) {
113 return 0; /* didn't find it */
116 /** @brief Identify audio device
117 * @param name Device name
120 AudioDeviceID
coreaudio_getdevice(const char *name
) {
128 || !strcmp(name
, "default"))
129 return coreaudio_use_default();
130 /* Convert the configured device name to a CFString */
132 dev
= CFStringCreateWithCString(NULL
/*default allocator*/,
134 kCFStringEncodingUTF8
);
136 disorder_fatal(0, "CFStringCreateWithBytes failed");
137 /* Get a list of available devices */
138 AudioDeviceID devs
[1024];
141 propertySize
= sizeof devs
;
142 status
= AudioHardwareGetProperty(kAudioHardwarePropertyDevices
,
143 &propertySize
, devs
);
145 coreaudio_fatal(status
, "AudioHardwareGetProperty kAudioHardwarePropertyDevices");
146 ndevs
= propertySize
/ sizeof *devs
;
148 disorder_fatal(0, "no sound devices found");
149 /* Try looking up by UID first */
150 found
= coreaudio_find_device(kAudioDevicePropertyDeviceUID
, //"UID",
151 devs
, ndevs
, dev
, &adid
);
152 /* Failing that try looking up by name */
154 found
= coreaudio_find_device(kAudioObjectPropertyName
, //"name",
155 devs
, ndevs
, dev
, &adid
);
158 disorder_fatal(0, "cannot find device '%s'", name
);