comparison src/audio/arts/SDL_artsaudio.c @ 3812:35d1367020a3 SDL-ryan-multiple-audio-device

Updated arts driver for 1.3 audio API.
author Ryan C. Gordon <icculus@icculus.org>
date Fri, 06 Oct 2006 02:40:02 +0000
parents 7852b5b78af5
children 92f7304e50ff
comparison
equal deleted inserted replaced
3811:d980c4dcad0f 3812:35d1367020a3
38 38
39 /* The tag name used by artsc audio */ 39 /* The tag name used by artsc audio */
40 #define ARTS_DRIVER_NAME "arts" 40 #define ARTS_DRIVER_NAME "arts"
41 41
42 /* Audio driver functions */ 42 /* Audio driver functions */
43 static int ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec); 43 static int ARTS_OpenDevice(_THIS, const char *devname, int iscapture);
44 static void ARTS_WaitAudio(_THIS); 44 static void ARTS_WaitDevice(_THIS);
45 static void ARTS_PlayAudio(_THIS); 45 static void ARTS_PlayDevice(_THIS);
46 static Uint8 *ARTS_GetAudioBuf(_THIS); 46 static Uint8 *ARTS_GetDeviceBuf(_THIS);
47 static void ARTS_CloseAudio(_THIS); 47 static void ARTS_CloseDevice(_THIS);
48 static void ARTS_WaitDone(_THIS);
48 49
49 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC 50 #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
50 51
51 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC; 52 static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
52 static void *arts_handle = NULL; 53 static void *arts_handle = NULL;
53 static int arts_loaded = 0; 54 static int arts_loaded = 0;
54 55
56 /* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
55 static int (*SDL_NAME(arts_init)) (void); 57 static int (*SDL_NAME(arts_init)) (void);
56 static void (*SDL_NAME(arts_free)) (void); 58 static void (*SDL_NAME(arts_free)) (void);
57 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, 59 static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
58 int channels, 60 int channels,
59 const char *name); 61 const char *name);
62 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, 64 static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
63 arts_parameter_t param); 65 arts_parameter_t param);
64 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, 66 static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
65 int count); 67 int count);
66 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); 68 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
67 69 static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
70 static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
71
72 #define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
68 static struct 73 static struct
69 { 74 {
70 const char *name; 75 const char *name;
71 void **func; 76 void **func;
72 } arts_functions[] = { 77 } arts_functions[] = {
73 { 78 SDL_ARTS_SYM(arts_init),
74 "arts_init", (void **) &SDL_NAME(arts_init)}, { 79 SDL_ARTS_SYM(arts_free),
75 "arts_free", (void **) &SDL_NAME(arts_free)}, { 80 SDL_ARTS_SYM(arts_play_stream),
76 "arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, { 81 SDL_ARTS_SYM(arts_stream_set),
77 "arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, { 82 SDL_ARTS_SYM(arts_stream_get),
78 "arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, { 83 SDL_ARTS_SYM(arts_write),
79 "arts_write", (void **) &SDL_NAME(arts_write)}, { 84 SDL_ARTS_SYM(arts_close_stream),
80 "arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},}; 85 SDL_ARTS_SYM(arts_error_text),
86 };
87 #undef SDL_ARTS_SYM
81 88
82 static void 89 static void
83 UnloadARTSLibrary() 90 UnloadARTSLibrary()
84 { 91 {
85 if (arts_loaded) { 92 if (arts_loaded) {
92 static int 99 static int
93 LoadARTSLibrary(void) 100 LoadARTSLibrary(void)
94 { 101 {
95 int i, retval = -1; 102 int i, retval = -1;
96 103
97 arts_handle = SDL_LoadObject(arts_library); 104 if (!arts_loaded) {
98 if (arts_handle) { 105 arts_handle = SDL_LoadObject(arts_library);
99 arts_loaded = 1; 106 if (arts_handle) {
100 retval = 0; 107 arts_loaded = 1;
101 for (i = 0; i < SDL_arraysize(arts_functions); ++i) { 108 retval = 0;
102 *arts_functions[i].func = 109 for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
103 SDL_LoadFunction(arts_handle, arts_functions[i].name); 110 *arts_functions[i].func =
104 if (!*arts_functions[i].func) { 111 SDL_LoadFunction(arts_handle, arts_functions[i].name);
105 retval = -1; 112 if (!*arts_functions[i].func) {
106 UnloadARTSLibrary(); 113 retval = -1;
107 break; 114 UnloadARTSLibrary();
115 break;
116 }
108 } 117 }
109 } 118 }
110 } 119 }
120
111 return retval; 121 return retval;
112 } 122 }
113 123
114 #else 124 #else
115 125
128 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */ 138 #endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
129 139
130 /* Audio driver bootstrap functions */ 140 /* Audio driver bootstrap functions */
131 141
132 static int 142 static int
133 Audio_Available(void) 143 ARTS_Available(void)
134 { 144 {
135 int available = 0; 145 int available = 0;
136 146
137 if (LoadARTSLibrary() < 0) { 147 if (LoadARTSLibrary() == 0) {
138 return available; 148 if (SDL_NAME(arts_init) () == 0) {
139 }
140 if (SDL_NAME(arts_init) () == 0) {
141 #define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */ 149 #define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */
142 #ifdef ARTS_CRASH_HACK 150 #ifdef ARTS_CRASH_HACK
143 arts_stream_t stream2; 151 arts_stream_t stream;
144 stream2 = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); 152 stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
145 SDL_NAME(arts_write) (stream2, "", 0); 153 SDL_NAME(arts_write) (stream, "", 0);
146 SDL_NAME(arts_close_stream) (stream2); 154 SDL_NAME(arts_close_stream) (stream);
147 #endif 155 #endif
148 available = 1; 156 available = 1;
149 SDL_NAME(arts_free) (); 157 SDL_NAME(arts_free) ();
150 } 158 }
151 UnloadARTSLibrary(); 159 UnloadARTSLibrary();
160 }
152 161
153 return available; 162 return available;
154 } 163 }
155 164
156 static void 165
157 Audio_DeleteDevice(SDL_AudioDevice * device) 166 static int
158 { 167 ARTS_Init(SDL_AudioDriverImpl *impl)
159 SDL_free(device->hidden); 168 {
160 SDL_free(device);
161 UnloadARTSLibrary();
162 }
163
164 static SDL_AudioDevice *
165 Audio_CreateDevice(int devindex)
166 {
167 SDL_AudioDevice *this;
168
169 /* Initialize all variables that we clean on shutdown */
170 LoadARTSLibrary();
171 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
172 if (this) {
173 SDL_memset(this, 0, (sizeof *this));
174 this->hidden = (struct SDL_PrivateAudioData *)
175 SDL_malloc((sizeof *this->hidden));
176 }
177 if ((this == NULL) || (this->hidden == NULL)) {
178 SDL_OutOfMemory();
179 if (this) {
180 SDL_free(this);
181 }
182 return (0);
183 }
184 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
185 stream = 0;
186
187 /* Set the function pointers */ 169 /* Set the function pointers */
188 this->OpenAudio = ARTS_OpenAudio; 170 impl->OpenDevice = ARTS_OpenDevice;
189 this->WaitAudio = ARTS_WaitAudio; 171 impl->PlayDevice = ARTS_PlayDevice;
190 this->PlayAudio = ARTS_PlayAudio; 172 impl->WaitDevice = ARTS_WaitDevice;
191 this->GetAudioBuf = ARTS_GetAudioBuf; 173 impl->GetDeviceBuf = ARTS_GetDeviceBuf;
192 this->CloseAudio = ARTS_CloseAudio; 174 impl->CloseDevice = ARTS_CloseDevice;
193 175 impl->WaitDone = ARTS_WaitDone;
194 this->free = Audio_DeleteDevice; 176 impl->OnlyHasDefaultOutputDevice = 1;
195 177
196 return this; 178 return 1;
197 } 179 }
180
198 181
199 AudioBootStrap ARTS_bootstrap = { 182 AudioBootStrap ARTS_bootstrap = {
200 ARTS_DRIVER_NAME, "Analog Realtime Synthesizer", 183 ARTS_DRIVER_NAME, "Analog RealTime Synthesizer",
201 Audio_Available, Audio_CreateDevice, 0 184 ARTS_Available, ARTS_Init, 0
202 }; 185 };
203 186
187
204 /* This function waits until it is possible to write a full sound buffer */ 188 /* This function waits until it is possible to write a full sound buffer */
205 static void 189 static void
206 ARTS_WaitAudio(_THIS) 190 ARTS_WaitDevice(_THIS)
207 { 191 {
208 Sint32 ticks; 192 Sint32 ticks;
209 193
210 /* Check to see if the thread-parent process is still alive */ 194 /* Check to see if the thread-parent process is still alive */
211 { 195 {
212 static int cnt = 0; 196 static int cnt = 0;
213 /* Note that this only works with thread implementations 197 /* Note that this only works with thread implementations
214 that use a different process id for each thread. 198 that use a different process id for each thread.
215 */ 199 */
216 if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ 200 /* Check every 10 loops */
217 if (kill(parent, 0) < 0) { 201 if (this->hidden->parent && (((++cnt) % 10) == 0)) {
202 if (kill(this->hidden->parent, 0) < 0) {
218 this->enabled = 0; 203 this->enabled = 0;
219 } 204 }
220 } 205 }
221 } 206 }
222 207
223 /* Use timer for general audio synchronization */ 208 /* Use timer for general audio synchronization */
224 ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; 209 ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
225 if (ticks > 0) { 210 if (ticks > 0) {
226 SDL_Delay(ticks); 211 SDL_Delay(ticks);
227 } 212 }
228 } 213 }
229 214
230 static void 215 static void
231 ARTS_PlayAudio(_THIS) 216 ARTS_PlayDevice(_THIS)
232 { 217 {
233 int written;
234
235 /* Write the audio data */ 218 /* Write the audio data */
236 written = SDL_NAME(arts_write) (stream, mixbuf, mixlen); 219 int written = SDL_NAME(arts_write) (
220 this->hidden->stream,
221 this->hidden->mixbuf,
222 this->hidden->mixlen);
237 223
238 /* If timer synchronization is enabled, set the next write frame */ 224 /* If timer synchronization is enabled, set the next write frame */
239 if (frame_ticks) { 225 if (this->hidden->frame_ticks) {
240 next_frame += frame_ticks; 226 this->hidden->next_frame += this->hidden->frame_ticks;
241 } 227 }
242 228
243 /* If we couldn't write, assume fatal error for now */ 229 /* If we couldn't write, assume fatal error for now */
244 if (written < 0) { 230 if (written < 0) {
245 this->enabled = 0; 231 this->enabled = 0;
247 #ifdef DEBUG_AUDIO 233 #ifdef DEBUG_AUDIO
248 fprintf(stderr, "Wrote %d bytes of audio data\n", written); 234 fprintf(stderr, "Wrote %d bytes of audio data\n", written);
249 #endif 235 #endif
250 } 236 }
251 237
238 static void
239 ARTS_WaitDone(_THIS)
240 {
241 /* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
242 }
243
244
252 static Uint8 * 245 static Uint8 *
253 ARTS_GetAudioBuf(_THIS) 246 ARTS_GetDeviceBuf(_THIS)
254 { 247 {
255 return (mixbuf); 248 return (this->hidden->mixbuf);
256 } 249 }
257 250
258 static void 251
259 ARTS_CloseAudio(_THIS) 252 static void
260 { 253 ARTS_CloseDevice(_THIS)
261 if (mixbuf != NULL) { 254 {
262 SDL_FreeAudioMem(mixbuf); 255 if (this->hidden != NULL) {
263 mixbuf = NULL; 256 if (this->hidden->mixbuf != NULL) {
264 } 257 SDL_FreeAudioMem(this->hidden->mixbuf);
265 if (stream) { 258 this->hidden->mixbuf = NULL;
266 SDL_NAME(arts_close_stream) (stream); 259 }
267 stream = 0; 260 if (this->hidden->stream) {
268 } 261 SDL_NAME(arts_close_stream) (this->hidden->stream);
269 SDL_NAME(arts_free) (); 262 this->hidden->stream = 0;
270 } 263 }
271 264 SDL_NAME(arts_free) ();
272 static int 265 SDL_free(this->hidden);
273 ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec) 266 this->hidden = NULL;
274 { 267 }
268 UnloadARTSLibrary();
269 }
270
271
272 static int
273 ARTS_OpenDevice(_THIS, const char *devname, int iscapture)
274 {
275 int rc = 0;
275 int bits, frag_spec; 276 int bits, frag_spec;
276 SDL_AudioFormat test_format, format; 277 SDL_AudioFormat test_format, format;
277 278
278 /* Reset the timer synchronization flag */ 279 /* Initialize all variables that we clean on shutdown */
279 frame_ticks = 0.0; 280 this->hidden = (struct SDL_PrivateAudioData *)
280 281 SDL_malloc((sizeof *this->hidden));
281 mixbuf = NULL; 282 if (this->hidden == NULL) {
283 SDL_OutOfMemory();
284 return 0;
285 }
286 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
287
288 if (LoadARTSLibrary() < 0) {
289 ARTS_CloseDevice(this);
290 SDL_SetError("ARTS: failed to load library: %s", SDL_GetError());
291 return 0;
292 }
282 293
283 /* Try for a closest match on audio format */ 294 /* Try for a closest match on audio format */
284 format = 0; 295 format = 0;
285 bits = 0; 296 bits = 0;
286 for (test_format = SDL_FirstAudioFormat(spec->format); 297 for (test_format = SDL_FirstAudioFormat(this->spec.format);
287 !format && test_format;) { 298 !format && test_format;) {
288 #ifdef DEBUG_AUDIO 299 #ifdef DEBUG_AUDIO
289 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); 300 fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
290 #endif 301 #endif
291 switch (test_format) { 302 switch (test_format) {
304 if (!format) { 315 if (!format) {
305 test_format = SDL_NextAudioFormat(); 316 test_format = SDL_NextAudioFormat();
306 } 317 }
307 } 318 }
308 if (format == 0) { 319 if (format == 0) {
320 ARTS_CloseDevice(this);
309 SDL_SetError("Couldn't find any hardware audio formats"); 321 SDL_SetError("Couldn't find any hardware audio formats");
310 return (-1); 322 return 0;
311 } 323 }
312 spec->format = test_format; 324 this->spec.format = test_format;
313 325
314 if (SDL_NAME(arts_init) () != 0) { 326 if ((rc = SDL_NAME(arts_init) ()) != 0) {
315 SDL_SetError("Unable to initialize ARTS"); 327 ARTS_CloseDevice(this);
316 return (-1); 328 SDL_SetError( "Unable to initialize ARTS: %s",
317 } 329 SDL_NAME(arts_error_text)(rc) );
318 stream = 330 return 0;
319 SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL"); 331 }
332 this->hidden->stream = SDL_NAME(arts_play_stream) (
333 this->spec.freq,
334 bits, this->spec.channels,
335 "SDL");
320 336
321 /* Calculate the final parameters for this audio specification */ 337 /* Calculate the final parameters for this audio specification */
322 SDL_CalculateAudioSpec(spec); 338 SDL_CalculateAudioSpec(&this->spec);
323 339
324 /* Determine the power of two of the fragment size */ 340 /* Determine the power of two of the fragment size */
325 for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); 341 for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
326 if ((0x01 << frag_spec) != spec->size) { 342 if ((0x01 << frag_spec) != this->spec.size) {
343 ARTS_CloseDevice(this);
327 SDL_SetError("Fragment size must be a power of two"); 344 SDL_SetError("Fragment size must be a power of two");
328 return (-1); 345 return 0;
329 } 346 }
330 frag_spec |= 0x00020000; /* two fragments, for low latency */ 347 frag_spec |= 0x00020000; /* two fragments, for low latency */
331 348
332 #ifdef ARTS_P_PACKET_SETTINGS 349 #ifdef ARTS_P_PACKET_SETTINGS
333 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SETTINGS, frag_spec); 350 SDL_NAME(arts_stream_set) (this->hidden->stream,
351 ARTS_P_PACKET_SETTINGS, frag_spec);
334 #else 352 #else
335 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SIZE, 353 SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE,
336 frag_spec & 0xffff); 354 frag_spec & 0xffff);
337 SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_COUNT, frag_spec >> 16); 355 SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT,
338 #endif 356 frag_spec >> 16);
339 spec->size = SDL_NAME(arts_stream_get) (stream, ARTS_P_PACKET_SIZE); 357 #endif
358 this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream,
359 ARTS_P_PACKET_SIZE);
340 360
341 /* Allocate mixing buffer */ 361 /* Allocate mixing buffer */
342 mixlen = spec->size; 362 this->hidden->mixlen = this->spec.size;
343 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); 363 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
344 if (mixbuf == NULL) { 364 if (this->hidden->mixbuf == NULL) {
345 return (-1); 365 ARTS_CloseDevice(this);
346 } 366 SDL_OutOfMemory();
347 SDL_memset(mixbuf, spec->silence, spec->size); 367 return 0;
368 }
369 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
348 370
349 /* Get the parent process id (we're the parent of the audio thread) */ 371 /* Get the parent process id (we're the parent of the audio thread) */
350 parent = getpid(); 372 this->hidden->parent = getpid();
351 373
352 /* We're ready to rock and roll. :-) */ 374 /* We're ready to rock and roll. :-) */
353 return (0); 375 return 1;
354 } 376 }
355 377
356 /* vi: set ts=4 sw=4 expandtab: */ 378 /* vi: set ts=4 sw=4 expandtab: */