Mercurial > sdl-ios-xcode
comparison src/audio/alsa/SDL_alsa_audio.c @ 3818:49eadd6e8962 SDL-ryan-multiple-audio-device
Mangled ALSA dynamic loading...static loading will still work if you have the
right libraries, but this is expected to break in general cases as we start
dealing with different symbol versions, etc (but may work with, say,
distro-specific packages, etc).
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 06 Oct 2006 19:45:11 +0000 |
parents | c8b3d3d13ed1 |
children | b225d9820ee3 |
comparison
equal
deleted
inserted
replaced
3817:103bbe13f5eb | 3818:49eadd6e8962 |
---|---|
23 | 23 |
24 /* Allow access to a raw mixing buffer */ | 24 /* Allow access to a raw mixing buffer */ |
25 | 25 |
26 #include <sys/types.h> | 26 #include <sys/types.h> |
27 #include <signal.h> /* For kill() */ | 27 #include <signal.h> /* For kill() */ |
28 #include <dlfcn.h> | |
29 #include <errno.h> | |
30 #include <string.h> | |
28 | 31 |
29 #include "SDL_timer.h" | 32 #include "SDL_timer.h" |
30 #include "SDL_audio.h" | 33 #include "SDL_audio.h" |
31 #include "../SDL_audiomem.h" | 34 #include "../SDL_audiomem.h" |
32 #include "../SDL_audio_c.h" | 35 #include "../SDL_audio_c.h" |
33 #include "SDL_alsa_audio.h" | 36 #include "SDL_alsa_audio.h" |
34 | |
35 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC | |
36 #include <dlfcn.h> | |
37 #include "SDL_name.h" | |
38 #include "SDL_loadso.h" | |
39 #else | |
40 #define SDL_NAME(X) X | |
41 #endif | |
42 | 37 |
43 | 38 |
44 /* The tag name used by ALSA audio */ | 39 /* The tag name used by ALSA audio */ |
45 #define DRIVER_NAME "alsa" | 40 #define DRIVER_NAME "alsa" |
46 | 41 |
52 static void ALSA_WaitAudio(_THIS); | 47 static void ALSA_WaitAudio(_THIS); |
53 static void ALSA_PlayAudio(_THIS); | 48 static void ALSA_PlayAudio(_THIS); |
54 static Uint8 *ALSA_GetAudioBuf(_THIS); | 49 static Uint8 *ALSA_GetAudioBuf(_THIS); |
55 static void ALSA_CloseAudio(_THIS); | 50 static void ALSA_CloseAudio(_THIS); |
56 | 51 |
52 static int (*ALSA_snd_pcm_open) | |
53 (snd_pcm_t **, const char *, snd_pcm_stream_t, int); | |
54 static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm); | |
55 static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) | |
56 (snd_pcm_t *,const void *, snd_pcm_uframes_t); | |
57 static int (*ALSA_snd_pcm_resume)(snd_pcm_t *); | |
58 static int (*ALSA_snd_pcm_prepare)(snd_pcm_t *); | |
59 static int (*ALSA_snd_pcm_drain)(snd_pcm_t *); | |
60 static const char *(*ALSA_snd_strerror)(int); | |
61 static size_t(*ALSA_snd_pcm_hw_params_sizeof)(void); | |
62 static size_t(*ALSA_snd_pcm_sw_params_sizeof)(void); | |
63 static int (*ALSA_snd_pcm_hw_params_any)(snd_pcm_t *, snd_pcm_hw_params_t *); | |
64 static int (*ALSA_snd_pcm_hw_params_set_access) | |
65 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t); | |
66 static int (*ALSA_snd_pcm_hw_params_set_format) | |
67 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t); | |
68 static int (*ALSA_snd_pcm_hw_params_set_channels) | |
69 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int); | |
70 static int (*ALSA_snd_pcm_hw_params_get_channels)(const snd_pcm_hw_params_t *); | |
71 static unsigned int (*ALSA_snd_pcm_hw_params_set_rate_near) | |
72 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int, int *); | |
73 static snd_pcm_uframes_t (*ALSA_snd_pcm_hw_params_set_period_size_near) | |
74 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t, int *); | |
75 static snd_pcm_sframes_t (*ALSA_snd_pcm_hw_params_get_period_size) | |
76 (const snd_pcm_hw_params_t *); | |
77 static unsigned int (*ALSA_snd_pcm_hw_params_set_periods_near) | |
78 (snd_pcm_t *,snd_pcm_hw_params_t *, unsigned int, int *); | |
79 static int (*ALSA_snd_pcm_hw_params_get_periods)(snd_pcm_hw_params_t *); | |
80 static int (*ALSA_snd_pcm_hw_params)(snd_pcm_t *, snd_pcm_hw_params_t *); | |
81 static int (*ALSA_snd_pcm_sw_params_current)(snd_pcm_t*, snd_pcm_sw_params_t*); | |
82 static int (*ALSA_snd_pcm_sw_params_set_start_threshold) | |
83 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); | |
84 static int (*ALSA_snd_pcm_sw_params_set_avail_min) | |
85 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); | |
86 static int (*ALSA_snd_pcm_sw_params)(snd_pcm_t *, snd_pcm_sw_params_t *); | |
87 static int (*ALSA_snd_pcm_nonblock)(snd_pcm_t *, int); | |
88 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof | |
89 #define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof | |
90 | |
91 | |
57 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC | 92 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC |
58 | 93 |
59 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC; | 94 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC; |
60 static void *alsa_handle = NULL; | 95 static void *alsa_handle = NULL; |
61 static int alsa_loaded = 0; | 96 |
62 | 97 static int |
63 static int (*SDL_snd_pcm_open) (snd_pcm_t ** pcm, const char *name, | 98 load_alsa_sym(const char *fn, void **addr) |
64 snd_pcm_stream_t stream, int mode); | 99 { |
65 static int (*SDL_NAME(snd_pcm_open)) (snd_pcm_t ** pcm, const char *name, | 100 #if HAVE_DLVSYM |
66 snd_pcm_stream_t stream, int mode); | 101 *addr = dlvsym(alsa_handle, fn, "ALSA_0.9"); |
67 static int (*SDL_NAME(snd_pcm_close)) (snd_pcm_t * pcm); | 102 if (*addr == NULL) |
68 static snd_pcm_sframes_t(*SDL_NAME(snd_pcm_writei)) (snd_pcm_t * pcm, | 103 #endif |
69 const void *buffer, | 104 { |
70 snd_pcm_uframes_t size); | 105 *addr = dlsym(alsa_handle, fn); |
71 static int (*SDL_NAME(snd_pcm_resume)) (snd_pcm_t * pcm); | 106 if (*addr == NULL) { |
72 static int (*SDL_NAME(snd_pcm_prepare)) (snd_pcm_t * pcm); | 107 return 0; |
73 static int (*SDL_NAME(snd_pcm_drain)) (snd_pcm_t * pcm); | 108 } |
74 static const char *(*SDL_NAME(snd_strerror)) (int errnum); | 109 } |
75 static size_t(*SDL_NAME(snd_pcm_hw_params_sizeof)) (void); | 110 |
76 static size_t(*SDL_NAME(snd_pcm_sw_params_sizeof)) (void); | 111 return 1; |
77 static int (*SDL_NAME(snd_pcm_hw_params_any)) (snd_pcm_t * pcm, | 112 } |
78 snd_pcm_hw_params_t * params); | |
79 static int (*SDL_NAME(snd_pcm_hw_params_set_access)) (snd_pcm_t * pcm, | |
80 snd_pcm_hw_params_t * | |
81 params, | |
82 snd_pcm_access_t | |
83 access); | |
84 static int (*SDL_NAME(snd_pcm_hw_params_set_format)) (snd_pcm_t * pcm, | |
85 snd_pcm_hw_params_t * | |
86 params, | |
87 snd_pcm_format_t val); | |
88 static int (*SDL_NAME(snd_pcm_hw_params_set_channels)) (snd_pcm_t * pcm, | |
89 snd_pcm_hw_params_t * | |
90 params, | |
91 unsigned int val); | |
92 static int (*SDL_NAME(snd_pcm_hw_params_get_channels)) (const | |
93 snd_pcm_hw_params_t * | |
94 params); | |
95 static unsigned int | |
96 (*SDL_NAME(snd_pcm_hw_params_set_rate_near)) (snd_pcm_t * | |
97 pcm, | |
98 snd_pcm_hw_params_t | |
99 * params, | |
100 unsigned int val, int *dir); | |
101 static snd_pcm_uframes_t | |
102 (*SDL_NAME(snd_pcm_hw_params_set_period_size_near)) (snd_pcm_t * pcm, | |
103 snd_pcm_hw_params_t | |
104 * params, | |
105 snd_pcm_uframes_t | |
106 val, int *dir); | |
107 static snd_pcm_sframes_t | |
108 (*SDL_NAME(snd_pcm_hw_params_get_period_size)) (const | |
109 snd_pcm_hw_params_t | |
110 * params); | |
111 static unsigned int | |
112 (*SDL_NAME(snd_pcm_hw_params_set_periods_near)) (snd_pcm_t * pcm, | |
113 snd_pcm_hw_params_t | |
114 * params, | |
115 unsigned int val, | |
116 int *dir); | |
117 static int (*SDL_NAME(snd_pcm_hw_params_get_periods)) (snd_pcm_hw_params_t * | |
118 params); | |
119 static int (*SDL_NAME(snd_pcm_hw_params)) (snd_pcm_t * pcm, | |
120 snd_pcm_hw_params_t * params); | |
121 /* | |
122 */ | |
123 static int (*SDL_NAME(snd_pcm_sw_params_current)) (snd_pcm_t * pcm, | |
124 snd_pcm_sw_params_t * | |
125 swparams); | |
126 static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold)) (snd_pcm_t * | |
127 pcm, | |
128 snd_pcm_sw_params_t | |
129 * params, | |
130 snd_pcm_uframes_t | |
131 val); | |
132 static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min)) (snd_pcm_t * pcm, | |
133 snd_pcm_sw_params_t | |
134 * params, | |
135 snd_pcm_uframes_t | |
136 val); | |
137 static int (*SDL_NAME(snd_pcm_sw_params)) (snd_pcm_t * pcm, | |
138 snd_pcm_sw_params_t * params); | |
139 static int (*SDL_NAME(snd_pcm_nonblock)) (snd_pcm_t * pcm, int nonblock); | |
140 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof) | |
141 #define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof) | |
142 | 113 |
143 /* cast funcs to char* first, to please GCC's strict aliasing rules. */ | 114 /* cast funcs to char* first, to please GCC's strict aliasing rules. */ |
144 static struct | 115 #define SDL_ALSA_SYM(x) \ |
145 { | 116 if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1 |
146 const char *name; | 117 #else |
147 void **func; | 118 #define SDL_ALSA_SYM(x) ALSA_##x = x |
148 } alsa_functions[] = { | 119 #endif |
149 { | 120 |
150 "snd_pcm_open", (void **) (char *) &SDL_NAME(snd_pcm_open)}, { | 121 static int load_alsa_syms(void) |
151 "snd_pcm_close", (void **) (char *) &SDL_NAME(snd_pcm_close)}, { | 122 { |
152 "snd_pcm_writei", (void **) (char *) &SDL_NAME(snd_pcm_writei)}, { | 123 SDL_ALSA_SYM(snd_pcm_open); |
153 "snd_pcm_resume", (void **) (char *) &SDL_NAME(snd_pcm_resume)}, { | 124 SDL_ALSA_SYM(snd_pcm_close); |
154 "snd_pcm_prepare", (void **) (char *) &SDL_NAME(snd_pcm_prepare)}, { | 125 SDL_ALSA_SYM(snd_pcm_writei); |
155 "snd_pcm_drain", (void **) (char *) &SDL_NAME(snd_pcm_drain)}, { | 126 SDL_ALSA_SYM(snd_pcm_resume); |
156 "snd_strerror", (void **) (char *) &SDL_NAME(snd_strerror)}, { | 127 SDL_ALSA_SYM(snd_pcm_prepare); |
157 "snd_pcm_hw_params_sizeof", | 128 SDL_ALSA_SYM(snd_pcm_drain); |
158 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_sizeof)}, { | 129 SDL_ALSA_SYM(snd_strerror); |
159 "snd_pcm_sw_params_sizeof", | 130 SDL_ALSA_SYM(snd_pcm_hw_params_sizeof); |
160 (void **) (char *) &SDL_NAME(snd_pcm_sw_params_sizeof)}, { | 131 SDL_ALSA_SYM(snd_pcm_sw_params_sizeof); |
161 "snd_pcm_hw_params_any", | 132 SDL_ALSA_SYM(snd_pcm_hw_params_any); |
162 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_any)}, { | 133 SDL_ALSA_SYM(snd_pcm_hw_params_set_access); |
163 "snd_pcm_hw_params_set_access", | 134 SDL_ALSA_SYM(snd_pcm_hw_params_set_format); |
164 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_access)}, { | 135 SDL_ALSA_SYM(snd_pcm_hw_params_set_channels); |
165 "snd_pcm_hw_params_set_format", | 136 SDL_ALSA_SYM(snd_pcm_hw_params_get_channels); |
166 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_format)}, { | 137 SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near); |
167 "snd_pcm_hw_params_set_channels", | 138 SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near); |
168 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_channels)}, { | 139 SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size); |
169 "snd_pcm_hw_params_get_channels", | 140 SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near); |
170 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_channels)}, { | 141 SDL_ALSA_SYM(snd_pcm_hw_params_get_periods); |
171 "snd_pcm_hw_params_set_rate_near", | 142 SDL_ALSA_SYM(snd_pcm_hw_params); |
172 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_set_rate_near)}, { | 143 SDL_ALSA_SYM(snd_pcm_sw_params_current); |
173 "snd_pcm_hw_params_set_period_size_near", (void **) (char *) | 144 SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold); |
174 &SDL_NAME(snd_pcm_hw_params_set_period_size_near)}, { | 145 SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min); |
175 "snd_pcm_hw_params_get_period_size", | 146 SDL_ALSA_SYM(snd_pcm_sw_params); |
176 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_period_size)}, | 147 SDL_ALSA_SYM(snd_pcm_nonblock); |
177 { | 148 return 0; |
178 "snd_pcm_hw_params_set_periods_near", (void **) (char *) | 149 } |
179 &SDL_NAME(snd_pcm_hw_params_set_periods_near)}, { | |
180 "snd_pcm_hw_params_get_periods", | |
181 (void **) (char *) &SDL_NAME(snd_pcm_hw_params_get_periods)}, { | |
182 "snd_pcm_hw_params", (void **) (char *) &SDL_NAME(snd_pcm_hw_params)}, { | |
183 "snd_pcm_sw_params_current", | |
184 (void **) (char *) &SDL_NAME(snd_pcm_sw_params_current)}, { | |
185 "snd_pcm_sw_params_set_start_threshold", (void **) (char *) | |
186 &SDL_NAME(snd_pcm_sw_params_set_start_threshold)}, { | |
187 "snd_pcm_sw_params_set_avail_min", | |
188 (void **) (char *) &SDL_NAME(snd_pcm_sw_params_set_avail_min)}, { | |
189 "snd_pcm_sw_params", (void **) (char *) &SDL_NAME(snd_pcm_sw_params)}, { | |
190 "snd_pcm_nonblock", (void **) (char *) &SDL_NAME(snd_pcm_nonblock)},}; | |
191 | 150 |
192 static void | 151 static void |
193 UnloadALSALibrary(void) | 152 UnloadALSALibrary(void) |
194 { | 153 { |
195 if (alsa_loaded) { | 154 if (alsa_handle != NULL) { |
196 /* SDL_UnloadObject(alsa_handle);*/ | |
197 dlclose(alsa_handle); | 155 dlclose(alsa_handle); |
198 alsa_handle = NULL; | 156 alsa_handle = NULL; |
199 alsa_loaded = 0; | |
200 } | 157 } |
201 } | 158 } |
202 | 159 |
203 static int | 160 static int |
204 LoadALSALibrary(void) | 161 LoadALSALibrary(void) |
205 { | 162 { |
206 int i, retval = -1; | 163 int i, retval = -1; |
207 | 164 |
208 /* alsa_handle = SDL_LoadObject(alsa_library);*/ | |
209 alsa_handle = dlopen(alsa_library, RTLD_NOW); | 165 alsa_handle = dlopen(alsa_library, RTLD_NOW); |
210 if (alsa_handle) { | 166 if (alsa_handle == NULL) { |
211 alsa_loaded = 1; | 167 SDL_SetError("ALSA: dlopen('%s') failed: %s\n", |
212 retval = 0; | 168 alsa_library, strerror(errno)); |
213 for (i = 0; i < SDL_arraysize(alsa_functions); i++) { | 169 } else { |
214 /* *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/ | 170 retval = load_alsa_syms(); |
215 #if HAVE_DLVSYM | 171 if (retval < 0) { |
216 *alsa_functions[i].func = | 172 UnloadALSALibrary(); |
217 dlvsym(alsa_handle, alsa_functions[i].name, "ALSA_0.9"); | |
218 if (!*alsa_functions[i].func) | |
219 #endif | |
220 *alsa_functions[i].func = | |
221 dlsym(alsa_handle, alsa_functions[i].name); | |
222 if (!*alsa_functions[i].func) { | |
223 retval = -1; | |
224 UnloadALSALibrary(); | |
225 break; | |
226 } | |
227 } | 173 } |
228 } | 174 } |
229 return retval; | 175 return retval; |
230 } | 176 } |
231 | 177 |
238 } | 184 } |
239 | 185 |
240 static int | 186 static int |
241 LoadALSALibrary(void) | 187 LoadALSALibrary(void) |
242 { | 188 { |
189 load_alsa_syms(); | |
243 return 0; | 190 return 0; |
244 } | 191 } |
245 | 192 |
246 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */ | 193 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */ |
247 | 194 |
273 | 220 |
274 available = 0; | 221 available = 0; |
275 if (LoadALSALibrary() < 0) { | 222 if (LoadALSALibrary() < 0) { |
276 return available; | 223 return available; |
277 } | 224 } |
278 status = | 225 status = ALSA_snd_pcm_open(&handle, get_audio_device(2), |
279 SDL_NAME(snd_pcm_open) (&handle, get_audio_device(2), | 226 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); |
280 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | |
281 if (status >= 0) { | 227 if (status >= 0) { |
282 available = 1; | 228 available = 1; |
283 SDL_NAME(snd_pcm_close) (handle); | 229 ALSA_snd_pcm_close(handle); |
284 } | 230 } |
285 UnloadALSALibrary(); | 231 UnloadALSALibrary(); |
286 return (available); | 232 return (available); |
287 } | 233 } |
288 | 234 |
425 | 371 |
426 sample_len = this->spec.samples; | 372 sample_len = this->spec.samples; |
427 sample_buf = (signed short *) mixbuf; | 373 sample_buf = (signed short *) mixbuf; |
428 | 374 |
429 while (sample_len > 0) { | 375 while (sample_len > 0) { |
430 status = | 376 status = ALSA_snd_pcm_writei(pcm_handle, sample_buf, sample_len); |
431 SDL_NAME(snd_pcm_writei) (pcm_handle, sample_buf, sample_len); | |
432 if (status < 0) { | 377 if (status < 0) { |
433 if (status == -EAGAIN) { | 378 if (status == -EAGAIN) { |
434 SDL_Delay(1); | 379 SDL_Delay(1); |
435 continue; | 380 continue; |
436 } | 381 } |
437 if (status == -ESTRPIPE) { | 382 if (status == -ESTRPIPE) { |
438 do { | 383 do { |
439 SDL_Delay(1); | 384 SDL_Delay(1); |
440 status = SDL_NAME(snd_pcm_resume) (pcm_handle); | 385 status = ALSA_snd_pcm_resume(pcm_handle); |
441 } while (status == -EAGAIN); | 386 } while (status == -EAGAIN); |
442 } | 387 } |
443 if (status < 0) { | 388 if (status < 0) { |
444 status = SDL_NAME(snd_pcm_prepare) (pcm_handle); | 389 status = ALSA_snd_pcm_prepare(pcm_handle); |
445 } | 390 } |
446 if (status < 0) { | 391 if (status < 0) { |
447 /* Hmm, not much we can do - abort */ | 392 /* Hmm, not much we can do - abort */ |
448 this->enabled = 0; | 393 this->enabled = 0; |
449 return; | 394 return; |
467 if (mixbuf != NULL) { | 412 if (mixbuf != NULL) { |
468 SDL_FreeAudioMem(mixbuf); | 413 SDL_FreeAudioMem(mixbuf); |
469 mixbuf = NULL; | 414 mixbuf = NULL; |
470 } | 415 } |
471 if (pcm_handle) { | 416 if (pcm_handle) { |
472 SDL_NAME(snd_pcm_drain) (pcm_handle); | 417 ALSA_snd_pcm_drain(pcm_handle); |
473 SDL_NAME(snd_pcm_close) (pcm_handle); | 418 ALSA_snd_pcm_close(pcm_handle); |
474 pcm_handle = NULL; | 419 pcm_handle = NULL; |
475 } | 420 } |
476 } | 421 } |
477 | 422 |
478 static int | 423 static int |
485 snd_pcm_uframes_t frames; | 430 snd_pcm_uframes_t frames; |
486 SDL_AudioFormat test_format; | 431 SDL_AudioFormat test_format; |
487 | 432 |
488 /* Open the audio device */ | 433 /* Open the audio device */ |
489 /* Name of device should depend on # channels in spec */ | 434 /* Name of device should depend on # channels in spec */ |
490 status = | 435 status = ALSA_snd_pcm_open(&pcm_handle, |
491 SDL_NAME(snd_pcm_open) (&pcm_handle, | 436 get_audio_device(spec->channels), |
492 get_audio_device(spec->channels), | 437 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); |
493 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | |
494 | 438 |
495 if (status < 0) { | 439 if (status < 0) { |
496 SDL_SetError("Couldn't open audio device: %s", | 440 SDL_SetError("Couldn't open audio device: %s", |
497 SDL_NAME(snd_strerror) (status)); | 441 ALSA_snd_strerror(status)); |
498 return (-1); | 442 return (-1); |
499 } | 443 } |
500 | 444 |
501 /* Figure out what the hardware is capable of */ | 445 /* Figure out what the hardware is capable of */ |
502 snd_pcm_hw_params_alloca(&hwparams); | 446 snd_pcm_hw_params_alloca(&hwparams); |
503 status = SDL_NAME(snd_pcm_hw_params_any) (pcm_handle, hwparams); | 447 status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams); |
504 if (status < 0) { | 448 if (status < 0) { |
505 SDL_SetError("Couldn't get hardware config: %s", | 449 SDL_SetError("Couldn't get hardware config: %s", |
506 SDL_NAME(snd_strerror) (status)); | 450 ALSA_snd_strerror(status)); |
507 ALSA_CloseAudio(this); | 451 ALSA_CloseAudio(this); |
508 return (-1); | 452 return (-1); |
509 } | 453 } |
510 | 454 |
511 /* SDL only uses interleaved sample output */ | 455 /* SDL only uses interleaved sample output */ |
512 status = | 456 status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams, |
513 SDL_NAME(snd_pcm_hw_params_set_access) (pcm_handle, hwparams, | 457 SND_PCM_ACCESS_RW_INTERLEAVED); |
514 SND_PCM_ACCESS_RW_INTERLEAVED); | |
515 if (status < 0) { | 458 if (status < 0) { |
516 SDL_SetError("Couldn't set interleaved access: %s", | 459 SDL_SetError("Couldn't set interleaved access: %s", |
517 SDL_NAME(snd_strerror) (status)); | 460 ALSA_snd_strerror(status)); |
518 ALSA_CloseAudio(this); | 461 ALSA_CloseAudio(this); |
519 return (-1); | 462 return (-1); |
520 } | 463 } |
521 | 464 |
522 /* Try for a closest match on audio format */ | 465 /* Try for a closest match on audio format */ |
558 default: | 501 default: |
559 status = -1; | 502 status = -1; |
560 break; | 503 break; |
561 } | 504 } |
562 if (status >= 0) { | 505 if (status >= 0) { |
563 status = | 506 status = ALSA_snd_pcm_hw_params_set_format(pcm_handle, |
564 SDL_NAME(snd_pcm_hw_params_set_format) (pcm_handle, | 507 hwparams, format); |
565 hwparams, format); | |
566 } | 508 } |
567 if (status < 0) { | 509 if (status < 0) { |
568 test_format = SDL_NextAudioFormat(); | 510 test_format = SDL_NextAudioFormat(); |
569 } | 511 } |
570 } | 512 } |
574 return (-1); | 516 return (-1); |
575 } | 517 } |
576 spec->format = test_format; | 518 spec->format = test_format; |
577 | 519 |
578 /* Set the number of channels */ | 520 /* Set the number of channels */ |
579 status = | 521 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams, |
580 SDL_NAME(snd_pcm_hw_params_set_channels) (pcm_handle, hwparams, | 522 spec->channels); |
581 spec->channels); | 523 if (status < 0) { |
582 if (status < 0) { | 524 status = ALSA_snd_pcm_hw_params_get_channels(hwparams); |
583 status = SDL_NAME(snd_pcm_hw_params_get_channels) (hwparams); | |
584 if ((status <= 0) || (status > 2)) { | 525 if ((status <= 0) || (status > 2)) { |
585 SDL_SetError("Couldn't set audio channels"); | 526 SDL_SetError("Couldn't set audio channels"); |
586 ALSA_CloseAudio(this); | 527 ALSA_CloseAudio(this); |
587 return (-1); | 528 return (-1); |
588 } | 529 } |
589 spec->channels = status; | 530 spec->channels = status; |
590 } | 531 } |
591 | 532 |
592 /* Set the audio rate */ | 533 /* Set the audio rate */ |
593 status = | 534 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, |
594 SDL_NAME(snd_pcm_hw_params_set_rate_near) (pcm_handle, hwparams, | 535 spec->freq, NULL); |
595 spec->freq, NULL); | 536 if (status < 0) { |
596 if (status < 0) { | 537 ALSA_CloseAudio(this); |
597 SDL_SetError("Couldn't set audio frequency: %s", | 538 SDL_SetError("Couldn't set audio frequency: %s", |
598 SDL_NAME(snd_strerror) (status)); | 539 ALSA_snd_strerror(status)); |
599 ALSA_CloseAudio(this); | |
600 return (-1); | 540 return (-1); |
601 } | 541 } |
602 spec->freq = status; | 542 spec->freq = status; |
603 | 543 |
604 /* Set the buffer size, in samples */ | 544 /* Set the buffer size, in samples */ |
605 frames = spec->samples; | 545 frames = spec->samples; |
606 frames = | 546 frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, |
607 SDL_NAME(snd_pcm_hw_params_set_period_size_near) (pcm_handle, | 547 frames, NULL); |
608 hwparams, frames, | |
609 NULL); | |
610 spec->samples = frames; | 548 spec->samples = frames; |
611 SDL_NAME(snd_pcm_hw_params_set_periods_near) (pcm_handle, hwparams, 2, | 549 ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL); |
612 NULL); | |
613 | 550 |
614 /* "set" the hardware with the desired parameters */ | 551 /* "set" the hardware with the desired parameters */ |
615 status = SDL_NAME(snd_pcm_hw_params) (pcm_handle, hwparams); | 552 status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams); |
616 if (status < 0) { | 553 if (status < 0) { |
554 ALSA_CloseAudio(this); | |
617 SDL_SetError("Couldn't set hardware audio parameters: %s", | 555 SDL_SetError("Couldn't set hardware audio parameters: %s", |
618 SDL_NAME(snd_strerror) (status)); | 556 ALSA_snd_strerror(status)); |
619 ALSA_CloseAudio(this); | |
620 return (-1); | 557 return (-1); |
621 } | 558 } |
622 | 559 |
623 /* This is useful for debugging... */ | 560 /* This is useful for debugging... */ |
624 /* | 561 /* |
625 { snd_pcm_sframes_t bufsize; int fragments; | 562 { snd_pcm_sframes_t bufsize; int fragments; |
626 bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams); | 563 bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams); |
627 fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams); | 564 fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams); |
628 | 565 |
629 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments); | 566 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments); |
630 } | 567 } |
631 */ | 568 */ |
632 | 569 |
633 /* Set the software parameters */ | 570 /* Set the software parameters */ |
634 snd_pcm_sw_params_alloca(&swparams); | 571 snd_pcm_sw_params_alloca(&swparams); |
635 status = SDL_NAME(snd_pcm_sw_params_current) (pcm_handle, swparams); | 572 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); |
636 if (status < 0) { | 573 if (status < 0) { |
637 SDL_SetError("Couldn't get software config: %s", | 574 SDL_SetError("Couldn't get software config: %s", |
638 SDL_NAME(snd_strerror) (status)); | 575 ALSA_snd_strerror(status)); |
639 ALSA_CloseAudio(this); | 576 ALSA_CloseAudio(this); |
640 return (-1); | 577 return (-1); |
641 } | 578 } |
642 status = | 579 status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0); |
643 SDL_NAME(snd_pcm_sw_params_set_start_threshold) (pcm_handle, | |
644 swparams, 0); | |
645 if (status < 0) { | 580 if (status < 0) { |
646 SDL_SetError("Couldn't set start threshold: %s", | 581 SDL_SetError("Couldn't set start threshold: %s", |
647 SDL_NAME(snd_strerror) (status)); | 582 ALSA_snd_strerror(status)); |
648 ALSA_CloseAudio(this); | 583 ALSA_CloseAudio(this); |
649 return (-1); | 584 return (-1); |
650 } | 585 } |
651 status = | 586 status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames); |
652 SDL_NAME(snd_pcm_sw_params_set_avail_min) (pcm_handle, swparams, | 587 if (status < 0) { |
653 frames); | 588 SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status)); |
654 if (status < 0) { | 589 ALSA_CloseAudio(this); |
655 SDL_SetError("Couldn't set avail min: %s", | 590 return (-1); |
656 SDL_NAME(snd_strerror) (status)); | 591 } |
657 ALSA_CloseAudio(this); | 592 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); |
658 return (-1); | |
659 } | |
660 status = SDL_NAME(snd_pcm_sw_params) (pcm_handle, swparams); | |
661 if (status < 0) { | 593 if (status < 0) { |
662 SDL_SetError("Couldn't set software audio parameters: %s", | 594 SDL_SetError("Couldn't set software audio parameters: %s", |
663 SDL_NAME(snd_strerror) (status)); | 595 ALSA_snd_strerror(status)); |
664 ALSA_CloseAudio(this); | 596 ALSA_CloseAudio(this); |
665 return (-1); | 597 return (-1); |
666 } | 598 } |
667 | 599 |
668 /* Calculate the final parameters for this audio specification */ | 600 /* Calculate the final parameters for this audio specification */ |
679 | 611 |
680 /* Get the parent process id (we're the parent of the audio thread) */ | 612 /* Get the parent process id (we're the parent of the audio thread) */ |
681 parent = getpid(); | 613 parent = getpid(); |
682 | 614 |
683 /* Switch to blocking mode for playback */ | 615 /* Switch to blocking mode for playback */ |
684 SDL_NAME(snd_pcm_nonblock) (pcm_handle, 0); | 616 ALSA_snd_pcm_nonblock(pcm_handle, 0); |
685 | 617 |
686 /* We're ready to rock and roll. :-) */ | 618 /* We're ready to rock and roll. :-) */ |
687 return (0); | 619 return (0); |
688 } | 620 } |
689 | 621 |