Mercurial > sdl-ios-xcode
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: */ |