comparison src/audio/alsa/SDL_alsa_audio.c @ 3362:4e83cdb58134

Merged r4990:4991 from branches/SDL-1.2: ALSA 1.0 API and dlvsym() removal.
author Ryan C. Gordon <icculus@icculus.org>
date Sat, 10 Oct 2009 07:34:15 +0000
parents b21348d47cab
children 631173ffd68f
comparison
equal deleted inserted replaced
3361:d559edc85610 3362:4e83cdb58134
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> 28 #include <errno.h>
30 #include <string.h> 29 #include <string.h>
31 30
32 #include "SDL_timer.h" 31 #include "SDL_timer.h"
33 #include "SDL_audio.h" 32 #include "SDL_audio.h"
34 #include "../SDL_audiomem.h" 33 #include "../SDL_audiomem.h"
35 #include "../SDL_audio_c.h" 34 #include "../SDL_audio_c.h"
36 #include "SDL_alsa_audio.h" 35 #include "SDL_alsa_audio.h"
37 36
37 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
38 #include "SDL_loadso.h"
39 #endif
38 40
39 /* The tag name used by ALSA audio */ 41 /* The tag name used by ALSA audio */
40 #define DRIVER_NAME "alsa" 42 #define DRIVER_NAME "alsa"
41 43
42 /* The default ALSA audio driver */ 44 /* The default ALSA audio driver */
58 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t); 60 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
59 static int (*ALSA_snd_pcm_hw_params_set_format) 61 static int (*ALSA_snd_pcm_hw_params_set_format)
60 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t); 62 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
61 static int (*ALSA_snd_pcm_hw_params_set_channels) 63 static int (*ALSA_snd_pcm_hw_params_set_channels)
62 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int); 64 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
63 static int (*ALSA_snd_pcm_hw_params_get_channels) (const snd_pcm_hw_params_t 65 static int (*ALSA_snd_pcm_hw_params_set_rate_near)
64 *); 66 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
65 static unsigned int (*ALSA_snd_pcm_hw_params_set_rate_near) 67 static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
66 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int, int *); 68 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
67 static snd_pcm_uframes_t(*ALSA_snd_pcm_hw_params_set_period_size_near) 69 static int (*ALSA_snd_pcm_hw_params_get_channels)
68 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t, int *); 70 (const snd_pcm_hw_params_t *, unsigned int *);
69 static snd_pcm_sframes_t(*ALSA_snd_pcm_hw_params_get_period_size) 71 static snd_pcm_sframes_t(*ALSA_snd_pcm_hw_params_get_period_size)
70 (const snd_pcm_hw_params_t *); 72 (const snd_pcm_hw_params_t *);
71 static unsigned int (*ALSA_snd_pcm_hw_params_set_periods_near) 73 static int (*ALSA_snd_pcm_hw_params_set_periods_near)
72 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int, int *); 74 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
73 static int (*ALSA_snd_pcm_hw_params_get_periods) (snd_pcm_hw_params_t *); 75 static int (*ALSA_snd_pcm_hw_params_get_periods) (snd_pcm_hw_params_t *);
74 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *); 76 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *);
75 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *, 77 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *,
76 snd_pcm_sw_params_t *); 78 snd_pcm_sw_params_t *);
77 static int (*ALSA_snd_pcm_sw_params_set_start_threshold) 79 static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
90 static void *alsa_handle = NULL; 92 static void *alsa_handle = NULL;
91 93
92 static int 94 static int
93 load_alsa_sym(const char *fn, void **addr) 95 load_alsa_sym(const char *fn, void **addr)
94 { 96 {
95 /* 97 *addr = SDL_LoadFunction(alsa_handle, fn);
96 * !!! FIXME: 98 if (*addr == NULL) {
97 * Eventually, this will deal with fallbacks, version changes, and 99 /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
98 * missing symbols we can workaround. But for now, it doesn't. 100 return 0;
99 */
100
101 #if HAVE_DLVSYM
102 *addr = dlvsym(alsa_handle, fn, "ALSA_0.9");
103 if (*addr == NULL)
104 #endif
105 {
106 *addr = dlsym(alsa_handle, fn);
107 if (*addr == NULL) {
108 SDL_SetError("dlsym('%s') failed: %s", fn, strerror(errno));
109 return 0;
110 }
111 } 101 }
112 102
113 return 1; 103 return 1;
114 } 104 }
115 105
157 147
158 static void 148 static void
159 UnloadALSALibrary(void) 149 UnloadALSALibrary(void)
160 { 150 {
161 if (alsa_handle != NULL) { 151 if (alsa_handle != NULL) {
162 dlclose(alsa_handle); 152 SDL_UnloadObject(alsa_handle);
163 alsa_handle = NULL; 153 alsa_handle = NULL;
164 } 154 }
165 } 155 }
166 156
167 static int 157 static int
168 LoadALSALibrary(void) 158 LoadALSALibrary(void)
169 { 159 {
170 int retval = 0; 160 int retval = 0;
171 if (alsa_handle == NULL) { 161 if (alsa_handle == NULL) {
172 alsa_handle = dlopen(alsa_library, RTLD_NOW); 162 alsa_handle = SDL_LoadObject(alsa_library);
173 if (alsa_handle == NULL) { 163 if (alsa_handle == NULL) {
174 retval = -1; 164 retval = -1;
175 SDL_SetError("ALSA: dlopen('%s') failed: %s\n", 165 /* Don't call SDL_SetError(): SDL_LoadObject already did. */
176 alsa_library, strerror(errno));
177 } else { 166 } else {
178 retval = load_alsa_syms(); 167 retval = load_alsa_syms();
179 if (retval < 0) { 168 if (retval < 0) {
180 UnloadALSALibrary(); 169 UnloadALSALibrary();
181 } 170 }
378 snd_pcm_hw_params_t *hwparams = NULL; 367 snd_pcm_hw_params_t *hwparams = NULL;
379 snd_pcm_sw_params_t *swparams = NULL; 368 snd_pcm_sw_params_t *swparams = NULL;
380 snd_pcm_format_t format = 0; 369 snd_pcm_format_t format = 0;
381 snd_pcm_uframes_t frames = 0; 370 snd_pcm_uframes_t frames = 0;
382 SDL_AudioFormat test_format = 0; 371 SDL_AudioFormat test_format = 0;
372 unsigned int rate = 0;
373 unsigned int periods = 0;
374 unsigned int channels = 0;
383 375
384 /* Initialize all variables that we clean on shutdown */ 376 /* Initialize all variables that we clean on shutdown */
385 this->hidden = (struct SDL_PrivateAudioData *) 377 this->hidden = (struct SDL_PrivateAudioData *)
386 SDL_malloc((sizeof *this->hidden)); 378 SDL_malloc((sizeof *this->hidden));
387 if (this->hidden == NULL) { 379 if (this->hidden == NULL) {
481 this->spec.format = test_format; 473 this->spec.format = test_format;
482 474
483 /* Set the number of channels */ 475 /* Set the number of channels */
484 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 476 status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
485 this->spec.channels); 477 this->spec.channels);
486 if (status < 0) { 478 channels = this->spec.channels;
487 status = ALSA_snd_pcm_hw_params_get_channels(hwparams); 479 if (status < 0) {
488 if ((status <= 0) || (status > 2)) { 480 status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
481 if (status < 0) {
489 ALSA_CloseDevice(this); 482 ALSA_CloseDevice(this);
490 SDL_SetError("ALSA: Couldn't set audio channels"); 483 SDL_SetError("ALSA: Couldn't set audio channels");
491 return 0; 484 return 0;
492 } 485 }
493 this->spec.channels = status; 486 this->spec.channels = channels;
494 } 487 }
495 488
496 /* Set the audio rate */ 489 /* Set the audio rate */
490 rate = this->spec.freq;
497 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, 491 status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
498 this->spec.freq, NULL); 492 &rate, NULL);
499 if (status < 0) { 493 if (status < 0) {
500 ALSA_CloseDevice(this); 494 ALSA_CloseDevice(this);
501 SDL_SetError("ALSA: Couldn't set audio frequency: %s", 495 SDL_SetError("ALSA: Couldn't set audio frequency: %s",
502 ALSA_snd_strerror(status)); 496 ALSA_snd_strerror(status));
503 return 0; 497 return 0;
504 } 498 }
505 this->spec.freq = status; 499 this->spec.freq = rate;
506 500
507 /* Set the buffer size, in samples */ 501 /* Set the buffer size, in samples */
508 frames = this->spec.samples; 502 frames = this->spec.samples;
509 frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, 503 status = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
510 frames, NULL); 504 &frames, NULL);
505 if ( status < 0 ) {
506 ALSA_CloseDevice(this);
507 SDL_SetError("ALSA: Couldn't set audio frequency: %s",
508 ALSA_snd_strerror(status));
509 return(-1);
510 }
511 this->spec.samples = frames; 511 this->spec.samples = frames;
512 ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL); 512
513 periods = 2;
514 ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams,
515 &periods, NULL);
513 516
514 /* "set" the hardware with the desired parameters */ 517 /* "set" the hardware with the desired parameters */
515 status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams); 518 status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams);
516 if (status < 0) { 519 if (status < 0) {
517 ALSA_CloseDevice(this); 520 ALSA_CloseDevice(this);