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