Mercurial > sdl-ios-xcode
comparison src/audio/alsa/SDL_alsa_audio.c @ 3819:b225d9820ee3 SDL-ryan-multiple-audio-device
Updated a bunch of audio backends to 1.3 API (Dreamcast, OS/2, ALSA, and
BeOS). None are tested, so anyu could fail to compile.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 06 Oct 2006 20:36:23 +0000 |
parents | 49eadd6e8962 |
children | 25052dd25810 |
comparison
equal
deleted
inserted
replaced
3818:49eadd6e8962 | 3819:b225d9820ee3 |
---|---|
39 /* The tag name used by ALSA audio */ | 39 /* The tag name used by ALSA audio */ |
40 #define DRIVER_NAME "alsa" | 40 #define DRIVER_NAME "alsa" |
41 | 41 |
42 /* The default ALSA audio driver */ | 42 /* The default ALSA audio driver */ |
43 #define DEFAULT_DEVICE "default" | 43 #define DEFAULT_DEVICE "default" |
44 | |
45 /* Audio driver functions */ | |
46 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec); | |
47 static void ALSA_WaitAudio(_THIS); | |
48 static void ALSA_PlayAudio(_THIS); | |
49 static Uint8 *ALSA_GetAudioBuf(_THIS); | |
50 static void ALSA_CloseAudio(_THIS); | |
51 | 44 |
52 static int (*ALSA_snd_pcm_open) | 45 static int (*ALSA_snd_pcm_open) |
53 (snd_pcm_t **, const char *, snd_pcm_stream_t, int); | 46 (snd_pcm_t **, const char *, snd_pcm_stream_t, int); |
54 static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm); | 47 static int (*ALSA_snd_pcm_close)(snd_pcm_t * pcm); |
55 static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) | 48 static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) |
146 SDL_ALSA_SYM(snd_pcm_sw_params); | 139 SDL_ALSA_SYM(snd_pcm_sw_params); |
147 SDL_ALSA_SYM(snd_pcm_nonblock); | 140 SDL_ALSA_SYM(snd_pcm_nonblock); |
148 return 0; | 141 return 0; |
149 } | 142 } |
150 | 143 |
144 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC | |
145 | |
146 static int library_load_count = 0; | |
147 | |
151 static void | 148 static void |
152 UnloadALSALibrary(void) | 149 UnloadALSALibrary(void) |
153 { | 150 { |
154 if (alsa_handle != NULL) { | 151 if ((alsa_handle != NULL) && (--library_load_count == 0)) { |
155 dlclose(alsa_handle); | 152 dlclose(alsa_handle); |
156 alsa_handle = NULL; | 153 alsa_handle = NULL; |
157 } | 154 } |
158 } | 155 } |
159 | 156 |
160 static int | 157 static int |
161 LoadALSALibrary(void) | 158 LoadALSALibrary(void) |
162 { | 159 { |
163 int i, retval = -1; | 160 int retval = 0; |
164 | 161 if (library_load_count++ == 0) { |
165 alsa_handle = dlopen(alsa_library, RTLD_NOW); | 162 alsa_handle = dlopen(alsa_library, RTLD_NOW); |
166 if (alsa_handle == NULL) { | 163 if (alsa_handle == NULL) { |
167 SDL_SetError("ALSA: dlopen('%s') failed: %s\n", | 164 library_load_count--; |
168 alsa_library, strerror(errno)); | 165 retval = -1; |
169 } else { | 166 SDL_SetError("ALSA: dlopen('%s') failed: %s\n", |
170 retval = load_alsa_syms(); | 167 alsa_library, strerror(errno)); |
171 if (retval < 0) { | 168 } else { |
172 UnloadALSALibrary(); | 169 retval = load_alsa_syms(); |
170 if (retval < 0) { | |
171 UnloadALSALibrary(); | |
172 } | |
173 } | 173 } |
174 } | 174 } |
175 return retval; | 175 return retval; |
176 } | 176 } |
177 | 177 |
178 #else | 178 #else |
179 | 179 |
180 static void | 180 static void |
181 UnloadALSALibrary(void) | 181 UnloadALSALibrary(void) |
182 { | 182 { |
183 return; | |
184 } | 183 } |
185 | 184 |
186 static int | 185 static int |
187 LoadALSALibrary(void) | 186 LoadALSALibrary(void) |
188 { | 187 { |
207 device = DEFAULT_DEVICE; | 206 device = DEFAULT_DEVICE; |
208 } | 207 } |
209 return device; | 208 return device; |
210 } | 209 } |
211 | 210 |
212 /* Audio driver bootstrap functions */ | |
213 | 211 |
214 static int | 212 static int |
215 Audio_Available(void) | 213 ALSA_Available(void) |
216 { | 214 { |
217 int available; | 215 int available = 0; |
218 int status; | 216 int status; |
219 snd_pcm_t *handle; | 217 snd_pcm_t *handle; |
220 | 218 |
221 available = 0; | 219 if (LoadALSALibrary() >= 0) { |
222 if (LoadALSALibrary() < 0) { | 220 int status = ALSA_snd_pcm_open(&handle, get_audio_device(2), |
223 return available; | 221 SND_PCM_STREAM_PLAYBACK, |
224 } | 222 SND_PCM_NONBLOCK); |
225 status = ALSA_snd_pcm_open(&handle, get_audio_device(2), | 223 if (status >= 0) { |
226 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | 224 available = 1; |
227 if (status >= 0) { | 225 ALSA_snd_pcm_close(handle); |
228 available = 1; | 226 } |
229 ALSA_snd_pcm_close(handle); | 227 UnloadALSALibrary(); |
230 } | 228 } |
231 UnloadALSALibrary(); | |
232 return (available); | 229 return (available); |
233 } | 230 } |
234 | 231 |
235 static void | 232 |
236 Audio_DeleteDevice(SDL_AudioDevice * device) | |
237 { | |
238 SDL_free(device->hidden); | |
239 SDL_free(device); | |
240 UnloadALSALibrary(); | |
241 } | |
242 | |
243 static SDL_AudioDevice * | |
244 Audio_CreateDevice(int devindex) | |
245 { | |
246 SDL_AudioDevice *this; | |
247 | |
248 /* Initialize all variables that we clean on shutdown */ | |
249 LoadALSALibrary(); | |
250 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | |
251 if (this) { | |
252 SDL_memset(this, 0, (sizeof *this)); | |
253 this->hidden = (struct SDL_PrivateAudioData *) | |
254 SDL_malloc((sizeof *this->hidden)); | |
255 } | |
256 if ((this == NULL) || (this->hidden == NULL)) { | |
257 SDL_OutOfMemory(); | |
258 if (this) { | |
259 SDL_free(this); | |
260 } | |
261 return (0); | |
262 } | |
263 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
264 | |
265 /* Set the function pointers */ | |
266 this->OpenAudio = ALSA_OpenAudio; | |
267 this->WaitAudio = ALSA_WaitAudio; | |
268 this->PlayAudio = ALSA_PlayAudio; | |
269 this->GetAudioBuf = ALSA_GetAudioBuf; | |
270 this->CloseAudio = ALSA_CloseAudio; | |
271 | |
272 this->free = Audio_DeleteDevice; | |
273 | |
274 return this; | |
275 } | |
276 | |
277 AudioBootStrap ALSA_bootstrap = { | |
278 DRIVER_NAME, "ALSA 0.9 PCM audio", | |
279 Audio_Available, Audio_CreateDevice, 0 | |
280 }; | |
281 | 233 |
282 /* This function waits until it is possible to write a full sound buffer */ | 234 /* This function waits until it is possible to write a full sound buffer */ |
283 static void | 235 static void |
284 ALSA_WaitAudio(_THIS) | 236 ALSA_WaitDevice(_THIS) |
285 { | 237 { |
286 /* Check to see if the thread-parent process is still alive */ | 238 /* Check to see if the thread-parent process is still alive */ |
287 { | 239 { |
288 static int cnt = 0; | 240 static int cnt = 0; |
289 /* Note that this only works with thread implementations | 241 /* Note that this only works with thread implementations |
290 that use a different process id for each thread. | 242 that use a different process id for each thread. |
291 */ | 243 */ |
292 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ | 244 /* Check every 10 loops */ |
293 if (kill(parent, 0) < 0) { | 245 if (this->hidden->parent && (((++cnt) % 10) == 0)) { |
246 if (kill(this->hidden->parent, 0) < 0) { | |
294 this->enabled = 0; | 247 this->enabled = 0; |
295 } | 248 } |
296 } | 249 } |
297 } | 250 } |
298 } | 251 } |
299 | 252 |
300 | 253 |
254 /* !!! FIXME: is there a channel swizzler in alsalib instead? */ | |
301 /* | 255 /* |
302 * http://bugzilla.libsdl.org/show_bug.cgi?id=110 | 256 * http://bugzilla.libsdl.org/show_bug.cgi?id=110 |
303 * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE | 257 * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE |
304 * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR" | 258 * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR" |
305 */ | 259 */ |
306 #define SWIZ6(T) \ | 260 #define SWIZ6(T) \ |
307 T *ptr = (T *) mixbuf; \ | 261 T *ptr = (T *) this->hidden->mixbuf; \ |
308 const Uint32 count = (this->spec.samples / 6); \ | 262 const Uint32 count = (this->spec.samples / 6); \ |
309 Uint32 i; \ | 263 Uint32 i; \ |
310 for (i = 0; i < count; i++, ptr += 6) { \ | 264 for (i = 0; i < count; i++, ptr += 6) { \ |
311 T tmp; \ | 265 T tmp; \ |
312 tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \ | 266 tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \ |
336 | 290 |
337 #undef SWIZ6 | 291 #undef SWIZ6 |
338 | 292 |
339 | 293 |
340 /* | 294 /* |
341 * Called right before feeding this->mixbuf to the hardware. Swizzle channels | 295 * Called right before feeding this->hidden->mixbuf to the hardware. Swizzle |
342 * from Windows/Mac order to the format alsalib will want. | 296 * channels from Windows/Mac order to the format alsalib will want. |
343 */ | 297 */ |
344 static __inline__ void | 298 static __inline__ void |
345 swizzle_alsa_channels(_THIS) | 299 swizzle_alsa_channels(_THIS) |
346 { | 300 { |
347 if (this->spec.channels == 6) { | 301 if (this->spec.channels == 6) { |
359 /* !!! FIXME: update this for 7.1 if needed, later. */ | 313 /* !!! FIXME: update this for 7.1 if needed, later. */ |
360 } | 314 } |
361 | 315 |
362 | 316 |
363 static void | 317 static void |
364 ALSA_PlayAudio(_THIS) | 318 ALSA_PlayDevice(_THIS) |
365 { | 319 { |
366 int status; | 320 int status; |
367 int sample_len; | 321 int sample_len; |
368 signed short *sample_buf; | 322 signed short *sample_buf; |
369 | 323 |
370 swizzle_alsa_channels(this); | 324 swizzle_alsa_channels(this); |
371 | 325 |
372 sample_len = this->spec.samples; | 326 sample_len = this->spec.samples; |
373 sample_buf = (signed short *) mixbuf; | 327 sample_buf = (signed short *) this->hidden->mixbuf; |
374 | 328 |
375 while (sample_len > 0) { | 329 while (sample_len > 0) { |
376 status = ALSA_snd_pcm_writei(pcm_handle, sample_buf, sample_len); | 330 status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, |
331 sample_buf, sample_len); | |
332 | |
377 if (status < 0) { | 333 if (status < 0) { |
378 if (status == -EAGAIN) { | 334 if (status == -EAGAIN) { |
379 SDL_Delay(1); | 335 SDL_Delay(1); |
380 continue; | 336 continue; |
381 } | 337 } |
382 if (status == -ESTRPIPE) { | 338 if (status == -ESTRPIPE) { |
383 do { | 339 do { |
384 SDL_Delay(1); | 340 SDL_Delay(1); |
385 status = ALSA_snd_pcm_resume(pcm_handle); | 341 status = ALSA_snd_pcm_resume(this->hidden->pcm_handle); |
386 } while (status == -EAGAIN); | 342 } while (status == -EAGAIN); |
387 } | 343 } |
388 if (status < 0) { | 344 if (status < 0) { |
389 status = ALSA_snd_pcm_prepare(pcm_handle); | 345 status = ALSA_snd_pcm_prepare(this->hidden->pcm_handle); |
390 } | 346 } |
391 if (status < 0) { | 347 if (status < 0) { |
392 /* Hmm, not much we can do - abort */ | 348 /* Hmm, not much we can do - abort */ |
393 this->enabled = 0; | 349 this->enabled = 0; |
394 return; | 350 return; |
399 sample_len -= status; | 355 sample_len -= status; |
400 } | 356 } |
401 } | 357 } |
402 | 358 |
403 static Uint8 * | 359 static Uint8 * |
404 ALSA_GetAudioBuf(_THIS) | 360 ALSA_GetDeviceBuf(_THIS) |
405 { | 361 { |
406 return (mixbuf); | 362 return (this->hidden->mixbuf); |
407 } | 363 } |
408 | 364 |
409 static void | 365 static void |
410 ALSA_CloseAudio(_THIS) | 366 ALSA_CloseDevice(_THIS) |
411 { | 367 { |
412 if (mixbuf != NULL) { | 368 if (this->hidden != NULL) { |
413 SDL_FreeAudioMem(mixbuf); | 369 if (this->hidden->mixbuf != NULL) { |
414 mixbuf = NULL; | 370 SDL_FreeAudioMem(this->hidden->mixbuf); |
415 } | 371 this->hidden->mixbuf = NULL; |
416 if (pcm_handle) { | 372 } |
417 ALSA_snd_pcm_drain(pcm_handle); | 373 if (this->hidden->pcm_handle) { |
418 ALSA_snd_pcm_close(pcm_handle); | 374 ALSA_snd_pcm_drain(this->hidden->pcm_handle); |
419 pcm_handle = NULL; | 375 ALSA_snd_pcm_close(this->hidden->pcm_handle); |
376 this->hidden->pcm_handle = NULL; | |
377 } | |
378 SDL_free(this->hidden); | |
379 this->hidden = NULL; | |
420 } | 380 } |
421 } | 381 } |
422 | 382 |
423 static int | 383 static int |
424 ALSA_OpenAudio(_THIS, SDL_AudioSpec * spec) | 384 ALSA_OpenDevice(_THIS, const char *devname, int iscapture) |
425 { | 385 { |
426 int status; | 386 int status = 0; |
427 snd_pcm_hw_params_t *hwparams; | 387 snd_pcm_t *pcm_handle = NULL; |
428 snd_pcm_sw_params_t *swparams; | 388 snd_pcm_hw_params_t *hwparams = NULL; |
429 snd_pcm_format_t format; | 389 snd_pcm_sw_params_t *swparams = NULL; |
430 snd_pcm_uframes_t frames; | 390 snd_pcm_format_t format = 0; |
431 SDL_AudioFormat test_format; | 391 snd_pcm_uframes_t frames = 0; |
392 SDL_AudioFormat test_format = 0; | |
393 | |
394 /* Initialize all variables that we clean on shutdown */ | |
395 this->hidden = (struct SDL_PrivateAudioData *) | |
396 SDL_malloc((sizeof *this->hidden)); | |
397 if (this->hidden == NULL) { | |
398 SDL_OutOfMemory(); | |
399 return 0; | |
400 } | |
401 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
432 | 402 |
433 /* Open the audio device */ | 403 /* Open the audio device */ |
434 /* Name of device should depend on # channels in spec */ | 404 /* Name of device should depend on # channels in spec */ |
435 status = ALSA_snd_pcm_open(&pcm_handle, | 405 status = ALSA_snd_pcm_open(&pcm_handle, |
436 get_audio_device(spec->channels), | 406 get_audio_device(this->spec.channels), |
437 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | 407 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); |
438 | 408 |
439 if (status < 0) { | 409 if (status < 0) { |
440 SDL_SetError("Couldn't open audio device: %s", | 410 ALSA_CloseDevice(this); |
441 ALSA_snd_strerror(status)); | 411 SDL_SetError("ALSA: Couldn't open audio device: %s", |
442 return (-1); | 412 ALSA_snd_strerror(status)); |
443 } | 413 return 0; |
414 } | |
415 | |
416 this->hidden->pcm_handle = pcm_handle; | |
444 | 417 |
445 /* Figure out what the hardware is capable of */ | 418 /* Figure out what the hardware is capable of */ |
446 snd_pcm_hw_params_alloca(&hwparams); | 419 snd_pcm_hw_params_alloca(&hwparams); |
447 status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams); | 420 status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams); |
448 if (status < 0) { | 421 if (status < 0) { |
449 SDL_SetError("Couldn't get hardware config: %s", | 422 ALSA_CloseDevice(this); |
450 ALSA_snd_strerror(status)); | 423 SDL_SetError("ALSA: Couldn't get hardware config: %s", |
451 ALSA_CloseAudio(this); | 424 ALSA_snd_strerror(status)); |
452 return (-1); | 425 return 0; |
453 } | 426 } |
454 | 427 |
455 /* SDL only uses interleaved sample output */ | 428 /* SDL only uses interleaved sample output */ |
456 status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams, | 429 status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams, |
457 SND_PCM_ACCESS_RW_INTERLEAVED); | 430 SND_PCM_ACCESS_RW_INTERLEAVED); |
458 if (status < 0) { | 431 if (status < 0) { |
459 SDL_SetError("Couldn't set interleaved access: %s", | 432 ALSA_CloseDevice(this); |
460 ALSA_snd_strerror(status)); | 433 SDL_SetError("ALSA: Couldn't set interleaved access: %s", |
461 ALSA_CloseAudio(this); | 434 ALSA_snd_strerror(status)); |
462 return (-1); | 435 return 0; |
463 } | 436 } |
464 | 437 |
465 /* Try for a closest match on audio format */ | 438 /* Try for a closest match on audio format */ |
466 status = -1; | 439 status = -1; |
467 for (test_format = SDL_FirstAudioFormat(spec->format); | 440 for (test_format = SDL_FirstAudioFormat(this->spec.format); |
468 test_format && (status < 0);) { | 441 test_format && (status < 0);) { |
469 status = 0; /* if we can't support a format, it'll become -1. */ | 442 status = 0; /* if we can't support a format, it'll become -1. */ |
470 switch (test_format) { | 443 switch (test_format) { |
471 case AUDIO_U8: | 444 case AUDIO_U8: |
472 format = SND_PCM_FORMAT_U8; | 445 format = SND_PCM_FORMAT_U8; |
473 break; | 446 break; |
474 case AUDIO_S8: | 447 case AUDIO_S8: |
509 if (status < 0) { | 482 if (status < 0) { |
510 test_format = SDL_NextAudioFormat(); | 483 test_format = SDL_NextAudioFormat(); |
511 } | 484 } |
512 } | 485 } |
513 if (status < 0) { | 486 if (status < 0) { |
514 SDL_SetError("Couldn't find any hardware audio formats"); | 487 ALSA_CloseDevice(this); |
515 ALSA_CloseAudio(this); | 488 SDL_SetError("ALSA: Couldn't find any hardware audio formats"); |
516 return (-1); | 489 return 0; |
517 } | 490 } |
518 spec->format = test_format; | 491 this->spec.format = test_format; |
519 | 492 |
520 /* Set the number of channels */ | 493 /* Set the number of channels */ |
521 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams, | 494 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams, |
522 spec->channels); | 495 this->spec.channels); |
523 if (status < 0) { | 496 if (status < 0) { |
524 status = ALSA_snd_pcm_hw_params_get_channels(hwparams); | 497 status = ALSA_snd_pcm_hw_params_get_channels(hwparams); |
525 if ((status <= 0) || (status > 2)) { | 498 if ((status <= 0) || (status > 2)) { |
526 SDL_SetError("Couldn't set audio channels"); | 499 ALSA_CloseDevice(this); |
527 ALSA_CloseAudio(this); | 500 SDL_SetError("ALSA: Couldn't set audio channels"); |
528 return (-1); | 501 return 0; |
529 } | 502 } |
530 spec->channels = status; | 503 this->spec.channels = status; |
531 } | 504 } |
532 | 505 |
533 /* Set the audio rate */ | 506 /* Set the audio rate */ |
534 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, | 507 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, |
535 spec->freq, NULL); | 508 this->spec.freq, NULL); |
536 if (status < 0) { | 509 if (status < 0) { |
537 ALSA_CloseAudio(this); | 510 ALSA_CloseDevice(this); |
538 SDL_SetError("Couldn't set audio frequency: %s", | 511 SDL_SetError("ALSA: Couldn't set audio frequency: %s", |
539 ALSA_snd_strerror(status)); | 512 ALSA_snd_strerror(status)); |
540 return (-1); | 513 return 0; |
541 } | 514 } |
542 spec->freq = status; | 515 this->spec.freq = status; |
543 | 516 |
544 /* Set the buffer size, in samples */ | 517 /* Set the buffer size, in samples */ |
545 frames = spec->samples; | 518 frames = this->spec.samples; |
546 frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, | 519 frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, |
547 frames, NULL); | 520 frames, NULL); |
548 spec->samples = frames; | 521 this->spec.samples = frames; |
549 ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL); | 522 ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL); |
550 | 523 |
551 /* "set" the hardware with the desired parameters */ | 524 /* "set" the hardware with the desired parameters */ |
552 status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams); | 525 status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams); |
553 if (status < 0) { | 526 if (status < 0) { |
554 ALSA_CloseAudio(this); | 527 ALSA_CloseDevice(this); |
555 SDL_SetError("Couldn't set hardware audio parameters: %s", | 528 SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s", |
556 ALSA_snd_strerror(status)); | 529 ALSA_snd_strerror(status)); |
557 return (-1); | 530 return 0; |
558 } | 531 } |
559 | 532 |
560 /* This is useful for debugging... */ | 533 #if AUDIO_DEBUG |
561 /* | 534 { |
562 { snd_pcm_sframes_t bufsize; int fragments; | 535 snd_pcm_sframes_t bufsize; |
563 bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams); | 536 int fragments; |
564 fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams); | 537 bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams); |
565 | 538 fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams); |
566 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments); | 539 fprintf(stderr,"ALSA: bufsize = %ld, fragments = %d\n",bufsize,fragments); |
567 } | 540 } |
568 */ | 541 #endif |
569 | 542 |
570 /* Set the software parameters */ | 543 /* Set the software parameters */ |
571 snd_pcm_sw_params_alloca(&swparams); | 544 snd_pcm_sw_params_alloca(&swparams); |
572 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); | 545 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); |
573 if (status < 0) { | 546 if (status < 0) { |
574 SDL_SetError("Couldn't get software config: %s", | 547 ALSA_CloseDevice(this); |
575 ALSA_snd_strerror(status)); | 548 SDL_SetError("ALSA: Couldn't get software config: %s", |
576 ALSA_CloseAudio(this); | 549 ALSA_snd_strerror(status)); |
577 return (-1); | 550 return 0; |
578 } | 551 } |
579 status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0); | 552 status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle,swparams,0); |
580 if (status < 0) { | 553 if (status < 0) { |
581 SDL_SetError("Couldn't set start threshold: %s", | 554 ALSA_CloseDevice(this); |
582 ALSA_snd_strerror(status)); | 555 SDL_SetError("ALSA: Couldn't set start threshold: %s", |
583 ALSA_CloseAudio(this); | 556 ALSA_snd_strerror(status)); |
584 return (-1); | 557 return 0; |
585 } | 558 } |
586 status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames); | 559 status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames); |
587 if (status < 0) { | 560 if (status < 0) { |
561 ALSA_CloseDevice(this); | |
588 SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status)); | 562 SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status)); |
589 ALSA_CloseAudio(this); | 563 return 0; |
590 return (-1); | |
591 } | 564 } |
592 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); | 565 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); |
593 if (status < 0) { | 566 if (status < 0) { |
567 ALSA_CloseDevice(this); | |
594 SDL_SetError("Couldn't set software audio parameters: %s", | 568 SDL_SetError("Couldn't set software audio parameters: %s", |
595 ALSA_snd_strerror(status)); | 569 ALSA_snd_strerror(status)); |
596 ALSA_CloseAudio(this); | 570 return 0; |
597 return (-1); | |
598 } | 571 } |
599 | 572 |
600 /* Calculate the final parameters for this audio specification */ | 573 /* Calculate the final parameters for this audio specification */ |
601 SDL_CalculateAudioSpec(spec); | 574 SDL_CalculateAudioSpec(&this->spec); |
602 | 575 |
603 /* Allocate mixing buffer */ | 576 /* Allocate mixing buffer */ |
604 mixlen = spec->size; | 577 this->hidden->mixlen = this->spec.size; |
605 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); | 578 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); |
606 if (mixbuf == NULL) { | 579 if (this->hidden->mixbuf == NULL) { |
607 ALSA_CloseAudio(this); | 580 ALSA_CloseDevice(this); |
608 return (-1); | 581 SDL_OutOfMemory(); |
609 } | 582 return 0; |
610 SDL_memset(mixbuf, spec->silence, spec->size); | 583 } |
584 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | |
611 | 585 |
612 /* Get the parent process id (we're the parent of the audio thread) */ | 586 /* Get the parent process id (we're the parent of the audio thread) */ |
613 parent = getpid(); | 587 this->hidden->parent = getpid(); |
614 | 588 |
615 /* Switch to blocking mode for playback */ | 589 /* Switch to blocking mode for playback */ |
616 ALSA_snd_pcm_nonblock(pcm_handle, 0); | 590 ALSA_snd_pcm_nonblock(pcm_handle, 0); |
617 | 591 |
618 /* We're ready to rock and roll. :-) */ | 592 /* We're ready to rock and roll. :-) */ |
619 return (0); | 593 return 1; |
620 } | 594 } |
595 | |
596 static int | |
597 ALSA_Init(SDL_AudioDriverImpl *impl) | |
598 { | |
599 /* Set the function pointers */ | |
600 impl->OpenDevice = ALSA_OpenDevice; | |
601 impl->WaitDevice = ALSA_WaitDevice; | |
602 impl->GetDeviceBuf = ALSA_GetDeviceBuf; | |
603 impl->PlayDevice = ALSA_PlayDevice; | |
604 impl->CloseDevice = ALSA_CloseDevice; | |
605 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */ | |
606 | |
607 return 1; | |
608 } | |
609 | |
610 | |
611 AudioBootStrap ALSA_bootstrap = { | |
612 DRIVER_NAME, "ALSA 0.9 PCM audio", | |
613 ALSA_Available, ALSA_Init, 0 | |
614 }; | |
621 | 615 |
622 /* vi: set ts=4 sw=4 expandtab: */ | 616 /* vi: set ts=4 sw=4 expandtab: */ |