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: */