comparison src/audio/alsa/SDL_alsa_audio.c @ 1662:782fd950bd46 SDL-1.3

Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API. WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid. The code is now run through a consistent indent format: indent -i4 -nut -nsc -br -ce The headers are being converted to automatically generate doxygen documentation.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:04:16 +0000
parents 63fa37538842
children 11775724e3fe
comparison
equal deleted inserted replaced
1661:281d3f4870e5 1662:782fd950bd46
22 #include "SDL_config.h" 22 #include "SDL_config.h"
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 28
29 #include "SDL_timer.h" 29 #include "SDL_timer.h"
30 #include "SDL_audio.h" 30 #include "SDL_audio.h"
31 #include "../SDL_audiomem.h" 31 #include "../SDL_audiomem.h"
32 #include "../SDL_audio_c.h" 32 #include "../SDL_audio_c.h"
46 46
47 /* The default ALSA audio driver */ 47 /* The default ALSA audio driver */
48 #define DEFAULT_DEVICE "default" 48 #define DEFAULT_DEVICE "default"
49 49
50 /* Audio driver functions */ 50 /* Audio driver functions */
51 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec); 51 static int ALSA_OpenAudio (_THIS, SDL_AudioSpec * spec);
52 static void ALSA_WaitAudio(_THIS); 52 static void ALSA_WaitAudio (_THIS);
53 static void ALSA_PlayAudio(_THIS); 53 static void ALSA_PlayAudio (_THIS);
54 static Uint8 *ALSA_GetAudioBuf(_THIS); 54 static Uint8 *ALSA_GetAudioBuf (_THIS);
55 static void ALSA_CloseAudio(_THIS); 55 static void ALSA_CloseAudio (_THIS);
56 56
57 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC 57 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
58 58
59 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC; 59 static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
60 static void *alsa_handle = NULL; 60 static void *alsa_handle = NULL;
61 static int alsa_loaded = 0; 61 static int alsa_loaded = 0;
62 62
63 static int (*SDL_snd_pcm_open)(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); 63 static int (*SDL_snd_pcm_open) (snd_pcm_t ** pcm, const char *name,
64 static int (*SDL_NAME(snd_pcm_open))(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); 64 snd_pcm_stream_t stream, int mode);
65 static int (*SDL_NAME(snd_pcm_close))(snd_pcm_t *pcm); 65 static int (*SDL_NAME (snd_pcm_open)) (snd_pcm_t ** pcm, const char *name,
66 static snd_pcm_sframes_t (*SDL_NAME(snd_pcm_writei))(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); 66 snd_pcm_stream_t stream, int mode);
67 static int (*SDL_NAME(snd_pcm_resume))(snd_pcm_t *pcm); 67 static int (*SDL_NAME (snd_pcm_close)) (snd_pcm_t * pcm);
68 static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm); 68 static snd_pcm_sframes_t (*SDL_NAME (snd_pcm_writei)) (snd_pcm_t * pcm,
69 static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm); 69 const void *buffer,
70 static const char *(*SDL_NAME(snd_strerror))(int errnum); 70 snd_pcm_uframes_t
71 static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void); 71 size);
72 static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void); 72 static int (*SDL_NAME (snd_pcm_resume)) (snd_pcm_t * pcm);
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_prepare)) (snd_pcm_t * pcm);
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_drain)) (snd_pcm_t * pcm);
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 const char *(*SDL_NAME (snd_strerror)) (int errnum);
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 size_t (*SDL_NAME (snd_pcm_hw_params_sizeof)) (void);
77 static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params); 77 static size_t (*SDL_NAME (snd_pcm_sw_params_sizeof)) (void);
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 int (*SDL_NAME (snd_pcm_hw_params_any)) (snd_pcm_t * pcm,
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 snd_pcm_hw_params_t * params);
80 static snd_pcm_sframes_t (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params); 80 static int (*SDL_NAME (snd_pcm_hw_params_set_access)) (snd_pcm_t * pcm,
81 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); 81 snd_pcm_hw_params_t *
82 static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(snd_pcm_hw_params_t *params); 82 params,
83 static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); 83 snd_pcm_access_t
84 access);
85 static int (*SDL_NAME (snd_pcm_hw_params_set_format)) (snd_pcm_t * pcm,
86 snd_pcm_hw_params_t *
87 params,
88 snd_pcm_format_t val);
89 static int (*SDL_NAME (snd_pcm_hw_params_set_channels)) (snd_pcm_t * pcm,
90 snd_pcm_hw_params_t *
91 params,
92 unsigned int val);
93 static int (*SDL_NAME (snd_pcm_hw_params_get_channels)) (const
94 snd_pcm_hw_params_t *
95 params);
96 static unsigned int (*SDL_NAME (snd_pcm_hw_params_set_rate_near)) (snd_pcm_t *
97 pcm,
98 snd_pcm_hw_params_t
99 * params,
100 unsigned
101 int val,
102 int *dir);
103 static snd_pcm_uframes_t (*SDL_NAME (snd_pcm_hw_params_set_period_size_near))
104
105
106
107
108
109
110
111 (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, snd_pcm_uframes_t val,
112 int *dir);
113 static
114 snd_pcm_sframes_t (*SDL_NAME (snd_pcm_hw_params_get_period_size)) (const
115 snd_pcm_hw_params_t
116 * params);
117 static unsigned
118 int (*SDL_NAME (snd_pcm_hw_params_set_periods_near)) (snd_pcm_t * pcm,
119 snd_pcm_hw_params_t
120 * params,
121 unsigned int val,
122 int *dir);
123 static int (*SDL_NAME (snd_pcm_hw_params_get_periods)) (snd_pcm_hw_params_t *
124 params);
125 static int (*SDL_NAME (snd_pcm_hw_params)) (snd_pcm_t * pcm,
126 snd_pcm_hw_params_t * params);
84 /* 127 /*
85 */ 128 */
86 static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams); 129 static int (*SDL_NAME (snd_pcm_sw_params_current)) (snd_pcm_t * pcm,
87 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); 130 snd_pcm_sw_params_t *
88 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); 131 swparams);
89 static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); 132 static int (*SDL_NAME (snd_pcm_sw_params_set_start_threshold)) (snd_pcm_t *
90 static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock); 133 pcm,
134 snd_pcm_sw_params_t
135 * params,
136 snd_pcm_uframes_t
137 val);
138 static int (*SDL_NAME (snd_pcm_sw_params_set_avail_min)) (snd_pcm_t * pcm,
139 snd_pcm_sw_params_t
140 * params,
141 snd_pcm_uframes_t
142 val);
143 static int (*SDL_NAME (snd_pcm_sw_params)) (snd_pcm_t * pcm,
144 snd_pcm_sw_params_t * params);
145 static int (*SDL_NAME (snd_pcm_nonblock)) (snd_pcm_t * pcm, int nonblock);
91 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof) 146 #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) 147 #define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
93 148
94 /* cast funcs to char* first, to please GCC's strict aliasing rules. */ 149 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
95 static struct { 150 static struct
96 const char *name; 151 {
97 void **func; 152 const char *name;
153 void **func;
98 } alsa_functions[] = { 154 } alsa_functions[] = {
99 { "snd_pcm_open", (void**)(char*)&SDL_NAME(snd_pcm_open) }, 155 {
100 { "snd_pcm_close", (void**)(char*)&SDL_NAME(snd_pcm_close) }, 156 "snd_pcm_open", (void **) (char *) &SDL_NAME (snd_pcm_open)}, {
101 { "snd_pcm_writei", (void**)(char*)&SDL_NAME(snd_pcm_writei) }, 157 "snd_pcm_close", (void **) (char *) &SDL_NAME (snd_pcm_close)}, {
102 { "snd_pcm_resume", (void**)(char*)&SDL_NAME(snd_pcm_resume) }, 158 "snd_pcm_writei", (void **) (char *) &SDL_NAME (snd_pcm_writei)}, {
103 { "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) }, 159 "snd_pcm_resume", (void **) (char *) &SDL_NAME (snd_pcm_resume)}, {
104 { "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) }, 160 "snd_pcm_prepare", (void **) (char *) &SDL_NAME (snd_pcm_prepare)}, {
105 { "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) }, 161 "snd_pcm_drain", (void **) (char *) &SDL_NAME (snd_pcm_drain)}, {
106 { "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) }, 162 "snd_strerror", (void **) (char *) &SDL_NAME (snd_strerror)}, {
107 { "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) }, 163 "snd_pcm_hw_params_sizeof",
108 { "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) }, 164 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_sizeof)}, {
109 { "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) }, 165 "snd_pcm_sw_params_sizeof",
110 { "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) }, 166 (void **) (char *) &SDL_NAME (snd_pcm_sw_params_sizeof)}, {
111 { "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) }, 167 "snd_pcm_hw_params_any",
112 { "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) }, 168 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_any)}, {
113 { "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) }, 169 "snd_pcm_hw_params_set_access",
114 { "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) }, 170 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_set_access)}, {
115 { "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) }, 171 "snd_pcm_hw_params_set_format",
116 { "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) }, 172 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_set_format)}, {
117 { "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) }, 173 "snd_pcm_hw_params_set_channels",
118 { "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) }, 174 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_set_channels)}, {
119 { "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) }, 175 "snd_pcm_hw_params_get_channels",
120 { "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) }, 176 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_get_channels)}, {
121 { "snd_pcm_sw_params_set_avail_min", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_avail_min) }, 177 "snd_pcm_hw_params_set_rate_near",
122 { "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) }, 178 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_set_rate_near)}, {
123 { "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) }, 179 "snd_pcm_hw_params_set_period_size_near", (void **) (char *)
124 }; 180 &SDL_NAME (snd_pcm_hw_params_set_period_size_near)}, {
125 181 "snd_pcm_hw_params_get_period_size",
126 static void UnloadALSALibrary(void) { 182 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_get_period_size)},
127 if (alsa_loaded) { 183 {
184 "snd_pcm_hw_params_set_periods_near", (void **) (char *)
185 &SDL_NAME (snd_pcm_hw_params_set_periods_near)}, {
186 "snd_pcm_hw_params_get_periods",
187 (void **) (char *) &SDL_NAME (snd_pcm_hw_params_get_periods)}, {
188 "snd_pcm_hw_params", (void **) (char *) &SDL_NAME (snd_pcm_hw_params)}, {
189 "snd_pcm_sw_params_current",
190 (void **) (char *) &SDL_NAME (snd_pcm_sw_params_current)}, {
191 "snd_pcm_sw_params_set_start_threshold", (void **) (char *)
192 &SDL_NAME (snd_pcm_sw_params_set_start_threshold)}, {
193 "snd_pcm_sw_params_set_avail_min",
194 (void **) (char *) &SDL_NAME (snd_pcm_sw_params_set_avail_min)}, {
195 "snd_pcm_sw_params", (void **) (char *) &SDL_NAME (snd_pcm_sw_params)}, {
196 "snd_pcm_nonblock", (void **) (char *) &SDL_NAME (snd_pcm_nonblock)},};
197
198 static void
199 UnloadALSALibrary (void)
200 {
201 if (alsa_loaded) {
128 /* SDL_UnloadObject(alsa_handle);*/ 202 /* SDL_UnloadObject(alsa_handle);*/
129 dlclose(alsa_handle); 203 dlclose (alsa_handle);
130 alsa_handle = NULL; 204 alsa_handle = NULL;
131 alsa_loaded = 0; 205 alsa_loaded = 0;
132 } 206 }
133 } 207 }
134 208
135 static int LoadALSALibrary(void) { 209 static int
136 int i, retval = -1; 210 LoadALSALibrary (void)
211 {
212 int i, retval = -1;
137 213
138 /* alsa_handle = SDL_LoadObject(alsa_library);*/ 214 /* alsa_handle = SDL_LoadObject(alsa_library);*/
139 alsa_handle = dlopen(alsa_library,RTLD_NOW); 215 alsa_handle = dlopen (alsa_library, RTLD_NOW);
140 if (alsa_handle) { 216 if (alsa_handle) {
141 alsa_loaded = 1; 217 alsa_loaded = 1;
142 retval = 0; 218 retval = 0;
143 for (i = 0; i < SDL_arraysize(alsa_functions); i++) { 219 for (i = 0; i < SDL_arraysize (alsa_functions); i++) {
144 /* *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/ 220 /* *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);*/
145 #if HAVE_DLVSYM 221 #if HAVE_DLVSYM
146 *alsa_functions[i].func = dlvsym(alsa_handle,alsa_functions[i].name,"ALSA_0.9"); 222 *alsa_functions[i].func =
147 if (!*alsa_functions[i].func) 223 dlvsym (alsa_handle, alsa_functions[i].name, "ALSA_0.9");
224 if (!*alsa_functions[i].func)
148 #endif 225 #endif
149 *alsa_functions[i].func = dlsym(alsa_handle,alsa_functions[i].name); 226 *alsa_functions[i].func =
150 if (!*alsa_functions[i].func) { 227 dlsym (alsa_handle, alsa_functions[i].name);
151 retval = -1; 228 if (!*alsa_functions[i].func) {
152 UnloadALSALibrary(); 229 retval = -1;
153 break; 230 UnloadALSALibrary ();
154 } 231 break;
155 } 232 }
156 } 233 }
157 return retval; 234 }
235 return retval;
158 } 236 }
159 237
160 #else 238 #else
161 239
162 static void UnloadALSALibrary(void) { 240 static void
163 return; 241 UnloadALSALibrary (void)
164 } 242 {
165 243 return;
166 static int LoadALSALibrary(void) { 244 }
167 return 0; 245
246 static int
247 LoadALSALibrary (void)
248 {
249 return 0;
168 } 250 }
169 251
170 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */ 252 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
171 253
172 static const char *get_audio_device(int channels) 254 static const char *
173 { 255 get_audio_device (int channels)
174 const char *device; 256 {
175 257 const char *device;
176 device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */ 258
177 if ( device == NULL ) { 259 device = SDL_getenv ("AUDIODEV"); /* Is there a standard variable name? */
178 if (channels == 6) device = "surround51"; 260 if (device == NULL) {
179 else if (channels == 4) device = "surround40"; 261 if (channels == 6)
180 else device = DEFAULT_DEVICE; 262 device = "surround51";
181 } 263 else if (channels == 4)
182 return device; 264 device = "surround40";
265 else
266 device = DEFAULT_DEVICE;
267 }
268 return device;
183 } 269 }
184 270
185 /* Audio driver bootstrap functions */ 271 /* Audio driver bootstrap functions */
186 272
187 static int Audio_Available(void) 273 static int
188 { 274 Audio_Available (void)
189 int available; 275 {
190 int status; 276 int available;
191 snd_pcm_t *handle; 277 int status;
192 278 snd_pcm_t *handle;
193 available = 0; 279
194 if (LoadALSALibrary() < 0) { 280 available = 0;
195 return available; 281 if (LoadALSALibrary () < 0) {
196 } 282 return available;
197 status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 283 }
198 if ( status >= 0 ) { 284 status =
199 available = 1; 285 SDL_NAME (snd_pcm_open) (&handle, get_audio_device (2),
200 SDL_NAME(snd_pcm_close)(handle); 286 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
201 } 287 if (status >= 0) {
202 UnloadALSALibrary(); 288 available = 1;
203 return(available); 289 SDL_NAME (snd_pcm_close) (handle);
204 } 290 }
205 291 UnloadALSALibrary ();
206 static void Audio_DeleteDevice(SDL_AudioDevice *device) 292 return (available);
207 { 293 }
208 SDL_free(device->hidden); 294
209 SDL_free(device); 295 static void
210 UnloadALSALibrary(); 296 Audio_DeleteDevice (SDL_AudioDevice * device)
211 } 297 {
212 298 SDL_free (device->hidden);
213 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 299 SDL_free (device);
214 { 300 UnloadALSALibrary ();
215 SDL_AudioDevice *this; 301 }
216 302
217 /* Initialize all variables that we clean on shutdown */ 303 static SDL_AudioDevice *
218 LoadALSALibrary(); 304 Audio_CreateDevice (int devindex)
219 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 305 {
220 if ( this ) { 306 SDL_AudioDevice *this;
221 SDL_memset(this, 0, (sizeof *this)); 307
222 this->hidden = (struct SDL_PrivateAudioData *) 308 /* Initialize all variables that we clean on shutdown */
223 SDL_malloc((sizeof *this->hidden)); 309 LoadALSALibrary ();
224 } 310 this = (SDL_AudioDevice *) SDL_malloc (sizeof (SDL_AudioDevice));
225 if ( (this == NULL) || (this->hidden == NULL) ) { 311 if (this) {
226 SDL_OutOfMemory(); 312 SDL_memset (this, 0, (sizeof *this));
227 if ( this ) { 313 this->hidden = (struct SDL_PrivateAudioData *)
228 SDL_free(this); 314 SDL_malloc ((sizeof *this->hidden));
229 } 315 }
230 return(0); 316 if ((this == NULL) || (this->hidden == NULL)) {
231 } 317 SDL_OutOfMemory ();
232 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 318 if (this) {
233 319 SDL_free (this);
234 /* Set the function pointers */ 320 }
235 this->OpenAudio = ALSA_OpenAudio; 321 return (0);
236 this->WaitAudio = ALSA_WaitAudio; 322 }
237 this->PlayAudio = ALSA_PlayAudio; 323 SDL_memset (this->hidden, 0, (sizeof *this->hidden));
238 this->GetAudioBuf = ALSA_GetAudioBuf; 324
239 this->CloseAudio = ALSA_CloseAudio; 325 /* Set the function pointers */
240 326 this->OpenAudio = ALSA_OpenAudio;
241 this->free = Audio_DeleteDevice; 327 this->WaitAudio = ALSA_WaitAudio;
242 328 this->PlayAudio = ALSA_PlayAudio;
243 return this; 329 this->GetAudioBuf = ALSA_GetAudioBuf;
330 this->CloseAudio = ALSA_CloseAudio;
331
332 this->free = Audio_DeleteDevice;
333
334 return this;
244 } 335 }
245 336
246 AudioBootStrap ALSA_bootstrap = { 337 AudioBootStrap ALSA_bootstrap = {
247 DRIVER_NAME, "ALSA 0.9 PCM audio", 338 DRIVER_NAME, "ALSA 0.9 PCM audio",
248 Audio_Available, Audio_CreateDevice 339 Audio_Available, Audio_CreateDevice
249 }; 340 };
250 341
251 /* This function waits until it is possible to write a full sound buffer */ 342 /* This function waits until it is possible to write a full sound buffer */
252 static void ALSA_WaitAudio(_THIS) 343 static void
253 { 344 ALSA_WaitAudio (_THIS)
254 /* Check to see if the thread-parent process is still alive */ 345 {
255 { static int cnt = 0; 346 /* Check to see if the thread-parent process is still alive */
256 /* Note that this only works with thread implementations 347 {
257 that use a different process id for each thread. 348 static int cnt = 0;
258 */ 349 /* Note that this only works with thread implementations
259 if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */ 350 that use a different process id for each thread.
260 if ( kill(parent, 0) < 0 ) { 351 */
261 this->enabled = 0; 352 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
262 } 353 if (kill (parent, 0) < 0) {
263 } 354 this->enabled = 0;
264 } 355 }
265 } 356 }
266 357 }
267 static void ALSA_PlayAudio(_THIS) 358 }
268 { 359
269 int status; 360 static void
270 int sample_len; 361 ALSA_PlayAudio (_THIS)
271 signed short *sample_buf; 362 {
272 363 int status;
273 sample_len = this->spec.samples; 364 int sample_len;
274 sample_buf = (signed short *)mixbuf; 365 signed short *sample_buf;
275 while ( sample_len > 0 ) { 366
276 status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, sample_len); 367 sample_len = this->spec.samples;
277 if ( status < 0 ) { 368 sample_buf = (signed short *) mixbuf;
278 if ( status == -EAGAIN ) { 369 while (sample_len > 0) {
279 SDL_Delay(1); 370 status =
280 continue; 371 SDL_NAME (snd_pcm_writei) (pcm_handle, sample_buf, sample_len);
281 } 372 if (status < 0) {
282 if ( status == -ESTRPIPE ) { 373 if (status == -EAGAIN) {
283 do { 374 SDL_Delay (1);
284 SDL_Delay(1); 375 continue;
285 status = SDL_NAME(snd_pcm_resume)(pcm_handle); 376 }
286 } while ( status == -EAGAIN ); 377 if (status == -ESTRPIPE) {
287 } 378 do {
288 if ( status < 0 ) { 379 SDL_Delay (1);
289 status = SDL_NAME(snd_pcm_prepare)(pcm_handle); 380 status = SDL_NAME (snd_pcm_resume) (pcm_handle);
290 } 381 }
291 if ( status < 0 ) { 382 while (status == -EAGAIN);
292 /* Hmm, not much we can do - abort */ 383 }
293 this->enabled = 0; 384 if (status < 0) {
294 return; 385 status = SDL_NAME (snd_pcm_prepare) (pcm_handle);
295 } 386 }
296 continue; 387 if (status < 0) {
297 } 388 /* Hmm, not much we can do - abort */
298 sample_buf += status * this->spec.channels; 389 this->enabled = 0;
299 sample_len -= status; 390 return;
300 } 391 }
301 } 392 continue;
302 393 }
303 static Uint8 *ALSA_GetAudioBuf(_THIS) 394 sample_buf += status * this->spec.channels;
304 { 395 sample_len -= status;
305 return(mixbuf); 396 }
306 } 397 }
307 398
308 static void ALSA_CloseAudio(_THIS) 399 static Uint8 *
309 { 400 ALSA_GetAudioBuf (_THIS)
310 if ( mixbuf != NULL ) { 401 {
311 SDL_FreeAudioMem(mixbuf); 402 return (mixbuf);
312 mixbuf = NULL; 403 }
313 } 404
314 if ( pcm_handle ) { 405 static void
315 SDL_NAME(snd_pcm_drain)(pcm_handle); 406 ALSA_CloseAudio (_THIS)
316 SDL_NAME(snd_pcm_close)(pcm_handle); 407 {
317 pcm_handle = NULL; 408 if (mixbuf != NULL) {
318 } 409 SDL_FreeAudioMem (mixbuf);
319 } 410 mixbuf = NULL;
320 411 }
321 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec) 412 if (pcm_handle) {
322 { 413 SDL_NAME (snd_pcm_drain) (pcm_handle);
323 int status; 414 SDL_NAME (snd_pcm_close) (pcm_handle);
324 snd_pcm_hw_params_t *hwparams; 415 pcm_handle = NULL;
325 snd_pcm_sw_params_t *swparams; 416 }
326 snd_pcm_format_t format; 417 }
327 snd_pcm_uframes_t frames; 418
328 Uint16 test_format; 419 static int
329 420 ALSA_OpenAudio (_THIS, SDL_AudioSpec * spec)
330 /* Open the audio device */ 421 {
331 /* Name of device should depend on # channels in spec */ 422 int status;
332 status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 423 snd_pcm_hw_params_t *hwparams;
333 424 snd_pcm_sw_params_t *swparams;
334 if ( status < 0 ) { 425 snd_pcm_format_t format;
335 SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status)); 426 snd_pcm_uframes_t frames;
336 return(-1); 427 Uint16 test_format;
337 } 428
338 429 /* Open the audio device */
339 /* Figure out what the hardware is capable of */ 430 /* Name of device should depend on # channels in spec */
340 snd_pcm_hw_params_alloca(&hwparams); 431 status =
341 status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams); 432 SDL_NAME (snd_pcm_open) (&pcm_handle,
342 if ( status < 0 ) { 433 get_audio_device (spec->channels),
343 SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status)); 434 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
344 ALSA_CloseAudio(this); 435
345 return(-1); 436 if (status < 0) {
346 } 437 SDL_SetError ("Couldn't open audio device: %s",
347 438 SDL_NAME (snd_strerror) (status));
348 /* SDL only uses interleaved sample output */ 439 return (-1);
349 status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); 440 }
350 if ( status < 0 ) { 441
351 SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status)); 442 /* Figure out what the hardware is capable of */
352 ALSA_CloseAudio(this); 443 snd_pcm_hw_params_alloca (&hwparams);
353 return(-1); 444 status = SDL_NAME (snd_pcm_hw_params_any) (pcm_handle, hwparams);
354 } 445 if (status < 0) {
355 446 SDL_SetError ("Couldn't get hardware config: %s",
356 /* Try for a closest match on audio format */ 447 SDL_NAME (snd_strerror) (status));
357 status = -1; 448 ALSA_CloseAudio (this);
358 for ( test_format = SDL_FirstAudioFormat(spec->format); 449 return (-1);
359 test_format && (status < 0); ) { 450 }
360 switch ( test_format ) { 451
361 case AUDIO_U8: 452 /* SDL only uses interleaved sample output */
362 format = SND_PCM_FORMAT_U8; 453 status =
363 break; 454 SDL_NAME (snd_pcm_hw_params_set_access) (pcm_handle, hwparams,
364 case AUDIO_S8: 455 SND_PCM_ACCESS_RW_INTERLEAVED);
365 format = SND_PCM_FORMAT_S8; 456 if (status < 0) {
366 break; 457 SDL_SetError ("Couldn't set interleaved access: %s",
367 case AUDIO_S16LSB: 458 SDL_NAME (snd_strerror) (status));
368 format = SND_PCM_FORMAT_S16_LE; 459 ALSA_CloseAudio (this);
369 break; 460 return (-1);
370 case AUDIO_S16MSB: 461 }
371 format = SND_PCM_FORMAT_S16_BE; 462
372 break; 463 /* Try for a closest match on audio format */
373 case AUDIO_U16LSB: 464 status = -1;
374 format = SND_PCM_FORMAT_U16_LE; 465 for (test_format = SDL_FirstAudioFormat (spec->format);
375 break; 466 test_format && (status < 0);) {
376 case AUDIO_U16MSB: 467 switch (test_format) {
377 format = SND_PCM_FORMAT_U16_BE; 468 case AUDIO_U8:
378 break; 469 format = SND_PCM_FORMAT_U8;
379 default: 470 break;
380 format = 0; 471 case AUDIO_S8:
381 break; 472 format = SND_PCM_FORMAT_S8;
382 } 473 break;
383 if ( format != 0 ) { 474 case AUDIO_S16LSB:
384 status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format); 475 format = SND_PCM_FORMAT_S16_LE;
385 } 476 break;
386 if ( status < 0 ) { 477 case AUDIO_S16MSB:
387 test_format = SDL_NextAudioFormat(); 478 format = SND_PCM_FORMAT_S16_BE;
388 } 479 break;
389 } 480 case AUDIO_U16LSB:
390 if ( status < 0 ) { 481 format = SND_PCM_FORMAT_U16_LE;
391 SDL_SetError("Couldn't find any hardware audio formats"); 482 break;
392 ALSA_CloseAudio(this); 483 case AUDIO_U16MSB:
393 return(-1); 484 format = SND_PCM_FORMAT_U16_BE;
394 } 485 break;
395 spec->format = test_format; 486 default:
396 487 format = 0;
397 /* Set the number of channels */ 488 break;
398 status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels); 489 }
399 if ( status < 0 ) { 490 if (format != 0) {
400 status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams); 491 status =
401 if ( (status <= 0) || (status > 2) ) { 492 SDL_NAME (snd_pcm_hw_params_set_format) (pcm_handle,
402 SDL_SetError("Couldn't set audio channels"); 493 hwparams, format);
403 ALSA_CloseAudio(this); 494 }
404 return(-1); 495 if (status < 0) {
405 } 496 test_format = SDL_NextAudioFormat ();
406 spec->channels = status; 497 }
407 } 498 }
408 499 if (status < 0) {
409 /* Set the audio rate */ 500 SDL_SetError ("Couldn't find any hardware audio formats");
410 status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, spec->freq, NULL); 501 ALSA_CloseAudio (this);
411 if ( status < 0 ) { 502 return (-1);
412 SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status)); 503 }
413 ALSA_CloseAudio(this); 504 spec->format = test_format;
414 return(-1); 505
415 } 506 /* Set the number of channels */
416 spec->freq = status; 507 status =
417 508 SDL_NAME (snd_pcm_hw_params_set_channels) (pcm_handle, hwparams,
418 /* Set the buffer size, in samples */ 509 spec->channels);
419 frames = spec->samples; 510 if (status < 0) {
420 frames = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, frames, NULL); 511 status = SDL_NAME (snd_pcm_hw_params_get_channels) (hwparams);
421 spec->samples = frames; 512 if ((status <= 0) || (status > 2)) {
422 SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, 2, NULL); 513 SDL_SetError ("Couldn't set audio channels");
423 514 ALSA_CloseAudio (this);
424 /* "set" the hardware with the desired parameters */ 515 return (-1);
425 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams); 516 }
426 if ( status < 0 ) { 517 spec->channels = status;
427 SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status)); 518 }
428 ALSA_CloseAudio(this); 519
429 return(-1); 520 /* Set the audio rate */
430 } 521 status =
522 SDL_NAME (snd_pcm_hw_params_set_rate_near) (pcm_handle, hwparams,
523 spec->freq, NULL);
524 if (status < 0) {
525 SDL_SetError ("Couldn't set audio frequency: %s",
526 SDL_NAME (snd_strerror) (status));
527 ALSA_CloseAudio (this);
528 return (-1);
529 }
530 spec->freq = status;
531
532 /* Set the buffer size, in samples */
533 frames = spec->samples;
534 frames =
535 SDL_NAME (snd_pcm_hw_params_set_period_size_near) (pcm_handle,
536 hwparams, frames,
537 NULL);
538 spec->samples = frames;
539 SDL_NAME (snd_pcm_hw_params_set_periods_near) (pcm_handle, hwparams, 2,
540 NULL);
541
542 /* "set" the hardware with the desired parameters */
543 status = SDL_NAME (snd_pcm_hw_params) (pcm_handle, hwparams);
544 if (status < 0) {
545 SDL_SetError ("Couldn't set hardware audio parameters: %s",
546 SDL_NAME (snd_strerror) (status));
547 ALSA_CloseAudio (this);
548 return (-1);
549 }
431 550
432 /* This is useful for debugging... */ 551 /* This is useful for debugging... */
433 /* 552 /*
434 { snd_pcm_sframes_t bufsize; int fragments; 553 { snd_pcm_sframes_t bufsize; int fragments;
435 bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams); 554 bufsize = SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams);
437 556
438 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments); 557 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, fragments);
439 } 558 }
440 */ 559 */
441 560
442 /* Set the software parameters */ 561 /* Set the software parameters */
443 snd_pcm_sw_params_alloca(&swparams); 562 snd_pcm_sw_params_alloca (&swparams);
444 status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams); 563 status = SDL_NAME (snd_pcm_sw_params_current) (pcm_handle, swparams);
445 if ( status < 0 ) { 564 if (status < 0) {
446 SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status)); 565 SDL_SetError ("Couldn't get software config: %s",
447 ALSA_CloseAudio(this); 566 SDL_NAME (snd_strerror) (status));
448 return(-1); 567 ALSA_CloseAudio (this);
449 } 568 return (-1);
450 status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 0); 569 }
451 if ( status < 0 ) { 570 status =
452 SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status)); 571 SDL_NAME (snd_pcm_sw_params_set_start_threshold) (pcm_handle,
453 ALSA_CloseAudio(this); 572 swparams, 0);
454 return(-1); 573 if (status < 0) {
455 } 574 SDL_SetError ("Couldn't set start threshold: %s",
456 status = SDL_NAME(snd_pcm_sw_params_set_avail_min)(pcm_handle, swparams, frames); 575 SDL_NAME (snd_strerror) (status));
457 if ( status < 0 ) { 576 ALSA_CloseAudio (this);
458 SDL_SetError("Couldn't set avail min: %s", SDL_NAME(snd_strerror)(status)); 577 return (-1);
459 ALSA_CloseAudio(this); 578 }
460 return(-1); 579 status =
461 } 580 SDL_NAME (snd_pcm_sw_params_set_avail_min) (pcm_handle, swparams,
462 status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams); 581 frames);
463 if ( status < 0 ) { 582 if (status < 0) {
464 SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status)); 583 SDL_SetError ("Couldn't set avail min: %s",
465 ALSA_CloseAudio(this); 584 SDL_NAME (snd_strerror) (status));
466 return(-1); 585 ALSA_CloseAudio (this);
467 } 586 return (-1);
468 587 }
469 /* Calculate the final parameters for this audio specification */ 588 status = SDL_NAME (snd_pcm_sw_params) (pcm_handle, swparams);
470 SDL_CalculateAudioSpec(spec); 589 if (status < 0) {
471 590 SDL_SetError ("Couldn't set software audio parameters: %s",
472 /* Allocate mixing buffer */ 591 SDL_NAME (snd_strerror) (status));
473 mixlen = spec->size; 592 ALSA_CloseAudio (this);
474 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); 593 return (-1);
475 if ( mixbuf == NULL ) { 594 }
476 ALSA_CloseAudio(this); 595
477 return(-1); 596 /* Calculate the final parameters for this audio specification */
478 } 597 SDL_CalculateAudioSpec (spec);
479 SDL_memset(mixbuf, spec->silence, spec->size); 598
480 599 /* Allocate mixing buffer */
481 /* Get the parent process id (we're the parent of the audio thread) */ 600 mixlen = spec->size;
482 parent = getpid(); 601 mixbuf = (Uint8 *) SDL_AllocAudioMem (mixlen);
483 602 if (mixbuf == NULL) {
484 /* Switch to blocking mode for playback */ 603 ALSA_CloseAudio (this);
485 SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0); 604 return (-1);
486 605 }
487 /* We're ready to rock and roll. :-) */ 606 SDL_memset (mixbuf, spec->silence, spec->size);
488 return(0); 607
489 } 608 /* Get the parent process id (we're the parent of the audio thread) */
609 parent = getpid ();
610
611 /* Switch to blocking mode for playback */
612 SDL_NAME (snd_pcm_nonblock) (pcm_handle, 0);
613
614 /* We're ready to rock and roll. :-) */
615 return (0);
616 }
617
618 /* vi: set ts=4 sw=4 expandtab: */