Commit | Line | Data |
---|---|---|
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 | |
19 | * @brief Support for @ref BACKEND_COREAUDIO | |
20 | */ | |
21 | ||
22 | #include "common.h" | |
23 | ||
24 | #if HAVE_COREAUDIO_AUDIOHARDWARE_H | |
25 | ||
26 | #include "coreaudio.h" | |
27 | #include "log.h" | |
28 | #include <CoreFoundation/CFString.h> | |
29 | ||
30 | /** @brief Return the default device ID */ | |
31 | static AudioDeviceID coreaudio_use_default(void) { | |
32 | OSStatus status; | |
33 | UInt32 propertySize; | |
34 | AudioDeviceID adid; | |
35 | ||
36 | /* TODO should we use kAudioHardwarePropertyDefaultSystemOutputDevice | |
37 | * instead? It is listed in the enumeration but is not documented, so we | |
38 | * leave it alone until better information is available. */ | |
39 | propertySize = sizeof adid; | |
40 | status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, | |
41 | &propertySize, &adid); | |
42 | if(status) | |
43 | fatal(0, "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice: %d", (int)status); | |
44 | if(adid == kAudioDeviceUnknown) | |
45 | fatal(0, "no output device"); | |
46 | return adid; | |
47 | } | |
48 | ||
49 | /** @brief Find a device by some string | |
50 | * @param selector Selector for property to look for | |
51 | * @param description Property description | |
52 | * @param devs List of device IDs | |
53 | * @param ndevs Number of device IDs in @p devs | |
54 | * @param resultp Where to put device ID | |
55 | * @return 1 if found, 0 if not found | |
56 | */ | |
57 | static int coreaudio_find_device(AudioObjectPropertySelector selector, | |
58 | //const char *description, | |
59 | const AudioDeviceID *devs, | |
60 | unsigned ndevs, | |
61 | CFStringRef dev, | |
62 | AudioDeviceID *resultp) { | |
63 | OSStatus status; | |
64 | UInt32 propertySize; | |
65 | ||
66 | for(unsigned n = 0; n < ndevs; ++n) { | |
67 | CFStringRef name; | |
68 | propertySize = sizeof name; | |
69 | status = AudioDeviceGetProperty(devs[n], 0, FALSE, | |
70 | selector, | |
71 | &propertySize, &name); | |
72 | if(status) | |
73 | fatal(0, "AudioDeviceGetProperty: %d", (int)status); | |
74 | #if 0 | |
75 | UInt8 output[1024]; | |
76 | CFIndex used; | |
77 | CFRange r = { 0, CFStringGetLength(name) }; | |
78 | CFStringGetBytes(name, r, kCFStringEncodingUTF8, | |
79 | '?', FALSE, output, sizeof output, | |
80 | &used); | |
81 | output[used] = 0; | |
82 | info("device %u %s: %s", n, description, (char *)output); | |
83 | #endif | |
84 | if(CFStringCompare(dev, name, | |
85 | kCFCompareCaseInsensitive|kCFCompareNonliteral) | |
86 | == kCFCompareEqualTo) { | |
87 | *resultp = devs[n]; | |
88 | CFRelease(name); | |
89 | return 1; | |
90 | } | |
91 | CFRelease(name); | |
92 | } | |
93 | return 0; /* didn't find it */ | |
94 | } | |
95 | ||
96 | /** @brief Identify audio device | |
97 | * @param name Device name | |
98 | * @return Device ID | |
99 | */ | |
100 | AudioDeviceID coreaudio_getdevice(const char *name) { | |
101 | OSStatus status; | |
102 | UInt32 propertySize; | |
103 | int found; | |
104 | AudioDeviceID adid; | |
105 | ||
106 | if(!name | |
107 | || !*name | |
108 | || !strcmp(name, "default")) | |
109 | return coreaudio_use_default(); | |
110 | /* Convert the configured device name to a CFString */ | |
111 | CFStringRef dev; | |
112 | dev = CFStringCreateWithCString(NULL/*default allocator*/, | |
113 | name, | |
114 | kCFStringEncodingUTF8); | |
115 | if(!dev) | |
116 | fatal(0, "CFStringCreateWithBytes failed"); | |
117 | /* Get a list of available devices */ | |
118 | AudioDeviceID devs[1024]; | |
119 | unsigned ndevs; | |
120 | ||
121 | propertySize = sizeof devs; | |
122 | status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, | |
123 | &propertySize, devs); | |
124 | if(status) | |
125 | fatal(0, "AudioHardwareGetProperty kAudioHardwarePropertyDevices: %d", | |
126 | (int)status); | |
127 | ndevs = propertySize / sizeof *devs; | |
128 | if(!ndevs) | |
129 | fatal(0, "no sound devices found"); | |
130 | /* Try looking up by UID first */ | |
131 | found = coreaudio_find_device(kAudioDevicePropertyDeviceUID, //"UID", | |
132 | devs, ndevs, dev, &adid); | |
133 | /* Failing that try looking up by name */ | |
134 | if(!found) | |
135 | found = coreaudio_find_device(kAudioObjectPropertyName, //"name", | |
136 | devs, ndevs, dev, &adid); | |
137 | CFRelease(dev); | |
138 | if(!found) | |
139 | fatal(0, "cannot find device '%s'", name); | |
140 | return adid; | |
141 | } | |
142 | ||
143 | #endif | |
144 | ||
145 | /* | |
146 | Local Variables: | |
147 | c-basic-offset:2 | |
148 | comment-column:40 | |
149 | fill-column:79 | |
150 | indent-tabs-mode:nil | |
151 | End: | |
152 | */ |