Mercurial > sdl-ios-xcode
comparison src/audio/esd/SDL_esdaudio.c @ 3815:3234d6eee011 SDL-ryan-multiple-audio-device
Updated esd audio driver for 1.3 API.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 06 Oct 2006 04:16:11 +0000 |
parents | 7852b5b78af5 |
children | 9d070c1a45fa |
comparison
equal
deleted
inserted
replaced
3814:8e1af9ff0e1f | 3815:3234d6eee011 |
---|---|
44 | 44 |
45 /* The tag name used by ESD audio */ | 45 /* The tag name used by ESD audio */ |
46 #define ESD_DRIVER_NAME "esd" | 46 #define ESD_DRIVER_NAME "esd" |
47 | 47 |
48 /* Audio driver functions */ | 48 /* Audio driver functions */ |
49 static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec); | 49 static int ESD_OpenDevice(_THIS, const char *devname, int iscapture); |
50 static void ESD_WaitAudio(_THIS); | 50 static void ESD_WaitDevice(_THIS); |
51 static void ESD_PlayAudio(_THIS); | 51 static void ESD_PlayDevice(_THIS); |
52 static Uint8 *ESD_GetAudioBuf(_THIS); | 52 static Uint8 *ESD_GetDeviceBuf(_THIS); |
53 static void ESD_CloseAudio(_THIS); | 53 static void ESD_CloseDevice(_THIS); |
54 | 54 |
55 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC | 55 #ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC |
56 | 56 |
57 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC; | 57 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC; |
58 static void *esd_handle = NULL; | 58 static void *esd_handle = NULL; |
59 static int esd_loaded = 0; | |
60 | 59 |
61 static int (*SDL_NAME(esd_open_sound)) (const char *host); | 60 static int (*SDL_NAME(esd_open_sound)) (const char *host); |
62 static int (*SDL_NAME(esd_close)) (int esd); | 61 static int (*SDL_NAME(esd_close)) (int esd); |
63 static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate, | 62 static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate, |
64 const char *host, const char *name); | 63 const char *host, const char *name); |
64 | |
65 #define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) } | |
65 static struct | 66 static struct |
66 { | 67 { |
67 const char *name; | 68 const char *name; |
68 void **func; | 69 void **func; |
69 } esd_functions[] = { | 70 } esd_functions[] = { |
70 { | 71 SDL_ESD_SYM(esd_open_sound), |
71 "esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, { | 72 SDL_ESD_SYM(esd_close), |
72 "esd_close", (void **) &SDL_NAME(esd_close)}, { | 73 SDL_ESD_SYM(esd_play_stream), |
73 "esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},}; | 74 }; |
75 #undef SDL_ESD_SYM | |
74 | 76 |
75 static void | 77 static void |
76 UnloadESDLibrary() | 78 UnloadESDLibrary() |
77 { | 79 { |
78 if (esd_loaded) { | 80 if (esd_handle != NULL) { |
79 SDL_UnloadObject(esd_handle); | 81 SDL_UnloadObject(esd_handle); |
80 esd_handle = NULL; | 82 esd_handle = NULL; |
81 esd_loaded = 0; | |
82 } | 83 } |
83 } | 84 } |
84 | 85 |
85 static int | 86 static int |
86 LoadESDLibrary(void) | 87 LoadESDLibrary(void) |
87 { | 88 { |
88 int i, retval = -1; | 89 int i, retval = -1; |
89 | 90 |
90 esd_handle = SDL_LoadObject(esd_library); | 91 if (esd_handle == NULL) { |
91 if (esd_handle) { | 92 esd_handle = SDL_LoadObject(esd_library); |
92 esd_loaded = 1; | 93 if (esd_handle) { |
93 retval = 0; | 94 retval = 0; |
94 for (i = 0; i < SDL_arraysize(esd_functions); ++i) { | 95 for (i = 0; i < SDL_arraysize(esd_functions); ++i) { |
95 *esd_functions[i].func = | 96 *esd_functions[i].func = |
96 SDL_LoadFunction(esd_handle, esd_functions[i].name); | 97 SDL_LoadFunction(esd_handle, esd_functions[i].name); |
97 if (!*esd_functions[i].func) { | 98 if (!*esd_functions[i].func) { |
98 retval = -1; | 99 retval = -1; |
99 UnloadESDLibrary(); | 100 UnloadESDLibrary(); |
100 break; | 101 break; |
102 } | |
101 } | 103 } |
102 } | 104 } |
103 } | 105 } |
104 return retval; | 106 return retval; |
105 } | 107 } |
121 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */ | 123 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */ |
122 | 124 |
123 /* Audio driver bootstrap functions */ | 125 /* Audio driver bootstrap functions */ |
124 | 126 |
125 static int | 127 static int |
126 Audio_Available(void) | 128 ESD_Available(void) |
127 { | 129 { |
128 const char *esd_no_spawn = SDL_getenv("ESD_NO_SPAWN"); | |
129 int connection = 0; | |
130 int available = 0; | 130 int available = 0; |
131 | 131 if (LoadESDLibrary() == 0) { |
132 if (esd_no_spawn == NULL) { | 132 int connection; |
133 SDL_putenv("ESD_NO_SPAWN=1"); /* Don't start ESD if it's not running */ | 133 if (SDL_getenv("ESD_NO_SPAWN") == NULL) { |
134 } | 134 SDL_putenv("ESD_NO_SPAWN=1"); /* Don't start ESD if it's not running */ |
135 | 135 } |
136 if (LoadESDLibrary() < 0) { | 136 connection = SDL_NAME(esd_open_sound) (NULL); |
137 return available; | 137 if (connection >= 0) { |
138 } | 138 available = 1; |
139 connection = SDL_NAME(esd_open_sound) (NULL); | 139 SDL_NAME(esd_close) (connection); |
140 if (connection >= 0) { | 140 } |
141 available = 1; | 141 UnloadESDLibrary(); |
142 SDL_NAME(esd_close) (connection); | 142 } |
143 } | |
144 UnloadESDLibrary(); | |
145 return available; | 143 return available; |
146 } | 144 } |
147 | 145 |
148 static void | 146 |
149 Audio_DeleteDevice(SDL_AudioDevice * device) | 147 static int |
150 { | 148 ESD_Init(SDL_AudioDriverImpl *impl) |
151 SDL_free(device->hidden); | 149 { |
152 SDL_free(device); | |
153 UnloadESDLibrary(); | |
154 } | |
155 | |
156 static SDL_AudioDevice * | |
157 Audio_CreateDevice(int devindex) | |
158 { | |
159 SDL_AudioDevice *this; | |
160 | |
161 /* Initialize all variables that we clean on shutdown */ | |
162 LoadESDLibrary(); | |
163 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | |
164 if (this) { | |
165 SDL_memset(this, 0, (sizeof *this)); | |
166 this->hidden = (struct SDL_PrivateAudioData *) | |
167 SDL_malloc((sizeof *this->hidden)); | |
168 } | |
169 if ((this == NULL) || (this->hidden == NULL)) { | |
170 SDL_OutOfMemory(); | |
171 if (this) { | |
172 SDL_free(this); | |
173 } | |
174 return (0); | |
175 } | |
176 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
177 audio_fd = -1; | |
178 | |
179 /* Set the function pointers */ | 150 /* Set the function pointers */ |
180 this->OpenAudio = ESD_OpenAudio; | 151 impl->OpenDevice = ESD_OpenDevice; |
181 this->WaitAudio = ESD_WaitAudio; | 152 impl->PlayDevice = ESD_PlayDevice; |
182 this->PlayAudio = ESD_PlayAudio; | 153 impl->WaitDevice = ESD_WaitDevice; |
183 this->GetAudioBuf = ESD_GetAudioBuf; | 154 impl->GetDeviceBuf = ESD_GetDeviceBuf; |
184 this->CloseAudio = ESD_CloseAudio; | 155 impl->CloseDevice = ESD_CloseDevice; |
185 | 156 impl->OnlyHasDefaultOutputDevice = 1; |
186 this->free = Audio_DeleteDevice; | 157 |
187 | 158 return 1; |
188 return this; | 159 } |
189 } | 160 |
190 | 161 |
191 AudioBootStrap ESD_bootstrap = { | 162 AudioBootStrap ESD_bootstrap = { |
192 ESD_DRIVER_NAME, "Enlightened Sound Daemon", | 163 ESD_DRIVER_NAME, "Enlightened Sound Daemon", |
193 Audio_Available, Audio_CreateDevice, 0 | 164 ESD_Available, ESD_Init, 0 |
194 }; | 165 }; |
195 | 166 |
196 /* This function waits until it is possible to write a full sound buffer */ | 167 /* This function waits until it is possible to write a full sound buffer */ |
197 static void | 168 static void |
198 ESD_WaitAudio(_THIS) | 169 ESD_WaitDevice(_THIS) |
199 { | 170 { |
200 Sint32 ticks; | 171 Sint32 ticks; |
201 | 172 |
202 /* Check to see if the thread-parent process is still alive */ | 173 /* Check to see if the thread-parent process is still alive */ |
203 { | 174 { |
204 static int cnt = 0; | 175 static int cnt = 0; |
205 /* Note that this only works with thread implementations | 176 /* Note that this only works with thread implementations |
206 that use a different process id for each thread. | 177 that use a different process id for each thread. |
207 */ | 178 */ |
208 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ | 179 /* Check every 10 loops */ |
209 if (kill(parent, 0) < 0) { | 180 if (this->hidden->parent && (((++cnt) % 10) == 0)) { |
181 if (kill(this->hidden->parent, 0) < 0) { | |
210 this->enabled = 0; | 182 this->enabled = 0; |
211 } | 183 } |
212 } | 184 } |
213 } | 185 } |
214 | 186 |
215 /* Use timer for general audio synchronization */ | 187 /* Use timer for general audio synchronization */ |
216 ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; | 188 ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS; |
217 if (ticks > 0) { | 189 if (ticks > 0) { |
218 SDL_Delay(ticks); | 190 SDL_Delay(ticks); |
219 } | 191 } |
220 } | 192 } |
221 | 193 |
222 static void | 194 static void |
223 ESD_PlayAudio(_THIS) | 195 ESD_PlayDevice(_THIS) |
224 { | 196 { |
225 int written; | 197 int written = 0; |
226 | 198 |
227 /* Write the audio data, checking for EAGAIN on broken audio drivers */ | 199 /* Write the audio data, checking for EAGAIN on broken audio drivers */ |
228 do { | 200 do { |
229 written = write(audio_fd, mixbuf, mixlen); | 201 written = write(this->hidden->audio_fd, |
202 this->hidden->mixbuf, | |
203 this->hidden->mixlen); | |
230 if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) { | 204 if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) { |
231 SDL_Delay(1); /* Let a little CPU time go by */ | 205 SDL_Delay(1); /* Let a little CPU time go by */ |
232 } | 206 } |
233 } | 207 } |
234 while ((written < 0) && | 208 while ((written < 0) && |
235 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); | 209 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); |
236 | 210 |
237 /* Set the next write frame */ | 211 /* Set the next write frame */ |
238 next_frame += frame_ticks; | 212 this->hidden->next_frame += this->hidden->frame_ticks; |
239 | 213 |
240 /* If we couldn't write, assume fatal error for now */ | 214 /* If we couldn't write, assume fatal error for now */ |
241 if (written < 0) { | 215 if (written < 0) { |
242 this->enabled = 0; | 216 this->enabled = 0; |
243 } | 217 } |
244 } | 218 } |
245 | 219 |
246 static Uint8 * | 220 static Uint8 * |
247 ESD_GetAudioBuf(_THIS) | 221 ESD_GetDeviceBuf(_THIS) |
248 { | 222 { |
249 return (mixbuf); | 223 return (this->hidden->mixbuf); |
250 } | 224 } |
251 | 225 |
252 static void | 226 static void |
253 ESD_CloseAudio(_THIS) | 227 ESD_CloseDevice(_THIS) |
254 { | 228 { |
255 if (mixbuf != NULL) { | 229 if (this->hidden != NULL) { |
256 SDL_FreeAudioMem(mixbuf); | 230 if (this->hidden->mixbuf != NULL) { |
257 mixbuf = NULL; | 231 SDL_FreeAudioMem(this->hidden->mixbuf); |
258 } | 232 this->hidden->mixbuf = NULL; |
259 if (audio_fd >= 0) { | 233 } |
260 SDL_NAME(esd_close) (audio_fd); | 234 if (this->hidden->audio_fd >= 0) { |
261 audio_fd = -1; | 235 SDL_NAME(esd_close) (this->hidden->audio_fd); |
262 } | 236 this->hidden->audio_fd = -1; |
237 } | |
238 | |
239 SDL_free(this->hidden); | |
240 this->hidden = NULL; | |
241 } | |
242 UnloadESDLibrary(); | |
263 } | 243 } |
264 | 244 |
265 /* Try to get the name of the program */ | 245 /* Try to get the name of the program */ |
266 static char * | 246 static char * |
267 get_progname(void) | 247 get_progname(void) |
286 } | 266 } |
287 #endif | 267 #endif |
288 return (progname); | 268 return (progname); |
289 } | 269 } |
290 | 270 |
291 static int | 271 |
292 ESD_OpenAudio(_THIS, SDL_AudioSpec * spec) | 272 static int |
293 { | 273 ESD_OpenDevice(_THIS, const char *devname, int iscapture) |
294 esd_format_t format; | 274 { |
275 esd_format_t format = (ESD_STREAM | ESD_PLAY); | |
276 SDL_AudioFormat test_format = 0; | |
277 int found = 0; | |
278 | |
279 /* Initialize all variables that we clean on shutdown */ | |
280 this->hidden = (struct SDL_PrivateAudioData *) | |
281 SDL_malloc((sizeof *this->hidden)); | |
282 if (this->hidden == NULL) { | |
283 SDL_OutOfMemory(); | |
284 return 0; | |
285 } | |
286 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
287 this->hidden->audio_fd = -1; | |
288 | |
289 if (LoadESDLibrary() < 0) { | |
290 ESD_CloseDevice(this); | |
291 SDL_SetError("ESD: failed to load library: %s", SDL_GetError()); | |
292 return 0; | |
293 } | |
295 | 294 |
296 /* Convert audio spec to the ESD audio format */ | 295 /* Convert audio spec to the ESD audio format */ |
297 format = (ESD_STREAM | ESD_PLAY); | 296 /* Try for a closest match on audio format */ |
298 switch (spec->format & 0xFF) { | 297 for (test_format = SDL_FirstAudioFormat(this->spec.format); |
299 case 8: | 298 !found && test_format; test_format = SDL_NextAudioFormat()) { |
300 format |= ESD_BITS8; | 299 #ifdef DEBUG_AUDIO |
301 break; | 300 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); |
302 case 16: | 301 #endif |
303 format |= ESD_BITS16; | 302 found = 1; |
304 break; | 303 switch (test_format) { |
305 default: | 304 case AUDIO_U8: |
306 SDL_SetError("Unsupported ESD audio format"); | 305 format |= ESD_BITS8; |
307 return (-1); | 306 break; |
308 } | 307 case AUDIO_S16SYS: |
309 if (spec->channels == 1) { | 308 format |= ESD_BITS16; |
309 break; | |
310 default: | |
311 found = 0; | |
312 break; | |
313 } | |
314 } | |
315 | |
316 if (!found) { | |
317 ESD_CloseDevice(this); | |
318 SDL_SetError("Couldn't find any hardware audio formats"); | |
319 return 0; | |
320 } | |
321 | |
322 if (this->spec.channels == 1) { | |
310 format |= ESD_MONO; | 323 format |= ESD_MONO; |
311 } else { | 324 } else { |
312 format |= ESD_STEREO; | 325 format |= ESD_STEREO; |
313 } | 326 } |
314 #if 0 | 327 #if 0 |
315 spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */ | 328 this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */ |
316 #endif | 329 #endif |
317 | 330 |
318 /* Open a connection to the ESD audio server */ | 331 /* Open a connection to the ESD audio server */ |
319 audio_fd = | 332 this->hidden->audio_fd = |
320 SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname()); | 333 SDL_NAME(esd_play_stream)(format,this->spec.freq,NULL,get_progname()); |
321 if (audio_fd < 0) { | 334 |
335 if (this->hidden->audio_fd < 0) { | |
336 ESD_CloseDevice(this); | |
322 SDL_SetError("Couldn't open ESD connection"); | 337 SDL_SetError("Couldn't open ESD connection"); |
323 return (-1); | 338 return 0; |
324 } | 339 } |
325 | 340 |
326 /* Calculate the final parameters for this audio specification */ | 341 /* Calculate the final parameters for this audio specification */ |
327 SDL_CalculateAudioSpec(spec); | 342 SDL_CalculateAudioSpec(&this->spec); |
328 frame_ticks = (float) (spec->samples * 1000) / spec->freq; | 343 this->hidden->frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq; |
329 next_frame = SDL_GetTicks() + frame_ticks; | 344 this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks; |
330 | 345 |
331 /* Allocate mixing buffer */ | 346 /* Allocate mixing buffer */ |
332 mixlen = spec->size; | 347 this->hidden->mixlen = this->spec.size; |
333 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); | 348 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); |
334 if (mixbuf == NULL) { | 349 if (this->hidden->mixbuf == NULL) { |
335 return (-1); | 350 ESD_CloseDevice(this); |
336 } | 351 SDL_OutOfMemory(); |
337 SDL_memset(mixbuf, spec->silence, spec->size); | 352 return 0; |
353 } | |
354 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | |
338 | 355 |
339 /* Get the parent process id (we're the parent of the audio thread) */ | 356 /* Get the parent process id (we're the parent of the audio thread) */ |
340 parent = getpid(); | 357 this->hidden->parent = getpid(); |
341 | 358 |
342 /* We're ready to rock and roll. :-) */ | 359 /* We're ready to rock and roll. :-) */ |
343 return (0); | 360 return 1; |
344 } | 361 } |
345 | 362 |
346 /* vi: set ts=4 sw=4 expandtab: */ | 363 /* vi: set ts=4 sw=4 expandtab: */ |