chiark / gitweb /
New refresh_min option to bound below the web interface refresh
[disorder] / lib / coreaudio.c
CommitLineData
f5fd9a6b
RK
1/*
2 * This file is part of DisOrder
3 * Copyright (C) 2009 Richard Kettlewell
4 *
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.
9 *
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.
14 *
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/>.
17 */
18/** @file lib/coreaudio.c
8d251217 19 * @brief Support for Apple Core Audio
f5fd9a6b
RK
20 */
21
22#include "common.h"
23
24#if HAVE_COREAUDIO_AUDIOHARDWARE_H
25
26#include "coreaudio.h"
27#include "log.h"
ca6b4a12 28#include "printf.h"
f5fd9a6b 29#include <CoreFoundation/CFString.h>
ca6b4a12
RK
30/* evil bodge to work around broken header file */
31#undef error
32#include <CoreServices/CoreServices.h>
33#include <stdarg.h>
34
35/** @brief Report an error with an OSStatus */
36void coreaudio_fatal(OSStatus err, const char *fmt, ...) {
37 va_list ap;
38 char *msg;
39
40 va_start(ap, fmt);
41 byte_vasprintf(&msg, fmt, ap);
42 va_end(ap);
43
1f3d2413 44 disorder_fatal(0, "%s: error %u", msg, (unsigned)err);
ca6b4a12 45}
f5fd9a6b
RK
46
47/** @brief Return the default device ID */
48static AudioDeviceID coreaudio_use_default(void) {
49 OSStatus status;
50 UInt32 propertySize;
51 AudioDeviceID adid;
52
53 /* TODO should we use kAudioHardwarePropertyDefaultSystemOutputDevice
54 * instead? It is listed in the enumeration but is not documented, so we
55 * leave it alone until better information is available. */
56 propertySize = sizeof adid;
57 status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
58 &propertySize, &adid);
59 if(status)
ca6b4a12 60 coreaudio_fatal(status, "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice");
f5fd9a6b 61 if(adid == kAudioDeviceUnknown)
ca6b4a12 62 disorder_fatal(0, "no output device");
f5fd9a6b
RK
63 return adid;
64}
65
66/** @brief Find a device by some string
67 * @param selector Selector for property to look for
f5fd9a6b
RK
68 * @param devs List of device IDs
69 * @param ndevs Number of device IDs in @p devs
8d251217 70 * @param dev Desired device name
f5fd9a6b
RK
71 * @param resultp Where to put device ID
72 * @return 1 if found, 0 if not found
73 */
74static int coreaudio_find_device(AudioObjectPropertySelector selector,
75 //const char *description,
76 const AudioDeviceID *devs,
77 unsigned ndevs,
78 CFStringRef dev,
79 AudioDeviceID *resultp) {
80 OSStatus status;
81 UInt32 propertySize;
82
83 for(unsigned n = 0; n < ndevs; ++n) {
84 CFStringRef name;
85 propertySize = sizeof name;
86 status = AudioDeviceGetProperty(devs[n], 0, FALSE,
87 selector,
88 &propertySize, &name);
89 if(status)
ca6b4a12 90 coreaudio_fatal(status, "AudioDeviceGetProperty");
f5fd9a6b
RK
91#if 0
92 UInt8 output[1024];
93 CFIndex used;
94 CFRange r = { 0, CFStringGetLength(name) };
95 CFStringGetBytes(name, r, kCFStringEncodingUTF8,
96 '?', FALSE, output, sizeof output,
97 &used);
98 output[used] = 0;
2e9ba080 99 disorder_info("device %u %s: %s", n, description, (char *)output);
f5fd9a6b
RK
100#endif
101 if(CFStringCompare(dev, name,
102 kCFCompareCaseInsensitive|kCFCompareNonliteral)
103 == kCFCompareEqualTo) {
104 *resultp = devs[n];
105 CFRelease(name);
106 return 1;
107 }
108 CFRelease(name);
109 }
110 return 0; /* didn't find it */
111}
112
113/** @brief Identify audio device
114 * @param name Device name
115 * @return Device ID
116 */
117AudioDeviceID coreaudio_getdevice(const char *name) {
118 OSStatus status;
119 UInt32 propertySize;
120 int found;
121 AudioDeviceID adid;
122
123 if(!name
124 || !*name
125 || !strcmp(name, "default"))
126 return coreaudio_use_default();
127 /* Convert the configured device name to a CFString */
128 CFStringRef dev;
129 dev = CFStringCreateWithCString(NULL/*default allocator*/,
130 name,
131 kCFStringEncodingUTF8);
132 if(!dev)
ca6b4a12 133 disorder_fatal(0, "CFStringCreateWithBytes failed");
f5fd9a6b
RK
134 /* Get a list of available devices */
135 AudioDeviceID devs[1024];
136 unsigned ndevs;
137
138 propertySize = sizeof devs;
139 status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
140 &propertySize, devs);
141 if(status)
ca6b4a12 142 coreaudio_fatal(status, "AudioHardwareGetProperty kAudioHardwarePropertyDevices");
f5fd9a6b
RK
143 ndevs = propertySize / sizeof *devs;
144 if(!ndevs)
ca6b4a12 145 disorder_fatal(0, "no sound devices found");
f5fd9a6b 146 /* Try looking up by UID first */
1f3d2413 147 found = coreaudio_find_device(-1*kAudioDevicePropertyDeviceUID, //"UID",
f5fd9a6b
RK
148 devs, ndevs, dev, &adid);
149 /* Failing that try looking up by name */
150 if(!found)
151 found = coreaudio_find_device(kAudioObjectPropertyName, //"name",
152 devs, ndevs, dev, &adid);
153 CFRelease(dev);
154 if(!found)
ca6b4a12 155 disorder_fatal(0, "cannot find device '%s'", name);
f5fd9a6b
RK
156 return adid;
157}
158
159#endif
160
161/*
162Local Variables:
163c-basic-offset:2
164comment-column:40
165fill-column:79
166indent-tabs-mode:nil
167End:
168*/