Mercurial > sdl-ios-xcode
comparison src/audio/paudio/SDL_paudio.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 |
---|---|
28 #include <errno.h> | 28 #include <errno.h> |
29 #include <unistd.h> | 29 #include <unistd.h> |
30 #include <fcntl.h> | 30 #include <fcntl.h> |
31 #include <sys/time.h> | 31 #include <sys/time.h> |
32 #include <sys/ioctl.h> | 32 #include <sys/ioctl.h> |
33 #include <sys/types.h> | |
33 #include <sys/stat.h> | 34 #include <sys/stat.h> |
34 | 35 |
35 #include "SDL_timer.h" | 36 #include "SDL_timer.h" |
36 #include "SDL_audio.h" | 37 #include "SDL_audio.h" |
38 #include "SDL_stdinc.h" | |
37 #include "../SDL_audiomem.h" | 39 #include "../SDL_audiomem.h" |
38 #include "../SDL_audio_c.h" | 40 #include "../SDL_audio_c.h" |
39 #include "../SDL_audiodev_c.h" | |
40 #include "SDL_paudio.h" | 41 #include "SDL_paudio.h" |
41 | 42 |
42 #define DEBUG_AUDIO 1 | 43 #define DEBUG_AUDIO 0 |
43 | 44 |
44 /* A conflict within AIX 4.3.3 <sys/> headers and probably others as well. | 45 /* A conflict within AIX 4.3.3 <sys/> headers and probably others as well. |
45 * I guess nobody ever uses audio... Shame over AIX header files. */ | 46 * I guess nobody ever uses audio... Shame over AIX header files. */ |
46 #include <sys/machine.h> | 47 #include <sys/machine.h> |
47 #undef BIG_ENDIAN | 48 #undef BIG_ENDIAN |
48 #include <sys/audio.h> | 49 #include <sys/audio.h> |
49 | 50 |
50 /* The tag name used by paud audio */ | 51 /* The tag name used by paud audio */ |
51 #define Paud_DRIVER_NAME "paud" | 52 #define PAUDIO_DRIVER_NAME "paud" |
52 | 53 |
53 /* Open the audio device for playback, and don't block if busy */ | 54 /* Open the audio device for playback, and don't block if busy */ |
54 /* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */ | 55 /* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */ |
55 #define OPEN_FLAGS O_WRONLY | 56 #define OPEN_FLAGS O_WRONLY |
56 | 57 |
57 /* Audio driver functions */ | 58 /* Get the name of the audio device we use for output */ |
58 static int Paud_OpenAudio(_THIS, SDL_AudioSpec * spec); | 59 |
59 static void Paud_WaitAudio(_THIS); | 60 #ifndef _PATH_DEV_DSP |
60 static void Paud_PlayAudio(_THIS); | 61 #define _PATH_DEV_DSP "/dev/%caud%c/%c" |
61 static Uint8 *Paud_GetAudioBuf(_THIS); | 62 #endif |
62 static void Paud_CloseAudio(_THIS); | 63 |
63 | 64 static char devsettings[][3] = { |
64 /* Audio driver bootstrap functions */ | 65 {'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'}, |
66 {'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'}, | |
67 {'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'}, | |
68 {'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'}, | |
69 {'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'}, | |
70 {'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'}, | |
71 {'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'}, | |
72 {'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'}, | |
73 {'\0', '\0', '\0'} | |
74 }; | |
65 | 75 |
66 static int | 76 static int |
67 Audio_Available(void) | 77 OpenUserDefinedDevice(char *path, int maxlen, int flags) |
68 { | 78 { |
79 const char *audiodev; | |
69 int fd; | 80 int fd; |
70 int available; | 81 |
71 | 82 /* Figure out what our audio device is */ |
72 available = 0; | 83 if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) { |
73 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); | 84 audiodev = SDL_getenv("AUDIODEV"); |
74 if (fd >= 0) { | 85 } |
75 available = 1; | 86 if (audiodev == NULL) { |
76 close(fd); | 87 return -1; |
77 } | 88 } |
78 return (available); | 89 fd = open(audiodev, flags, 0); |
79 } | 90 if (path != NULL) { |
80 | 91 SDL_strlcpy(path, audiodev, maxlen); |
81 static void | 92 path[maxlen - 1] = '\0'; |
82 Audio_DeleteDevice(SDL_AudioDevice * device) | 93 } |
83 { | 94 return fd; |
84 SDL_free(device->hidden); | 95 } |
85 SDL_free(device); | 96 |
86 } | 97 static int |
87 | 98 OpenAudioPath(char *path, int maxlen, int flags, int classic) |
88 static SDL_AudioDevice * | 99 { |
89 Audio_CreateDevice(int devindex) | 100 struct stat sb; |
90 { | 101 int cycle = 0; |
91 SDL_AudioDevice *this; | 102 int fd = OpenUserDefinedDevice(path, maxlen, flags); |
92 | 103 |
93 /* Initialize all variables that we clean on shutdown */ | 104 if (fd != -1) { |
94 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | 105 return fd; |
95 if (this) { | 106 } |
96 SDL_memset(this, 0, (sizeof *this)); | 107 |
97 this->hidden = (struct SDL_PrivateAudioData *) | 108 /* !!! FIXME: do we really need a table here? */ |
98 SDL_malloc((sizeof *this->hidden)); | 109 while (devsettings[cycle][0] != '\0') { |
99 } | 110 char audiopath[1024]; |
100 if ((this == NULL) || (this->hidden == NULL)) { | 111 SDL_snprintf(audiopath, SDL_arraysize(audiopath), |
101 SDL_OutOfMemory(); | 112 _PATH_DEV_DSP, |
102 if (this) { | 113 devsettings[cycle][0], |
103 SDL_free(this); | 114 devsettings[cycle][1], devsettings[cycle][2]); |
104 } | 115 |
105 return (0); | 116 if (stat(audiopath, &sb) == 0) { |
106 } | 117 fd = open(audiopath, flags, 0); |
107 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | 118 if (fd > 0) { |
108 audio_fd = -1; | 119 if (path != NULL) { |
109 | 120 SDL_strlcpy(path, audiopath, maxlen); |
110 /* Set the function pointers */ | 121 } |
111 this->OpenAudio = Paud_OpenAudio; | 122 return fd; |
112 this->WaitAudio = Paud_WaitAudio; | 123 } |
113 this->PlayAudio = Paud_PlayAudio; | 124 } |
114 this->GetAudioBuf = Paud_GetAudioBuf; | 125 } |
115 this->CloseAudio = Paud_CloseAudio; | 126 return -1; |
116 | 127 } |
117 this->free = Audio_DeleteDevice; | |
118 | |
119 return this; | |
120 } | |
121 | |
122 AudioBootStrap Paud_bootstrap = { | |
123 Paud_DRIVER_NAME, "AIX Paudio", | |
124 Audio_Available, Audio_CreateDevice | |
125 }; | |
126 | 128 |
127 /* 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 */ |
128 static void | 130 static void |
129 Paud_WaitAudio(_THIS) | 131 PAUDIO_WaitDevice(_THIS) |
130 { | 132 { |
131 fd_set fdset; | 133 fd_set fdset; |
132 | 134 |
133 /* See if we need to use timed audio synchronization */ | 135 /* See if we need to use timed audio synchronization */ |
134 if (frame_ticks) { | 136 if (this->hidden->frame_ticks) { |
135 /* Use timer for general audio synchronization */ | 137 /* Use timer for general audio synchronization */ |
136 Sint32 ticks; | 138 Sint32 ticks; |
137 | 139 |
138 ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; | 140 ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS; |
139 if (ticks > 0) { | 141 if (ticks > 0) { |
140 SDL_Delay(ticks); | 142 SDL_Delay(ticks); |
141 } | 143 } |
142 } else { | 144 } else { |
143 audio_buffer paud_bufinfo; | 145 audio_buffer paud_bufinfo; |
144 | 146 |
145 /* Use select() for audio synchronization */ | 147 /* Use select() for audio synchronization */ |
146 struct timeval timeout; | 148 struct timeval timeout; |
147 FD_ZERO(&fdset); | 149 FD_ZERO(&fdset); |
148 FD_SET(audio_fd, &fdset); | 150 FD_SET(this->hidden->audio_fd, &fdset); |
149 | 151 |
150 if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { | 152 if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { |
151 #ifdef DEBUG_AUDIO | 153 #ifdef DEBUG_AUDIO |
152 fprintf(stderr, "Couldn't get audio buffer information\n"); | 154 fprintf(stderr, "Couldn't get audio buffer information\n"); |
153 #endif | 155 #endif |
154 timeout.tv_sec = 10; | 156 timeout.tv_sec = 10; |
155 timeout.tv_usec = 0; | 157 timeout.tv_usec = 0; |
166 } | 168 } |
167 | 169 |
168 #ifdef DEBUG_AUDIO | 170 #ifdef DEBUG_AUDIO |
169 fprintf(stderr, "Waiting for audio to get ready\n"); | 171 fprintf(stderr, "Waiting for audio to get ready\n"); |
170 #endif | 172 #endif |
171 if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) { | 173 if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) { |
172 const char *message = | 174 const char *message = |
173 "Audio timeout - buggy audio driver? (disabled)"; | 175 "Audio timeout - buggy audio driver? (disabled)"; |
174 /* | 176 /* |
175 * In general we should never print to the screen, | 177 * In general we should never print to the screen, |
176 * but in this case we have no other way of letting | 178 * but in this case we have no other way of letting |
177 * the user know what happened. | 179 * the user know what happened. |
178 */ | 180 */ |
179 fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); | 181 fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); |
180 this->enabled = 0; | 182 this->enabled = 0; |
181 /* Don't try to close - may hang */ | 183 /* Don't try to close - may hang */ |
182 audio_fd = -1; | 184 this->hidden->audio_fd = -1; |
183 #ifdef DEBUG_AUDIO | 185 #ifdef DEBUG_AUDIO |
184 fprintf(stderr, "Done disabling audio\n"); | 186 fprintf(stderr, "Done disabling audio\n"); |
185 #endif | 187 #endif |
186 } | 188 } |
187 #ifdef DEBUG_AUDIO | 189 #ifdef DEBUG_AUDIO |
189 #endif | 191 #endif |
190 } | 192 } |
191 } | 193 } |
192 | 194 |
193 static void | 195 static void |
194 Paud_PlayAudio(_THIS) | 196 PAUDIO_PlayDevice(_THIS) |
195 { | 197 { |
196 int written; | 198 int written = 0; |
199 const Uint8 *mixbuf = this->hidden->mixbuf; | |
200 const size_t mixlen = this->hidden->mixlen; | |
197 | 201 |
198 /* Write the audio data, checking for EAGAIN on broken audio drivers */ | 202 /* Write the audio data, checking for EAGAIN on broken audio drivers */ |
199 do { | 203 do { |
200 written = write(audio_fd, mixbuf, mixlen); | 204 written = write(this->hidden->audio_fd, mixbuf, mixlen); |
201 if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) { | 205 if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) { |
202 SDL_Delay(1); /* Let a little CPU time go by */ | 206 SDL_Delay(1); /* Let a little CPU time go by */ |
203 } | 207 } |
204 } | 208 } |
205 while ((written < 0) && | 209 while ((written < 0) && |
206 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); | 210 ((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); |
207 | 211 |
208 /* If timer synchronization is enabled, set the next write frame */ | 212 /* If timer synchronization is enabled, set the next write frame */ |
209 if (frame_ticks) { | 213 if (this->hidden->frame_ticks) { |
210 next_frame += frame_ticks; | 214 this->hidden->next_frame += this->hidden->frame_ticks; |
211 } | 215 } |
212 | 216 |
213 /* If we couldn't write, assume fatal error for now */ | 217 /* If we couldn't write, assume fatal error for now */ |
214 if (written < 0) { | 218 if (written < 0) { |
215 this->enabled = 0; | 219 this->enabled = 0; |
218 fprintf(stderr, "Wrote %d bytes of audio data\n", written); | 222 fprintf(stderr, "Wrote %d bytes of audio data\n", written); |
219 #endif | 223 #endif |
220 } | 224 } |
221 | 225 |
222 static Uint8 * | 226 static Uint8 * |
223 Paud_GetAudioBuf(_THIS) | 227 PAUDIO_GetDeviceBuf(_THIS) |
224 { | 228 { |
225 return mixbuf; | 229 return this->hidden->mixbuf; |
226 } | 230 } |
227 | 231 |
228 static void | 232 static void |
229 Paud_CloseAudio(_THIS) | 233 PAUDIO_CloseDevice(_THIS) |
230 { | 234 { |
231 if (mixbuf != NULL) { | 235 if (this->hidden != NULL) { |
232 SDL_FreeAudioMem(mixbuf); | 236 if (this->hidden->mixbuf != NULL) { |
233 mixbuf = NULL; | 237 SDL_FreeAudioMem(this->hidden->mixbuf); |
234 } | 238 this->hidden->mixbuf = NULL; |
235 if (audio_fd >= 0) { | 239 } |
236 close(audio_fd); | 240 if (this->hidden->audio_fd >= 0) { |
237 audio_fd = -1; | 241 close(this->hidden->audio_fd); |
242 this->hidden->audio_fd = -1; | |
243 } | |
244 SDL_free(this->hidden); | |
245 this->hidden = NULL; | |
238 } | 246 } |
239 } | 247 } |
240 | 248 |
241 static int | 249 static int |
242 Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) | 250 PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) |
243 { | 251 { |
252 const char *workaround = SDL_getenv("SDL_DSP_NOSELECT"); | |
244 char audiodev[1024]; | 253 char audiodev[1024]; |
254 const char *err = NULL; | |
245 int format; | 255 int format; |
246 int bytes_per_sample; | 256 int bytes_per_sample; |
247 SDL_AudioFormat test_format; | 257 SDL_AudioFormat test_format; |
248 audio_init paud_init; | 258 audio_init paud_init; |
249 audio_buffer paud_bufinfo; | 259 audio_buffer paud_bufinfo; |
250 audio_status paud_status; | 260 audio_status paud_status; |
251 audio_control paud_control; | 261 audio_control paud_control; |
252 audio_change paud_change; | 262 audio_change paud_change; |
253 | 263 int fd = -1; |
254 /* Reset the timer synchronization flag */ | 264 |
255 frame_ticks = 0.0; | 265 /* Initialize all variables that we clean on shutdown */ |
266 this->hidden = (struct SDL_PrivateAudioData *) | |
267 SDL_malloc((sizeof *this->hidden)); | |
268 if (this->hidden == NULL) { | |
269 SDL_OutOfMemory(); | |
270 return 0; | |
271 } | |
272 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
256 | 273 |
257 /* Open the audio device */ | 274 /* Open the audio device */ |
258 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); | 275 fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); |
259 if (audio_fd < 0) { | 276 this->hidden->audio_fd = fd; |
277 if (fd < 0) { | |
278 PAUDIO_CloseDevice(this); | |
260 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | 279 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); |
261 return -1; | 280 return 0; |
262 } | 281 } |
263 | 282 |
264 /* | 283 /* |
265 * We can't set the buffer size - just ask the device for the maximum | 284 * We can't set the buffer size - just ask the device for the maximum |
266 * that we can have. | 285 * that we can have. |
267 */ | 286 */ |
268 if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { | 287 if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { |
288 PAUDIO_CloseDevice(this); | |
269 SDL_SetError("Couldn't get audio buffer information"); | 289 SDL_SetError("Couldn't get audio buffer information"); |
270 return -1; | 290 return 0; |
271 } | 291 } |
272 | 292 |
273 mixbuf = NULL; | 293 if (this->spec.channels > 1) |
274 | 294 this->spec.channels = 2; |
275 if (spec->channels > 1) | |
276 spec->channels = 2; | |
277 else | 295 else |
278 spec->channels = 1; | 296 this->spec.channels = 1; |
279 | 297 |
280 /* | 298 /* |
281 * Fields in the audio_init structure: | 299 * Fields in the audio_init structure: |
282 * | 300 * |
283 * Ignored by us: | 301 * Ignored by us: |
320 * * CONFLICT - conflict with open's flags | 338 * * CONFLICT - conflict with open's flags |
321 * * OVERLOADED - out of DSP MIPS or memory | 339 * * OVERLOADED - out of DSP MIPS or memory |
322 * paud.position_resolution; * smallest increment for position | 340 * paud.position_resolution; * smallest increment for position |
323 */ | 341 */ |
324 | 342 |
325 paud_init.srate = spec->freq; | 343 paud_init.srate = this->spec.freq; |
326 paud_init.mode = PCM; | 344 paud_init.mode = PCM; |
327 paud_init.operation = PLAY; | 345 paud_init.operation = PLAY; |
328 paud_init.channels = spec->channels; | 346 paud_init.channels = this->spec.channels; |
329 | 347 |
330 /* Try for a closest match on audio format */ | 348 /* Try for a closest match on audio format */ |
331 format = 0; | 349 format = 0; |
332 for (test_format = SDL_FirstAudioFormat(spec->format); | 350 for (test_format = SDL_FirstAudioFormat(this->spec.format); |
333 !format && test_format;) { | 351 !format && test_format;) { |
334 #ifdef DEBUG_AUDIO | 352 #ifdef DEBUG_AUDIO |
335 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | 353 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); |
336 #endif | 354 #endif |
337 switch (test_format) { | 355 switch (test_format) { |
380 } | 398 } |
381 if (format == 0) { | 399 if (format == 0) { |
382 #ifdef DEBUG_AUDIO | 400 #ifdef DEBUG_AUDIO |
383 fprintf(stderr, "Couldn't find any hardware audio formats\n"); | 401 fprintf(stderr, "Couldn't find any hardware audio formats\n"); |
384 #endif | 402 #endif |
403 PAUDIO_CloseDevice(this); | |
385 SDL_SetError("Couldn't find any hardware audio formats"); | 404 SDL_SetError("Couldn't find any hardware audio formats"); |
386 return -1; | 405 return 0; |
387 } | 406 } |
388 spec->format = test_format; | 407 this->spec.format = test_format; |
389 | 408 |
390 /* | 409 /* |
391 * We know the buffer size and the max number of subsequent writes | 410 * We know the buffer size and the max number of subsequent writes |
392 * that can be pending. If more than one can pend, allow the application | 411 * that can be pending. If more than one can pend, allow the application |
393 * to do something like double buffering between our write buffer and | 412 * to do something like double buffering between our write buffer and |
394 * the device's own buffer that we are filling with write() anyway. | 413 * the device's own buffer that we are filling with write() anyway. |
395 * | 414 * |
396 * We calculate spec->samples like this because SDL_CalculateAudioSpec() | 415 * We calculate this->spec.samples like this because |
397 * will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2) | 416 * SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap |
398 * into spec->size in return. | 417 * (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return. |
399 */ | 418 */ |
400 if (paud_bufinfo.request_buf_cap == 1) { | 419 if (paud_bufinfo.request_buf_cap == 1) { |
401 spec->samples = paud_bufinfo.write_buf_cap | 420 this->spec.samples = paud_bufinfo.write_buf_cap |
402 / bytes_per_sample / spec->channels; | 421 / bytes_per_sample / this->spec.channels; |
403 } else { | 422 } else { |
404 spec->samples = paud_bufinfo.write_buf_cap | 423 this->spec.samples = paud_bufinfo.write_buf_cap |
405 / bytes_per_sample / spec->channels / 2; | 424 / bytes_per_sample / this->spec.channels / 2; |
406 } | 425 } |
407 paud_init.bsize = bytes_per_sample * spec->channels; | 426 paud_init.bsize = bytes_per_sample * this->spec.channels; |
408 | 427 |
409 SDL_CalculateAudioSpec(spec); | 428 SDL_CalculateAudioSpec(&this->spec); |
410 | 429 |
411 /* | 430 /* |
412 * The AIX paud device init can't modify the values of the audio_init | 431 * The AIX paud device init can't modify the values of the audio_init |
413 * structure that we pass to it. So we don't need any recalculation | 432 * structure that we pass to it. So we don't need any recalculation |
414 * of this stuff and no reinit call as in linux dsp and dma code. | 433 * of this stuff and no reinit call as in linux dsp and dma code. |
415 * | 434 * |
416 * /dev/paud supports all of the encoding formats, so we don't need | 435 * /dev/paud supports all of the encoding formats, so we don't need |
417 * to do anything like reopening the device, either. | 436 * to do anything like reopening the device, either. |
418 */ | 437 */ |
419 if (ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0) { | 438 if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) { |
420 switch (paud_init.rc) { | 439 switch (paud_init.rc) { |
421 case 1: | 440 case 1: |
422 SDL_SetError | 441 err = "Couldn't set audio format: DSP can't do play requests"; |
423 ("Couldn't set audio format: DSP can't do play requests"); | |
424 return -1; | |
425 break; | 442 break; |
426 case 2: | 443 case 2: |
427 SDL_SetError | 444 err = "Couldn't set audio format: DSP can't do record requests"; |
428 ("Couldn't set audio format: DSP can't do record requests"); | |
429 return -1; | |
430 break; | 445 break; |
431 case 4: | 446 case 4: |
432 SDL_SetError("Couldn't set audio format: request was invalid"); | 447 err = "Couldn't set audio format: request was invalid"; |
433 return -1; | |
434 break; | 448 break; |
435 case 5: | 449 case 5: |
436 SDL_SetError | 450 err = "Couldn't set audio format: conflict with open's flags"; |
437 ("Couldn't set audio format: conflict with open's flags"); | |
438 return -1; | |
439 break; | 451 break; |
440 case 6: | 452 case 6: |
441 SDL_SetError | 453 err = "Couldn't set audio format: out of DSP MIPS or memory"; |
442 ("Couldn't set audio format: out of DSP MIPS or memory"); | |
443 return -1; | |
444 break; | 454 break; |
445 default: | 455 default: |
446 SDL_SetError | 456 err = "Couldn't set audio format: not documented in sys/audio.h"; |
447 ("Couldn't set audio format: not documented in sys/audio.h"); | 457 break; |
448 return -1; | 458 } |
449 break; | 459 } |
450 } | 460 |
461 if (err != NULL) { | |
462 PAUDIO_CloseDevice(this); | |
463 SDL_SetError("Paudio: %s", err); | |
464 return 0; | |
451 } | 465 } |
452 | 466 |
453 /* Allocate mixing buffer */ | 467 /* Allocate mixing buffer */ |
454 mixlen = spec->size; | 468 this->hidden->mixlen = this->spec.size; |
455 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); | 469 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); |
456 if (mixbuf == NULL) { | 470 if (this->hidden->mixbuf == NULL) { |
457 return -1; | 471 PAUDIO_CloseDevice(this); |
458 } | 472 SDL_OutOfMemory(); |
459 SDL_memset(mixbuf, spec->silence, spec->size); | 473 return 0; |
474 } | |
475 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | |
460 | 476 |
461 /* | 477 /* |
462 * Set some paramters: full volume, first speaker that we can find. | 478 * Set some paramters: full volume, first speaker that we can find. |
463 * Ignore the other settings for now. | 479 * Ignore the other settings for now. |
464 */ | 480 */ |
473 paud_change.bass = AUDIO_IGNORE; /* the new bass state */ | 489 paud_change.bass = AUDIO_IGNORE; /* the new bass state */ |
474 paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */ | 490 paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */ |
475 | 491 |
476 paud_control.ioctl_request = AUDIO_CHANGE; | 492 paud_control.ioctl_request = AUDIO_CHANGE; |
477 paud_control.request_info = (char *) &paud_change; | 493 paud_control.request_info = (char *) &paud_change; |
478 if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) { | 494 if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) { |
479 #ifdef DEBUG_AUDIO | 495 #ifdef DEBUG_AUDIO |
480 fprintf(stderr, "Can't change audio display settings\n"); | 496 fprintf(stderr, "Can't change audio display settings\n"); |
481 #endif | 497 #endif |
482 } | 498 } |
483 | 499 |
485 * Tell the device to expect data. Actual start will wait for | 501 * Tell the device to expect data. Actual start will wait for |
486 * the first write() call. | 502 * the first write() call. |
487 */ | 503 */ |
488 paud_control.ioctl_request = AUDIO_START; | 504 paud_control.ioctl_request = AUDIO_START; |
489 paud_control.position = 0; | 505 paud_control.position = 0; |
490 if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) { | 506 if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) { |
507 PAUDIO_CloseDevice(this); | |
491 #ifdef DEBUG_AUDIO | 508 #ifdef DEBUG_AUDIO |
492 fprintf(stderr, "Can't start audio play\n"); | 509 fprintf(stderr, "Can't start audio play\n"); |
493 #endif | 510 #endif |
494 SDL_SetError("Can't start audio play"); | 511 SDL_SetError("Can't start audio play"); |
495 return -1; | 512 return 0; |
496 } | 513 } |
497 | 514 |
498 /* Check to see if we need to use select() workaround */ | 515 /* Check to see if we need to use select() workaround */ |
499 { | 516 if (workaround != NULL) { |
500 char *workaround; | 517 this->hidden->frame_ticks = (float) (this->spec.samples * 1000) / |
501 workaround = SDL_getenv("SDL_DSP_NOSELECT"); | 518 this->spec.freq; |
502 if (workaround) { | 519 this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks; |
503 frame_ticks = (float) (spec->samples * 1000) / spec->freq; | 520 } |
504 next_frame = SDL_GetTicks() + frame_ticks; | |
505 } | |
506 } | |
507 | |
508 /* Get the parent process id (we're the parent of the audio thread) */ | |
509 parent = getpid(); | |
510 | 521 |
511 /* We're ready to rock and roll. :-) */ | 522 /* We're ready to rock and roll. :-) */ |
512 return 0; | 523 return 1; |
513 } | 524 } |
525 | |
526 static int | |
527 PAUDIO_Init(SDL_AudioDriverImpl *impl) | |
528 { | |
529 int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); | |
530 if (fd < 0) { | |
531 SDL_SetError("PAUDIO: Couldn't open audio device"); | |
532 return 0; | |
533 } | |
534 close(fd); | |
535 | |
536 /* Set the function pointers */ | |
537 impl->OpenDevice = DSP_OpenDevice; | |
538 impl->PlayDevice = DSP_PlayDevice; | |
539 impl->PlayDevice = DSP_WaitDevice; | |
540 impl->GetDeviceBuf = DSP_GetDeviceBuf; | |
541 impl->CloseDevice = DSP_CloseDevice; | |
542 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */ | |
543 | |
544 return 1; | |
545 } | |
546 | |
547 AudioBootStrap PAUDIO_bootstrap = { | |
548 PAUDIO_DRIVER_NAME, "AIX Paudio", PAUDIO_Init, 0 | |
549 }; | |
514 | 550 |
515 /* vi: set ts=4 sw=4 expandtab: */ | 551 /* vi: set ts=4 sw=4 expandtab: */ |