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