comparison src/audio/esd/SDL_esdaudio.c @ 1895:c121d94672cb

SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 10 Jul 2006 21:04:37 +0000
parents 9f836cec0521
children 5f6550e5184f c8b3d3d13ed1
comparison
equal deleted inserted replaced
1894:c69cee13dd76 1895:c121d94672cb
45 45
46 /* The tag name used by ESD audio */ 46 /* The tag name used by ESD audio */
47 #define ESD_DRIVER_NAME "esd" 47 #define ESD_DRIVER_NAME "esd"
48 48
49 /* Audio driver functions */ 49 /* Audio driver functions */
50 static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec); 50 static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec);
51 static void ESD_WaitAudio(_THIS); 51 static void ESD_WaitAudio(_THIS);
52 static void ESD_PlayAudio(_THIS); 52 static void ESD_PlayAudio(_THIS);
53 static Uint8 *ESD_GetAudioBuf(_THIS); 53 static Uint8 *ESD_GetAudioBuf(_THIS);
54 static void ESD_CloseAudio(_THIS); 54 static void ESD_CloseAudio(_THIS);
55 55
57 57
58 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC; 58 static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
59 static void *esd_handle = NULL; 59 static void *esd_handle = NULL;
60 static int esd_loaded = 0; 60 static int esd_loaded = 0;
61 61
62 static int (*SDL_NAME(esd_open_sound))( const char *host ); 62 static int (*SDL_NAME(esd_open_sound)) (const char *host);
63 static int (*SDL_NAME(esd_close))( int esd ); 63 static int (*SDL_NAME(esd_close)) (int esd);
64 static int (*SDL_NAME(esd_play_stream))( esd_format_t format, int rate, 64 static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
65 const char *host, const char *name ); 65 const char *host, const char *name);
66 static struct { 66 static struct
67 const char *name; 67 {
68 void **func; 68 const char *name;
69 void **func;
69 } esd_functions[] = { 70 } esd_functions[] = {
70 { "esd_open_sound", (void **)&SDL_NAME(esd_open_sound) }, 71 {
71 { "esd_close", (void **)&SDL_NAME(esd_close) }, 72 "esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, {
72 { "esd_play_stream", (void **)&SDL_NAME(esd_play_stream) }, 73 "esd_close", (void **) &SDL_NAME(esd_close)}, {
74 "esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},};
75
76 static void
77 UnloadESDLibrary()
78 {
79 if (esd_loaded) {
80 SDL_UnloadObject(esd_handle);
81 esd_handle = NULL;
82 esd_loaded = 0;
83 }
84 }
85
86 static int
87 LoadESDLibrary(void)
88 {
89 int i, retval = -1;
90
91 esd_handle = SDL_LoadObject(esd_library);
92 if (esd_handle) {
93 esd_loaded = 1;
94 retval = 0;
95 for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
96 *esd_functions[i].func =
97 SDL_LoadFunction(esd_handle, esd_functions[i].name);
98 if (!*esd_functions[i].func) {
99 retval = -1;
100 UnloadESDLibrary();
101 break;
102 }
103 }
104 }
105 return retval;
106 }
107
108 #else
109
110 static void
111 UnloadESDLibrary()
112 {
113 return;
114 }
115
116 static int
117 LoadESDLibrary(void)
118 {
119 return 0;
120 }
121
122 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
123
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
73 }; 191 };
74 192
75 static void UnloadESDLibrary()
76 {
77 if ( esd_loaded ) {
78 SDL_UnloadObject(esd_handle);
79 esd_handle = NULL;
80 esd_loaded = 0;
81 }
82 }
83
84 static int LoadESDLibrary(void)
85 {
86 int i, retval = -1;
87
88 esd_handle = SDL_LoadObject(esd_library);
89 if ( esd_handle ) {
90 esd_loaded = 1;
91 retval = 0;
92 for ( i=0; i<SDL_arraysize(esd_functions); ++i ) {
93 *esd_functions[i].func = SDL_LoadFunction(esd_handle, esd_functions[i].name);
94 if ( !*esd_functions[i].func ) {
95 retval = -1;
96 UnloadESDLibrary();
97 break;
98 }
99 }
100 }
101 return retval;
102 }
103
104 #else
105
106 static void UnloadESDLibrary()
107 {
108 return;
109 }
110
111 static int LoadESDLibrary(void)
112 {
113 return 0;
114 }
115
116 #endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
117
118 /* Audio driver bootstrap functions */
119
120 static int Audio_Available(void)
121 {
122 int connection;
123 int available;
124
125 available = 0;
126 if ( LoadESDLibrary() < 0 ) {
127 return available;
128 }
129 connection = SDL_NAME(esd_open_sound)(NULL);
130 if ( connection >= 0 ) {
131 available = 1;
132 SDL_NAME(esd_close)(connection);
133 }
134 UnloadESDLibrary();
135 return(available);
136 }
137
138 static void Audio_DeleteDevice(SDL_AudioDevice *device)
139 {
140 SDL_free(device->hidden);
141 SDL_free(device);
142 UnloadESDLibrary();
143 }
144
145 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
146 {
147 SDL_AudioDevice *this;
148
149 /* Initialize all variables that we clean on shutdown */
150 LoadESDLibrary();
151 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
152 if ( this ) {
153 SDL_memset(this, 0, (sizeof *this));
154 this->hidden = (struct SDL_PrivateAudioData *)
155 SDL_malloc((sizeof *this->hidden));
156 }
157 if ( (this == NULL) || (this->hidden == NULL) ) {
158 SDL_OutOfMemory();
159 if ( this ) {
160 SDL_free(this);
161 }
162 return(0);
163 }
164 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
165 audio_fd = -1;
166
167 /* Set the function pointers */
168 this->OpenAudio = ESD_OpenAudio;
169 this->WaitAudio = ESD_WaitAudio;
170 this->PlayAudio = ESD_PlayAudio;
171 this->GetAudioBuf = ESD_GetAudioBuf;
172 this->CloseAudio = ESD_CloseAudio;
173
174 this->free = Audio_DeleteDevice;
175
176 return this;
177 }
178
179 AudioBootStrap ESD_bootstrap = {
180 ESD_DRIVER_NAME, "Enlightened Sound Daemon",
181 Audio_Available, Audio_CreateDevice
182 };
183
184 /* This function waits until it is possible to write a full sound buffer */ 193 /* This function waits until it is possible to write a full sound buffer */
185 static void ESD_WaitAudio(_THIS) 194 static void
186 { 195 ESD_WaitAudio(_THIS)
187 Sint32 ticks; 196 {
188 197 Sint32 ticks;
189 /* Check to see if the thread-parent process is still alive */ 198
190 { static int cnt = 0; 199 /* Check to see if the thread-parent process is still alive */
191 /* Note that this only works with thread implementations 200 {
192 that use a different process id for each thread. 201 static int cnt = 0;
193 */ 202 /* Note that this only works with thread implementations
194 if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */ 203 that use a different process id for each thread.
195 if ( kill(parent, 0) < 0 ) { 204 */
196 this->enabled = 0; 205 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
197 } 206 if (kill(parent, 0) < 0) {
198 } 207 this->enabled = 0;
199 } 208 }
200 209 }
201 /* Use timer for general audio synchronization */ 210 }
202 ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS; 211
203 if ( ticks > 0 ) { 212 /* Use timer for general audio synchronization */
204 SDL_Delay(ticks); 213 ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
205 } 214 if (ticks > 0) {
206 } 215 SDL_Delay(ticks);
207 216 }
208 static void ESD_PlayAudio(_THIS) 217 }
209 { 218
210 int written; 219 static void
211 220 ESD_PlayAudio(_THIS)
212 /* Write the audio data, checking for EAGAIN on broken audio drivers */ 221 {
213 do { 222 int written;
214 written = write(audio_fd, mixbuf, mixlen); 223
215 if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) { 224 /* Write the audio data, checking for EAGAIN on broken audio drivers */
216 SDL_Delay(1); /* Let a little CPU time go by */ 225 do {
217 } 226 written = write(audio_fd, mixbuf, mixlen);
218 } while ( (written < 0) && 227 if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
219 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) ); 228 SDL_Delay(1); /* Let a little CPU time go by */
220 229 }
221 /* Set the next write frame */ 230 }
222 next_frame += frame_ticks; 231 while ((written < 0) &&
223 232 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
224 /* If we couldn't write, assume fatal error for now */ 233
225 if ( written < 0 ) { 234 /* Set the next write frame */
226 this->enabled = 0; 235 next_frame += frame_ticks;
227 } 236
228 } 237 /* If we couldn't write, assume fatal error for now */
229 238 if (written < 0) {
230 static Uint8 *ESD_GetAudioBuf(_THIS) 239 this->enabled = 0;
231 { 240 }
232 return(mixbuf); 241 }
233 } 242
234 243 static Uint8 *
235 static void ESD_CloseAudio(_THIS) 244 ESD_GetAudioBuf(_THIS)
236 { 245 {
237 if ( mixbuf != NULL ) { 246 return (mixbuf);
238 SDL_FreeAudioMem(mixbuf); 247 }
239 mixbuf = NULL; 248
240 } 249 static void
241 if ( audio_fd >= 0 ) { 250 ESD_CloseAudio(_THIS)
242 SDL_NAME(esd_close)(audio_fd); 251 {
243 audio_fd = -1; 252 if (mixbuf != NULL) {
244 } 253 SDL_FreeAudioMem(mixbuf);
254 mixbuf = NULL;
255 }
256 if (audio_fd >= 0) {
257 SDL_NAME(esd_close) (audio_fd);
258 audio_fd = -1;
259 }
245 } 260 }
246 261
247 /* Try to get the name of the program */ 262 /* Try to get the name of the program */
248 static char *get_progname(void) 263 static char *
249 { 264 get_progname(void)
250 char *progname = NULL; 265 {
266 char *progname = NULL;
251 #ifdef __LINUX__ 267 #ifdef __LINUX__
252 FILE *fp; 268 FILE *fp;
253 static char temp[BUFSIZ]; 269 static char temp[BUFSIZ];
254 270
255 SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid()); 271 SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
256 fp = fopen(temp, "r"); 272 fp = fopen(temp, "r");
257 if ( fp != NULL ) { 273 if (fp != NULL) {
258 if ( fgets(temp, sizeof(temp)-1, fp) ) { 274 if (fgets(temp, sizeof(temp) - 1, fp)) {
259 progname = SDL_strrchr(temp, '/'); 275 progname = SDL_strrchr(temp, '/');
260 if ( progname == NULL ) { 276 if (progname == NULL) {
261 progname = temp; 277 progname = temp;
262 } else { 278 } else {
263 progname = progname+1; 279 progname = progname + 1;
264 } 280 }
265 } 281 }
266 fclose(fp); 282 fclose(fp);
267 } 283 }
268 #endif 284 #endif
269 return(progname); 285 return (progname);
270 } 286 }
271 287
272 static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec) 288 static int
273 { 289 ESD_OpenAudio(_THIS, SDL_AudioSpec * spec)
274 esd_format_t format; 290 {
275 291 esd_format_t format;
276 /* Convert audio spec to the ESD audio format */ 292
277 format = (ESD_STREAM | ESD_PLAY); 293 /* Convert audio spec to the ESD audio format */
278 switch ( spec->format & 0xFF ) { 294 format = (ESD_STREAM | ESD_PLAY);
279 case 8: 295 switch (spec->format & 0xFF) {
280 format |= ESD_BITS8; 296 case 8:
281 break; 297 format |= ESD_BITS8;
282 case 16: 298 break;
283 format |= ESD_BITS16; 299 case 16:
284 break; 300 format |= ESD_BITS16;
285 default: 301 break;
286 SDL_SetError("Unsupported ESD audio format"); 302 default:
287 return(-1); 303 SDL_SetError("Unsupported ESD audio format");
288 } 304 return (-1);
289 if ( spec->channels == 1 ) { 305 }
290 format |= ESD_MONO; 306 if (spec->channels == 1) {
291 } else { 307 format |= ESD_MONO;
292 format |= ESD_STEREO; 308 } else {
293 } 309 format |= ESD_STEREO;
310 }
294 #if 0 311 #if 0
295 spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */ 312 spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
296 #endif 313 #endif
297 314
298 /* Open a connection to the ESD audio server */ 315 /* Open a connection to the ESD audio server */
299 audio_fd = SDL_NAME(esd_play_stream)(format, spec->freq, NULL, get_progname()); 316 audio_fd =
300 if ( audio_fd < 0 ) { 317 SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname());
301 SDL_SetError("Couldn't open ESD connection"); 318 if (audio_fd < 0) {
302 return(-1); 319 SDL_SetError("Couldn't open ESD connection");
303 } 320 return (-1);
304 321 }
305 /* Calculate the final parameters for this audio specification */ 322
306 SDL_CalculateAudioSpec(spec); 323 /* Calculate the final parameters for this audio specification */
307 frame_ticks = (float)(spec->samples*1000)/spec->freq; 324 SDL_CalculateAudioSpec(spec);
308 next_frame = SDL_GetTicks()+frame_ticks; 325 frame_ticks = (float) (spec->samples * 1000) / spec->freq;
309 326 next_frame = SDL_GetTicks() + frame_ticks;
310 /* Allocate mixing buffer */ 327
311 mixlen = spec->size; 328 /* Allocate mixing buffer */
312 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); 329 mixlen = spec->size;
313 if ( mixbuf == NULL ) { 330 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
314 return(-1); 331 if (mixbuf == NULL) {
315 } 332 return (-1);
316 SDL_memset(mixbuf, spec->silence, spec->size); 333 }
317 334 SDL_memset(mixbuf, spec->silence, spec->size);
318 /* Get the parent process id (we're the parent of the audio thread) */ 335
319 parent = getpid(); 336 /* Get the parent process id (we're the parent of the audio thread) */
320 337 parent = getpid();
321 /* We're ready to rock and roll. :-) */ 338
322 return(0); 339 /* We're ready to rock and roll. :-) */
323 } 340 return (0);
341 }
342
343 /* vi: set ts=4 sw=4 expandtab: */