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