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: */