リビジョン | bda80654cb6d31f4039df18a228a738b61d90fe2 (tree) |
---|---|
日時 | 2021-07-25 06:38:35 |
作者 | AlaskanEmily <emily@alas...> |
コミッター | AlaskanEmily |
Add basic device enumeration API.
This is kind of sub-optimal though, OpenAL just says there is one "OpenAL Soft"
device which is clearly not what we really wanted. I need to investigate the
method OpenAL uses to choose devices, and possibly just tell it using an envvar.
@@ -119,16 +119,22 @@ int main(int argc, char **argv){ | ||
119 | 119 | char *const buffer = malloc(rate); |
120 | 120 | unsigned num_read, total_read = 0; |
121 | 121 | |
122 | - struct Cin_Driver *const driver = malloc(Cin_StructDriverSize()); | |
123 | - struct Cin_Sound *const sound = malloc(Cin_StructSoundSize()); | |
124 | - struct Cin_Loader *const loader = malloc(Cin_StructLoaderSize()); | |
122 | + struct Cin_Driver *const driver = | |
123 | + malloc(Cin_StructDriverSize()); | |
124 | + struct Cin_Sound *const sound = | |
125 | + malloc(Cin_StructSoundSize()); | |
126 | + struct Cin_Loader *const loader = | |
127 | + malloc(Cin_StructLoaderSize()); | |
125 | 128 | |
126 | - if(driver == NULL || Cin_CreateDriver(driver) != Cin_eDriverSuccess){ | |
129 | + if(driver == NULL || | |
130 | + Cin_CreateDriver(driver, NULL) != Cin_eDriverSuccess){ | |
131 | + | |
127 | 132 | fputs("Could not create driver\n", stderr); |
128 | 133 | return EXIT_FAILURE; |
129 | 134 | } |
130 | 135 | |
131 | - if(loader == NULL || Cin_CreateLoader(loader, driver, rate, channels, format) != Cin_eLoaderSuccess){ | |
136 | + if(loader == NULL || | |
137 | + Cin_CreateLoader(loader, driver, rate, channels, format) != Cin_eLoaderSuccess){ | |
132 | 138 | fputs("Could not create loader\n", stderr); |
133 | 139 | return EXIT_FAILURE; |
134 | 140 | } |
@@ -141,7 +147,8 @@ int main(int argc, char **argv){ | ||
141 | 147 | /* The buffer is no longer needed. */ |
142 | 148 | free(buffer); |
143 | 149 | |
144 | - if(sound == NULL || Cin_LoaderFinalize(loader, sound) != Cin_eLoaderSuccess){ | |
150 | + if(sound == NULL || | |
151 | + Cin_LoaderFinalize(loader, sound) != Cin_eLoaderSuccess){ | |
145 | 152 | fputs("Could not create sound\n", stderr); |
146 | 153 | return EXIT_FAILURE; |
147 | 154 | } |
@@ -36,6 +36,28 @@ enum Cin_DriverError { | ||
36 | 36 | Cin_eDriverNoDevice |
37 | 37 | }; |
38 | 38 | |
39 | +typedef const char **cin_device_list_t; | |
40 | + | |
41 | +/** | |
42 | + * @brief Creates a list of all devices. | |
43 | + * | |
44 | + * The list is terminated with a NULL pointer, and each string is | |
45 | + * NULL-terminated. | |
46 | + * | |
47 | + * There is no guarantee that any devices will be enumerated, in which case | |
48 | + * only the default device (a NULL argument to Cin_CreateDriver) may be | |
49 | + * available, or no devices at all may be available. | |
50 | + * | |
51 | + * @return A list of devices. This must be freed with Cin_FreeDeviceList | |
52 | + * @sa Cin_FreeDeviceList | |
53 | + */ | |
54 | +CIN_EXPORT(cin_device_list_t) Cin_GetDeviceList(void); | |
55 | + | |
56 | +/** | |
57 | + * @brief Frees the result of Cin_GetDeviceList | |
58 | + */ | |
59 | +CIN_EXPORT(void) Cin_FreeDeviceList(const char **list); | |
60 | + | |
39 | 61 | /** |
40 | 62 | * @brief Returns the size of struct Cin_Driver |
41 | 63 | * |
@@ -52,11 +74,16 @@ CIN_EXPORT(unsigned) Cin_StructDriverSize(void); | ||
52 | 74 | * @warning The data that is placed in drv must NOT be copied. Do not use |
53 | 75 | * memcpy on @p sdrv, other structures may depend on the address of @p drv. |
54 | 76 | * |
77 | + * @param drv Memory to place the driver in. | |
78 | + * @param name Name of the device to open, or NULL for default. | |
79 | + * | |
55 | 80 | * @sa Cin_StructDriverSize |
56 | 81 | * @sa Cin_DestroyDriver |
57 | 82 | * @todo There is currently no way to enumerate devices. |
58 | 83 | */ |
59 | -CIN_EXPORT(enum Cin_DriverError) Cin_CreateDriver(struct Cin_Driver *drv); | |
84 | +CIN_EXPORT(enum Cin_DriverError) Cin_CreateDriver( | |
85 | + struct Cin_Driver *drv, | |
86 | + const char *name); | |
60 | 87 | |
61 | 88 | /** |
62 | 89 | * @brief Destroys the Driver |
@@ -196,6 +223,12 @@ CIN_EXPORT(enum Cin_LoaderError) Cin_LoaderFinalize(struct Cin_Loader *ld, | ||
196 | 223 | struct Cin_Sound *out); |
197 | 224 | |
198 | 225 | /** @} */ /* End Loader group. */ |
226 | + | |
227 | +/** | |
228 | + * @brief Name of the environment variable to set the default device to use. | |
229 | + */ | |
230 | +#define CIN_DEFAULT_DEVICE_ENV "CINDEV" | |
231 | + | |
199 | 232 | #ifdef __cplusplus |
200 | 233 | } // extern "C" |
201 | 234 | #endif |
@@ -8,9 +8,22 @@ | ||
8 | 8 | #include "cinnamon.h" |
9 | 9 | #include "cin_openal.h" |
10 | 10 | |
11 | -#include <stddef.h> | |
11 | +#include <string.h> | |
12 | +#include <stdlib.h> | |
12 | 13 | #include <assert.h> |
13 | 14 | |
15 | +#ifndef ALC_DEVICE_SPECIFIER | |
16 | +#define ALC_DEVICE_SPECIFIER 0x1005 | |
17 | +#endif | |
18 | + | |
19 | +#ifndef ALC_DEFAULT_ALL_DEVICES_SPECIFIER | |
20 | +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 | |
21 | +#endif | |
22 | + | |
23 | +#ifndef ALC_ALL_DEVICES_SPECIFIER | |
24 | +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 | |
25 | +#endif | |
26 | + | |
14 | 27 | /*****************************************************************************/ |
15 | 28 | /* See gen_float_table.py for how this table was generated. */ |
16 | 29 | static const float char_to_float_table[0x100] = { |
@@ -195,19 +208,82 @@ CIN_PRIVATE(int) Cin_CleanOpenALSound(ALuint snd, ALuint *out){ | ||
195 | 208 | |
196 | 209 | /*****************************************************************************/ |
197 | 210 | |
211 | +const char **Cin_GetDeviceList(void){ | |
212 | + static const char *nothing = NULL; | |
213 | + /* OS X has a totally broken implementation of these extensions. */ | |
214 | +#ifndef __APPLE__ | |
215 | + const char *strs = NULL, **list; | |
216 | + if(alcIsExtensionPresent(NULL, "ALC_enumeration_all_EXT")) | |
217 | + strs = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); | |
218 | + | |
219 | + if(strs == NULL && alcIsExtensionPresent(NULL, "ALC_enumeration_EXT")) | |
220 | + strs = alcGetString(NULL, ALC_DEVICE_SPECIFIER); | |
221 | + | |
222 | + if(strs != NULL){ | |
223 | + /* Count the number of strings first. */ | |
224 | + unsigned n = 0, i = 0, l; | |
225 | + while((l = strlen(strs + i)) != 0){ | |
226 | + n++; | |
227 | + i += l + 1; | |
228 | + } | |
229 | + /* Allocate the list */ | |
230 | + list = malloc(sizeof(char*) * n + 1); | |
231 | + if(list == NULL) | |
232 | + return ¬hing; | |
233 | + | |
234 | + /* Copy each string. */ | |
235 | + n = i = 0; | |
236 | + while((l = strlen(strs + i)) != 0){ | |
237 | + list[n] = malloc(l + 1); | |
238 | + if(list[n] == NULL) | |
239 | + break; | |
240 | + | |
241 | + memcpy((char*)(list[n]), strs + i, l + 1); | |
242 | + | |
243 | + i += l + 1; | |
244 | + n++; | |
245 | + } | |
246 | + list[n] = NULL; | |
247 | + return list; | |
248 | + } | |
249 | +#endif | |
250 | + return ¬hing; | |
251 | +} | |
252 | + | |
253 | +/*****************************************************************************/ | |
254 | + | |
255 | +void Cin_FreeDeviceList(const char **list){ | |
256 | +#ifdef __APPLE__ | |
257 | + (void)list; | |
258 | +#else | |
259 | + unsigned i; | |
260 | + for(i = 0; list[i] != NULL; i++) | |
261 | + free((char*)(list[i])); | |
262 | + free(list); | |
263 | +#endif | |
264 | +} | |
265 | + | |
266 | +/*****************************************************************************/ | |
267 | + | |
198 | 268 | unsigned Cin_StructDriverSize(){ |
199 | 269 | return sizeof(struct Cin_Driver); |
200 | 270 | } |
201 | 271 | |
202 | 272 | /*****************************************************************************/ |
203 | 273 | |
204 | -enum Cin_DriverError Cin_CreateDriver(struct Cin_Driver *drv){ | |
274 | +enum Cin_DriverError Cin_CreateDriver( | |
275 | + struct Cin_Driver *drv, | |
276 | + const char *name){ | |
277 | + | |
205 | 278 | ALCcontext *ctx; |
206 | 279 | ALCdevice *dev; |
207 | 280 | |
208 | 281 | assert(drv != NULL); |
209 | 282 | |
210 | - dev = alcOpenDevice(NULL); | |
283 | + if(name == NULL) | |
284 | + name = getenv(CIN_DEFAULT_DEVICE_ENV); | |
285 | + | |
286 | + dev = alcOpenDevice(name); | |
211 | 287 | if(dev == NULL){ |
212 | 288 | return Cin_eDriverNoDevice; |
213 | 289 | } |
@@ -43,9 +43,13 @@ int main(int argc, char **argv){ | ||
43 | 43 | assert(Cin_StructLoaderSize() > 0); |
44 | 44 | assert(Cin_StructSoundSize() > 0); |
45 | 45 | |
46 | - if(driver == NULL || Cin_CreateDriver(driver) == Cin_eDriverSuccess){ | |
47 | - struct Cin_Loader *const loader = malloc(Cin_StructLoaderSize()); | |
48 | - struct Cin_Sound *const sound = malloc(Cin_StructSoundSize()); | |
46 | + if(driver == NULL || | |
47 | + Cin_CreateDriver(driver, NULL) == Cin_eDriverSuccess){ | |
48 | + | |
49 | + struct Cin_Loader *const loader = | |
50 | + malloc(Cin_StructLoaderSize()); | |
51 | + struct Cin_Sound *const sound = | |
52 | + malloc(Cin_StructSoundSize()); | |
49 | 53 | |
50 | 54 | /* TODO: Make these configurable */ |
51 | 55 | unsigned num_channels = 2, |
@@ -1,7 +1,7 @@ | ||
1 | 1 | # Any copyright is dedicated to the Public Domain. |
2 | 2 | # http://creativecommons.org/publicdomain/zero/1.0/ |
3 | 3 | |
4 | -all: libcinnamon.a sine_test aucat | |
4 | +all: libcinnamon.a sine_test aucat list_dev | |
5 | 5 | |
6 | 6 | CIN_BACKEND?=$(BACKEND) |
7 | 7 |
@@ -22,16 +22,22 @@ libcinnamon.a: $(CIN_BACKEND)_lib | ||
22 | 22 | |
23 | 23 | sine_test.o: sine_test.c cinnamon.h cin_export.h cin_format.h |
24 | 24 | $(CC) $(CFLAGS) -c sine_test.c -o sine_test.o |
25 | - | |
25 | + | |
26 | 26 | aucat.o: aucat.c cinnamon.h cin_export.h cin_format.h |
27 | 27 | $(CC) $(CFLAGS) -c aucat.c -o aucat.o |
28 | 28 | |
29 | +list_dev.o: list_dev.c cinnamon.h cin_export.h cin_format.h | |
30 | + $(CC) $(CFLAGS) -c list_dev.c -o list_dev.o | |
31 | + | |
29 | 32 | sine_test: libcinnamon.a sine_test.o |
30 | 33 | $(LINK) sine_test.o libcinnamon.a $(EXTRALIBS) -lm -o sine_test |
31 | 34 | |
32 | 35 | aucat: libcinnamon.a aucat.o |
33 | 36 | $(LINK) aucat.o libcinnamon.a $(EXTRALIBS) -o aucat |
34 | 37 | |
38 | +list_dev: libcinnamon.a list_dev.o | |
39 | + $(LINK) list_dev.o libcinnamon.a $(EXTRALIBS) -o list_dev | |
40 | + | |
35 | 41 | clean: |
36 | 42 | rm *.o 2> /dev/null || true |
37 | 43 | rm *.a 2> /dev/null || true |