comparison src/audio/alsa/SDL_alsa_audio.c @ 1552:b2462b772cce

Fixed bug #79 Implemented snd_pcm_sw_params_set_start_threshold() and snd_pcm_sw_params_set_avail_min() in the ALSA 0.9 driver. This doesn't actually change any latency for me, but it's the right thing to do...
author Sam Lantinga <slouken@libsdl.org>
date Sun, 19 Mar 2006 10:41:49 +0000
parents d910939febfa
children 63fa37538842
comparison
equal deleted inserted replaced
1551:02e19471a694 1552:b2462b772cce
67 static int (*SDL_NAME(snd_pcm_resume))(snd_pcm_t *pcm); 67 static int (*SDL_NAME(snd_pcm_resume))(snd_pcm_t *pcm);
68 static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm); 68 static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm);
69 static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm); 69 static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm);
70 static const char *(*SDL_NAME(snd_strerror))(int errnum); 70 static const char *(*SDL_NAME(snd_strerror))(int errnum);
71 static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void); 71 static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void);
72 static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
72 static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); 73 static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
73 static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); 74 static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
74 static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); 75 static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
75 static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); 76 static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
76 static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params); 77 static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params);
77 static unsigned int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); 78 static unsigned int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir);
78 static snd_pcm_uframes_t (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int *dir); 79 static snd_pcm_uframes_t (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int *dir);
79 static unsigned int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); 80 static unsigned int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir);
80 static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); 81 static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
81 static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock); 82 static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
83 /*
84 static unsigned int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params);
85 static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(snd_pcm_hw_params_t *params);
86 */
87 static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams);
88 static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
89 static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
90 static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
82 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof) 91 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
92 #define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
83 93
84 /* cast funcs to char* first, to please GCC's strict aliasing rules. */ 94 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
85 static struct { 95 static struct {
86 const char *name; 96 const char *name;
87 void **func; 97 void **func;
92 { "snd_pcm_resume", (void**)(char*)&SDL_NAME(snd_pcm_resume) }, 102 { "snd_pcm_resume", (void**)(char*)&SDL_NAME(snd_pcm_resume) },
93 { "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) }, 103 { "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) },
94 { "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) }, 104 { "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) },
95 { "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) }, 105 { "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) },
96 { "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) }, 106 { "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) },
107 { "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) },
97 { "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) }, 108 { "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) },
98 { "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) }, 109 { "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) },
99 { "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) }, 110 { "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) },
100 { "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) }, 111 { "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) },
101 { "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) }, 112 { "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) },
102 { "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) }, 113 { "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) },
103 { "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) }, 114 { "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) },
104 { "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) }, 115 { "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
105 { "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) }, 116 { "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
106 { "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) }, 117 { "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
118 /*
119 { "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
120 { "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
121 */
122 { "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) },
123 { "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) },
124 { "snd_pcm_sw_params_set_avail_min", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_avail_min) },
125 { "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
107 }; 126 };
108 127
109 static void UnloadALSALibrary(void) { 128 static void UnloadALSALibrary(void) {
110 if (alsa_loaded) { 129 if (alsa_loaded) {
111 /* SDL_UnloadObject(alsa_handle);*/ 130 /* SDL_UnloadObject(alsa_handle);*/
302 } 321 }
303 322
304 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec) 323 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
305 { 324 {
306 int status; 325 int status;
307 snd_pcm_hw_params_t *params; 326 snd_pcm_hw_params_t *hwparams;
327 snd_pcm_sw_params_t *swparams;
308 snd_pcm_format_t format; 328 snd_pcm_format_t format;
309 snd_pcm_uframes_t frames; 329 snd_pcm_uframes_t frames;
310 Uint16 test_format; 330 Uint16 test_format;
311 331
312 /* Open the audio device */ 332 /* Open the audio device */
317 SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status)); 337 SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status));
318 return(-1); 338 return(-1);
319 } 339 }
320 340
321 /* Figure out what the hardware is capable of */ 341 /* Figure out what the hardware is capable of */
322 snd_pcm_hw_params_alloca(&params); 342 snd_pcm_hw_params_alloca(&hwparams);
323 status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, params); 343 status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams);
324 if ( status < 0 ) { 344 if ( status < 0 ) {
325 SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status)); 345 SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status));
326 ALSA_CloseAudio(this); 346 ALSA_CloseAudio(this);
327 return(-1); 347 return(-1);
328 } 348 }
329 349
330 /* SDL only uses interleaved sample output */ 350 /* SDL only uses interleaved sample output */
331 status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); 351 status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
332 if ( status < 0 ) { 352 if ( status < 0 ) {
333 SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status)); 353 SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status));
334 ALSA_CloseAudio(this); 354 ALSA_CloseAudio(this);
335 return(-1); 355 return(-1);
336 } 356 }
361 default: 381 default:
362 format = 0; 382 format = 0;
363 break; 383 break;
364 } 384 }
365 if ( format != 0 ) { 385 if ( format != 0 ) {
366 status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, params, format); 386 status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format);
367 } 387 }
368 if ( status < 0 ) { 388 if ( status < 0 ) {
369 test_format = SDL_NextAudioFormat(); 389 test_format = SDL_NextAudioFormat();
370 } 390 }
371 } 391 }
375 return(-1); 395 return(-1);
376 } 396 }
377 spec->format = test_format; 397 spec->format = test_format;
378 398
379 /* Set the number of channels */ 399 /* Set the number of channels */
380 status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, params, spec->channels); 400 status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels);
381 if ( status < 0 ) { 401 if ( status < 0 ) {
382 status = SDL_NAME(snd_pcm_hw_params_get_channels)(params); 402 status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams);
383 if ( (status <= 0) || (status > 2) ) { 403 if ( (status <= 0) || (status > 2) ) {
384 SDL_SetError("Couldn't set audio channels"); 404 SDL_SetError("Couldn't set audio channels");
385 ALSA_CloseAudio(this); 405 ALSA_CloseAudio(this);
386 return(-1); 406 return(-1);
387 } 407 }
388 spec->channels = status; 408 spec->channels = status;
389 } 409 }
390 410
391 /* Set the audio rate */ 411 /* Set the audio rate */
392 status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, params, spec->freq, NULL); 412 status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, spec->freq, NULL);
393 if ( status < 0 ) { 413 if ( status < 0 ) {
394 SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status)); 414 SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
395 ALSA_CloseAudio(this); 415 ALSA_CloseAudio(this);
396 return(-1); 416 return(-1);
397 } 417 }
398 spec->freq = status; 418 spec->freq = status;
399 419
400 /* Set the buffer size, in samples */ 420 /* Set the buffer size, in samples */
401 frames = spec->samples; 421 frames = spec->samples;
402 frames = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, params, frames, NULL); 422 frames = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, frames, NULL);
403 spec->samples = frames; 423 spec->samples = frames;
404 SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, params, 2, NULL); 424 SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, 2, NULL);
405 425
406 /* "set" the hardware with the desired parameters */ 426 /* "set" the hardware with the desired parameters */
407 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, params); 427 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
408 if ( status < 0 ) { 428 if ( status < 0 ) {
409 SDL_SetError("Couldn't set audio parameters: %s", SDL_NAME(snd_strerror)(status)); 429 SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
430 ALSA_CloseAudio(this);
431 return(-1);
432 }
433
434 /*
435 { unsigned int bufsize; int fragments;
436 bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams);
437 fragments = SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams);
438
439 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);
440 }
441 */
442
443 /* Set the software parameters */
444 snd_pcm_sw_params_alloca(&swparams);
445 status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams);
446 if ( status < 0 ) {
447 SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status));
448 ALSA_CloseAudio(this);
449 return(-1);
450 }
451 status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 0);
452 if ( status < 0 ) {
453 SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status));
454 ALSA_CloseAudio(this);
455 return(-1);
456 }
457 status = SDL_NAME(snd_pcm_sw_params_set_avail_min)(pcm_handle, swparams, frames);
458 if ( status < 0 ) {
459 SDL_SetError("Couldn't set avail min: %s", SDL_NAME(snd_strerror)(status));
460 ALSA_CloseAudio(this);
461 return(-1);
462 }
463 status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
464 if ( status < 0 ) {
465 SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
410 ALSA_CloseAudio(this); 466 ALSA_CloseAudio(this);
411 return(-1); 467 return(-1);
412 } 468 }
413 469
414 /* Calculate the final parameters for this audio specification */ 470 /* Calculate the final parameters for this audio specification */