Mercurial > sdl-ios-xcode
comparison src/audio/dma/SDL_dmaaudio.c @ 3795:589bc3d060cd SDL-ryan-multiple-audio-device
More 1.3 audio work...moved dsp and dma drivers over to new model. Untested!
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Wed, 04 Oct 2006 06:00:10 +0000 |
parents | 3b4ce57c6215 |
children | c8b3d3d13ed1 |
comparison
equal
deleted
inserted
replaced
3794:db24e43972ac | 3795:589bc3d060cd |
---|---|
18 | 18 |
19 Sam Lantinga | 19 Sam Lantinga |
20 slouken@libsdl.org | 20 slouken@libsdl.org |
21 */ | 21 */ |
22 #include "SDL_config.h" | 22 #include "SDL_config.h" |
23 | |
24 /* !!! FIXME: merge this driver with "dsp". */ | |
23 | 25 |
24 /* Allow access to a raw mixing buffer */ | 26 /* Allow access to a raw mixing buffer */ |
25 | 27 |
26 #include <stdio.h> | 28 #include <stdio.h> |
27 #include <string.h> /* For strerror() */ | 29 #include <string.h> /* For strerror() */ |
58 | 60 |
59 /* Open the audio device for playback, and don't block if busy */ | 61 /* Open the audio device for playback, and don't block if busy */ |
60 #define OPEN_FLAGS (O_RDWR|O_NONBLOCK) | 62 #define OPEN_FLAGS (O_RDWR|O_NONBLOCK) |
61 | 63 |
62 /* Audio driver functions */ | 64 /* Audio driver functions */ |
63 static int DMA_OpenAudio(_THIS, SDL_AudioSpec * spec); | 65 static int DMA_DetectDevices(int iscapture); |
64 static void DMA_WaitAudio(_THIS); | 66 static const char *DMA_GetDeviceName(int index, int iscapture); |
65 static void DMA_PlayAudio(_THIS); | 67 static int DMA_OpenDevice(_THIS, const char *devname, int iscapture); |
66 static Uint8 *DMA_GetAudioBuf(_THIS); | 68 static void DMA_WaitDevice(_THIS); |
67 static void DMA_CloseAudio(_THIS); | 69 static void DMA_PlayDevice(_THIS); |
70 static Uint8 *DMA_GetDeviceBuf(_THIS); | |
71 static void DMA_CloseDevice(_THIS); | |
68 | 72 |
69 /* Audio driver bootstrap functions */ | 73 /* Audio driver bootstrap functions */ |
70 | 74 |
71 static int | 75 static int |
72 Audio_Available(void) | 76 DMA_Available(void) |
73 { | 77 { |
78 /* | |
79 * !!! FIXME: maybe change this to always available, and move this to | |
80 * !!! FIXME: to device enumeration and opening? | |
81 */ | |
74 int available; | 82 int available; |
75 int fd; | 83 int fd; |
76 | 84 |
77 available = 0; | 85 available = 0; |
78 | 86 |
89 close(fd); | 97 close(fd); |
90 } | 98 } |
91 return (available); | 99 return (available); |
92 } | 100 } |
93 | 101 |
94 static void | 102 |
95 Audio_DeleteDevice(SDL_AudioDevice * device) | 103 static int |
96 { | 104 DMA_Init(SDL_AudioDriverImpl *impl) |
97 SDL_free(device->hidden); | 105 { |
98 SDL_free(device); | |
99 } | |
100 | |
101 static SDL_AudioDevice * | |
102 Audio_CreateDevice(int devindex) | |
103 { | |
104 SDL_AudioDevice *this; | |
105 | |
106 /* Initialize all variables that we clean on shutdown */ | |
107 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | |
108 if (this) { | |
109 SDL_memset(this, 0, (sizeof *this)); | |
110 this->hidden = (struct SDL_PrivateAudioData *) | |
111 SDL_malloc((sizeof *this->hidden)); | |
112 } | |
113 if ((this == NULL) || (this->hidden == NULL)) { | |
114 SDL_OutOfMemory(); | |
115 if (this) { | |
116 SDL_free(this); | |
117 } | |
118 return (0); | |
119 } | |
120 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
121 audio_fd = -1; | |
122 | |
123 /* Set the function pointers */ | 106 /* Set the function pointers */ |
124 this->OpenAudio = DMA_OpenAudio; | 107 impl->DetectDevices = DMA_DetectDevices; |
125 this->WaitAudio = DMA_WaitAudio; | 108 impl->GetDeviceName = DMA_GetDeviceName; |
126 this->PlayAudio = DMA_PlayAudio; | 109 impl->OpenDevice = DMA_OpenDevice; |
127 this->GetAudioBuf = DMA_GetAudioBuf; | 110 impl->WaitDevice = DMA_WaitDevice; |
128 this->CloseAudio = DMA_CloseAudio; | 111 impl->PlayDevice = DMA_PlayDevice; |
129 | 112 impl->GetDeviceBuf = DMA_GetDeviceBuf; |
130 this->free = Audio_DeleteDevice; | 113 impl->CloseDevice = DMA_CloseDevice; |
131 | 114 |
132 return this; | 115 return 1; |
133 } | 116 } |
134 | 117 |
135 AudioBootStrap DMA_bootstrap = { | 118 AudioBootStrap DMA_bootstrap = { |
136 DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", | 119 DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", |
137 Audio_Available, Audio_CreateDevice | 120 DMA_Available, DMA_Init |
138 }; | 121 }; |
122 | |
123 | |
124 static int | |
125 DMA_DetectDevices(int iscapture) | |
126 { | |
127 return -1; /* !!! FIXME */ | |
128 } | |
129 | |
130 | |
131 static const char * | |
132 DMA_GetDeviceName(int index, int iscapture) | |
133 { | |
134 SDL_SetError("No such device"); /* !!! FIXME */ | |
135 return NULL; | |
136 } | |
137 | |
138 | |
139 static int | |
140 DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo) | |
141 { | |
142 int frag_spec; | |
143 int value; | |
144 | |
145 /* Close and then reopen the audio device */ | |
146 close(audio_fd); | |
147 audio_fd = open(audiodev, O_RDWR, 0); | |
148 if (audio_fd < 0) { | |
149 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | |
150 return (-1); | |
151 } | |
152 | |
153 /* Calculate the final parameters for this audio specification */ | |
154 SDL_CalculateAudioSpec(&this->spec); | |
155 | |
156 /* Determine the power of two of the fragment size */ | |
157 for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); | |
158 if ((0x01 << frag_spec) != this->spec.size) { | |
159 SDL_SetError("Fragment size must be a power of two"); | |
160 return (-1); | |
161 } | |
162 | |
163 /* Set the audio buffering parameters */ | |
164 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { | |
165 SDL_SetError("Couldn't set audio fragment spec"); | |
166 return (-1); | |
167 } | |
168 | |
169 /* Set the audio format */ | |
170 value = format; | |
171 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { | |
172 SDL_SetError("Couldn't set audio format"); | |
173 return (-1); | |
174 } | |
175 | |
176 /* Set mono or stereo audio */ | |
177 value = (this->spec.channels > 1); | |
178 if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) || | |
179 (value != stereo)) { | |
180 SDL_SetError("Couldn't set audio channels"); | |
181 return (-1); | |
182 } | |
183 | |
184 /* Set the DSP frequency */ | |
185 value = this->spec.freq; | |
186 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { | |
187 SDL_SetError("Couldn't set audio frequency"); | |
188 return (-1); | |
189 } | |
190 this->spec.freq = value; | |
191 | |
192 /* We successfully re-opened the audio */ | |
193 return (0); | |
194 } | |
195 | |
196 | |
197 | |
198 static int | |
199 open_device_internal(_THIS, const char *devname, int iscapture) | |
200 { | |
201 char audiodev[1024]; | |
202 int format; | |
203 int stereo; | |
204 int value; | |
205 SDL_AudioFormat test_format; | |
206 struct audio_buf_info info; | |
207 | |
208 /* Initialize all variables that we clean on shutdown */ | |
209 this->hidden = (struct SDL_PrivateAudioData *) | |
210 SDL_malloc((sizeof *this->hidden)); | |
211 if (this->hidden == NULL) { | |
212 SDL_OutOfMemory(); | |
213 return 0; | |
214 } | |
215 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
216 | |
217 /* !!! FIXME: handle devname */ | |
218 /* !!! FIXME: handle iscapture */ | |
219 | |
220 /* Open the audio device */ | |
221 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); | |
222 if (audio_fd < 0) { | |
223 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | |
224 return 0; | |
225 } | |
226 dma_buf = NULL; | |
227 ioctl(audio_fd, SNDCTL_DSP_RESET, 0); | |
228 | |
229 /* Get a list of supported hardware formats */ | |
230 if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { | |
231 SDL_SetError("Couldn't get audio format list"); | |
232 return 0; | |
233 } | |
234 | |
235 /* Try for a closest match on audio format */ | |
236 format = 0; | |
237 for (test_format = SDL_FirstAudioFormat(this->spec.format); | |
238 !format && test_format;) { | |
239 #ifdef DEBUG_AUDIO | |
240 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | |
241 #endif | |
242 switch (test_format) { | |
243 case AUDIO_U8: | |
244 if (value & AFMT_U8) { | |
245 format = AFMT_U8; | |
246 } | |
247 break; | |
248 case AUDIO_S8: | |
249 if (value & AFMT_S8) { | |
250 format = AFMT_S8; | |
251 } | |
252 break; | |
253 case AUDIO_S16LSB: | |
254 if (value & AFMT_S16_LE) { | |
255 format = AFMT_S16_LE; | |
256 } | |
257 break; | |
258 case AUDIO_S16MSB: | |
259 if (value & AFMT_S16_BE) { | |
260 format = AFMT_S16_BE; | |
261 } | |
262 break; | |
263 case AUDIO_U16LSB: | |
264 if (value & AFMT_U16_LE) { | |
265 format = AFMT_U16_LE; | |
266 } | |
267 break; | |
268 case AUDIO_U16MSB: | |
269 if (value & AFMT_U16_BE) { | |
270 format = AFMT_U16_BE; | |
271 } | |
272 break; | |
273 default: | |
274 format = 0; | |
275 break; | |
276 } | |
277 if (!format) { | |
278 test_format = SDL_NextAudioFormat(); | |
279 } | |
280 } | |
281 if (format == 0) { | |
282 SDL_SetError("Couldn't find any hardware audio formats"); | |
283 return 0; | |
284 } | |
285 this->spec.format = test_format; | |
286 | |
287 /* Set the audio format */ | |
288 value = format; | |
289 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { | |
290 SDL_SetError("Couldn't set audio format"); | |
291 return 0; | |
292 } | |
293 | |
294 /* Set mono or stereo audio (currently only two channels supported) */ | |
295 stereo = (this->spec.channels > 1); | |
296 ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo); | |
297 if (stereo) { | |
298 this->spec.channels = 2; | |
299 } else { | |
300 this->spec.channels = 1; | |
301 } | |
302 | |
303 /* Because some drivers don't allow setting the buffer size | |
304 after setting the format, we must re-open the audio device | |
305 once we know what format and channels are supported | |
306 */ | |
307 if (DMA_ReopenAudio(this, audiodev, format, stereo) < 0) { | |
308 /* Error is set by DMA_ReopenAudio() */ | |
309 return 0; | |
310 } | |
311 | |
312 /* Memory map the audio buffer */ | |
313 if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { | |
314 SDL_SetError("Couldn't get OSPACE parameters"); | |
315 return 0; | |
316 } | |
317 this->spec.size = info.fragsize; | |
318 this->spec.samples = this->spec.size / ((this->spec.format & 0xFF) / 8); | |
319 this->spec.samples /= this->spec.channels; | |
320 num_buffers = info.fragstotal; | |
321 dma_len = num_buffers * this->spec.size; | |
322 dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED, | |
323 audio_fd, 0); | |
324 if (dma_buf == MAP_FAILED) { | |
325 SDL_SetError("DMA memory map failed"); | |
326 dma_buf = NULL; | |
327 return 0; | |
328 } | |
329 SDL_memset(dma_buf, this->spec.silence, dma_len); | |
330 | |
331 /* Check to see if we need to use select() workaround */ | |
332 { | |
333 char *workaround; | |
334 workaround = SDL_getenv("SDL_DSP_NOSELECT"); | |
335 if (workaround) { | |
336 frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq; | |
337 next_frame = SDL_GetTicks() + frame_ticks; | |
338 } | |
339 } | |
340 | |
341 /* Trigger audio playback */ | |
342 value = 0; | |
343 ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value); | |
344 value = PCM_ENABLE_OUTPUT; | |
345 if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) { | |
346 SDL_SetError("Couldn't trigger audio output"); | |
347 return 0; | |
348 } | |
349 | |
350 /* Get the parent process id (we're the parent of the audio thread) */ | |
351 parent = getpid(); | |
352 | |
353 /* We're ready to rock and roll. :-) */ | |
354 return 1; | |
355 } | |
356 | |
357 static int | |
358 DMA_OpenDevice(_THIS, const char *devname, int iscapture) | |
359 { | |
360 int retval = open_device_internal(this, devname, iscapture); | |
361 if (!retval) | |
362 DMA_CloseDevice(this); /* !!! FIXME: do this at higher level. */ | |
363 return retval; | |
364 } | |
365 | |
366 | |
367 | |
139 | 368 |
140 /* This function waits until it is possible to write a full sound buffer */ | 369 /* This function waits until it is possible to write a full sound buffer */ |
141 static void | 370 static void |
142 DMA_WaitAudio(_THIS) | 371 DMA_WaitDevice(_THIS) |
143 { | 372 { |
144 fd_set fdset; | 373 fd_set fdset; |
145 | 374 |
146 /* Check to see if the thread-parent process is still alive */ | 375 /* Check to see if the thread-parent process is still alive */ |
147 { | 376 { |
187 the user know what happened. | 416 the user know what happened. |
188 */ | 417 */ |
189 fprintf(stderr, "SDL: %s\n", message); | 418 fprintf(stderr, "SDL: %s\n", message); |
190 #ifdef AUDIO_OSPACE_HACK | 419 #ifdef AUDIO_OSPACE_HACK |
191 /* We may be able to use GET_OSPACE trick */ | 420 /* We may be able to use GET_OSPACE trick */ |
192 frame_ticks = (float) (this->spec->samples * 1000) / | 421 frame_ticks = (float) (this->spec.samples * 1000) / |
193 this->spec->freq; | 422 this->spec.freq; |
194 next_frame = SDL_GetTicks() + frame_ticks; | 423 next_frame = SDL_GetTicks() + frame_ticks; |
195 #else | 424 #else |
196 this->enabled = 0; | 425 this->enabled = 0; |
197 /* Don't try to close - may hang */ | 426 /* Don't try to close - may hang */ |
198 audio_fd = -1; | 427 audio_fd = -1; |
206 #endif | 435 #endif |
207 } | 436 } |
208 } | 437 } |
209 | 438 |
210 static void | 439 static void |
211 DMA_PlayAudio(_THIS) | 440 DMA_PlayDevice(_THIS) |
212 { | 441 { |
213 /* If timer synchronization is enabled, set the next write frame */ | 442 /* If timer synchronization is enabled, set the next write frame */ |
214 if (frame_ticks) { | 443 if (frame_ticks) { |
215 next_frame += frame_ticks; | 444 next_frame += frame_ticks; |
216 } | 445 } |
217 return; | 446 return; |
218 } | 447 } |
219 | 448 |
220 static Uint8 * | 449 static Uint8 * |
221 DMA_GetAudioBuf(_THIS) | 450 DMA_GetDeviceBuf(_THIS) |
222 { | 451 { |
223 count_info info; | 452 count_info info; |
224 int playing; | 453 int playing; |
225 int filling; | 454 int filling; |
226 | 455 |
242 filling = (playing + 1) % num_buffers; | 471 filling = (playing + 1) % num_buffers; |
243 return (dma_buf + (filling * this->spec.size)); | 472 return (dma_buf + (filling * this->spec.size)); |
244 } | 473 } |
245 | 474 |
246 static void | 475 static void |
247 DMA_CloseAudio(_THIS) | 476 DMA_CloseDevice(_THIS) |
248 { | 477 { |
249 if (dma_buf != NULL) { | 478 if (this->hidden != NULL) { |
250 munmap(dma_buf, dma_len); | 479 if (dma_buf != NULL) { |
251 dma_buf = NULL; | 480 munmap(dma_buf, dma_len); |
252 } | 481 dma_buf = NULL; |
253 if (audio_fd >= 0) { | 482 } |
254 close(audio_fd); | 483 if (audio_fd >= 0) { |
255 audio_fd = -1; | 484 close(audio_fd); |
256 } | 485 audio_fd = -1; |
257 } | 486 } |
258 | 487 SDL_free(this->hidden); |
259 static int | 488 this->hidden = NULL; |
260 DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, | 489 } |
261 SDL_AudioSpec * spec) | |
262 { | |
263 int frag_spec; | |
264 int value; | |
265 | |
266 /* Close and then reopen the audio device */ | |
267 close(audio_fd); | |
268 audio_fd = open(audiodev, O_RDWR, 0); | |
269 if (audio_fd < 0) { | |
270 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | |
271 return (-1); | |
272 } | |
273 | |
274 /* Calculate the final parameters for this audio specification */ | |
275 SDL_CalculateAudioSpec(spec); | |
276 | |
277 /* Determine the power of two of the fragment size */ | |
278 for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); | |
279 if ((0x01 << frag_spec) != spec->size) { | |
280 SDL_SetError("Fragment size must be a power of two"); | |
281 return (-1); | |
282 } | |
283 | |
284 /* Set the audio buffering parameters */ | |
285 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { | |
286 SDL_SetError("Couldn't set audio fragment spec"); | |
287 return (-1); | |
288 } | |
289 | |
290 /* Set the audio format */ | |
291 value = format; | |
292 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { | |
293 SDL_SetError("Couldn't set audio format"); | |
294 return (-1); | |
295 } | |
296 | |
297 /* Set mono or stereo audio */ | |
298 value = (spec->channels > 1); | |
299 if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) || | |
300 (value != stereo)) { | |
301 SDL_SetError("Couldn't set audio channels"); | |
302 return (-1); | |
303 } | |
304 | |
305 /* Set the DSP frequency */ | |
306 value = spec->freq; | |
307 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { | |
308 SDL_SetError("Couldn't set audio frequency"); | |
309 return (-1); | |
310 } | |
311 spec->freq = value; | |
312 | |
313 /* We successfully re-opened the audio */ | |
314 return (0); | |
315 } | |
316 | |
317 static int | |
318 DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) | |
319 { | |
320 char audiodev[1024]; | |
321 int format; | |
322 int stereo; | |
323 int value; | |
324 SDL_AudioFormat test_format; | |
325 struct audio_buf_info info; | |
326 | |
327 /* Reset the timer synchronization flag */ | |
328 frame_ticks = 0.0; | |
329 | |
330 /* Open the audio device */ | |
331 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); | |
332 if (audio_fd < 0) { | |
333 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | |
334 return (-1); | |
335 } | |
336 dma_buf = NULL; | |
337 ioctl(audio_fd, SNDCTL_DSP_RESET, 0); | |
338 | |
339 /* Get a list of supported hardware formats */ | |
340 if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { | |
341 SDL_SetError("Couldn't get audio format list"); | |
342 return (-1); | |
343 } | |
344 | |
345 /* Try for a closest match on audio format */ | |
346 format = 0; | |
347 for (test_format = SDL_FirstAudioFormat(spec->format); | |
348 !format && test_format;) { | |
349 #ifdef DEBUG_AUDIO | |
350 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); | |
351 #endif | |
352 switch (test_format) { | |
353 case AUDIO_U8: | |
354 if (value & AFMT_U8) { | |
355 format = AFMT_U8; | |
356 } | |
357 break; | |
358 case AUDIO_S8: | |
359 if (value & AFMT_S8) { | |
360 format = AFMT_S8; | |
361 } | |
362 break; | |
363 case AUDIO_S16LSB: | |
364 if (value & AFMT_S16_LE) { | |
365 format = AFMT_S16_LE; | |
366 } | |
367 break; | |
368 case AUDIO_S16MSB: | |
369 if (value & AFMT_S16_BE) { | |
370 format = AFMT_S16_BE; | |
371 } | |
372 break; | |
373 case AUDIO_U16LSB: | |
374 if (value & AFMT_U16_LE) { | |
375 format = AFMT_U16_LE; | |
376 } | |
377 break; | |
378 case AUDIO_U16MSB: | |
379 if (value & AFMT_U16_BE) { | |
380 format = AFMT_U16_BE; | |
381 } | |
382 break; | |
383 default: | |
384 format = 0; | |
385 break; | |
386 } | |
387 if (!format) { | |
388 test_format = SDL_NextAudioFormat(); | |
389 } | |
390 } | |
391 if (format == 0) { | |
392 SDL_SetError("Couldn't find any hardware audio formats"); | |
393 return (-1); | |
394 } | |
395 spec->format = test_format; | |
396 | |
397 /* Set the audio format */ | |
398 value = format; | |
399 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { | |
400 SDL_SetError("Couldn't set audio format"); | |
401 return (-1); | |
402 } | |
403 | |
404 /* Set mono or stereo audio (currently only two channels supported) */ | |
405 stereo = (spec->channels > 1); | |
406 ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo); | |
407 if (stereo) { | |
408 spec->channels = 2; | |
409 } else { | |
410 spec->channels = 1; | |
411 } | |
412 | |
413 /* Because some drivers don't allow setting the buffer size | |
414 after setting the format, we must re-open the audio device | |
415 once we know what format and channels are supported | |
416 */ | |
417 if (DMA_ReopenAudio(this, audiodev, format, stereo, spec) < 0) { | |
418 /* Error is set by DMA_ReopenAudio() */ | |
419 return (-1); | |
420 } | |
421 | |
422 /* Memory map the audio buffer */ | |
423 if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { | |
424 SDL_SetError("Couldn't get OSPACE parameters"); | |
425 return (-1); | |
426 } | |
427 spec->size = info.fragsize; | |
428 spec->samples = spec->size / ((spec->format & 0xFF) / 8); | |
429 spec->samples /= spec->channels; | |
430 num_buffers = info.fragstotal; | |
431 dma_len = num_buffers * spec->size; | |
432 dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED, | |
433 audio_fd, 0); | |
434 if (dma_buf == MAP_FAILED) { | |
435 SDL_SetError("DMA memory map failed"); | |
436 dma_buf = NULL; | |
437 return (-1); | |
438 } | |
439 SDL_memset(dma_buf, spec->silence, dma_len); | |
440 | |
441 /* Check to see if we need to use select() workaround */ | |
442 { | |
443 char *workaround; | |
444 workaround = SDL_getenv("SDL_DSP_NOSELECT"); | |
445 if (workaround) { | |
446 frame_ticks = (float) (spec->samples * 1000) / spec->freq; | |
447 next_frame = SDL_GetTicks() + frame_ticks; | |
448 } | |
449 } | |
450 | |
451 /* Trigger audio playback */ | |
452 value = 0; | |
453 ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value); | |
454 value = PCM_ENABLE_OUTPUT; | |
455 if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) { | |
456 SDL_SetError("Couldn't trigger audio output"); | |
457 return (-1); | |
458 } | |
459 | |
460 /* Get the parent process id (we're the parent of the audio thread) */ | |
461 parent = getpid(); | |
462 | |
463 /* We're ready to rock and roll. :-) */ | |
464 return (0); | |
465 } | 490 } |
466 | 491 |
467 /* vi: set ts=4 sw=4 expandtab: */ | 492 /* vi: set ts=4 sw=4 expandtab: */ |