comparison src/audio/dma/SDL_dmaaudio.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
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() */
55 57
56 /* The tag name used by DMA audio */ 58 /* The tag name used by DMA audio */
57 #define DMA_DRIVER_NAME "dma" 59 #define DMA_DRIVER_NAME "dma"
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_INPUT (O_RDWR|O_NONBLOCK)
61 63 #define OPEN_FLAGS_OUTPUT (O_RDWR|O_NONBLOCK)
62 /* Audio driver functions */ 64
63 static int DMA_OpenAudio(_THIS, SDL_AudioSpec * spec); 65 static char **outputDevices = NULL;
64 static void DMA_WaitAudio(_THIS); 66 static int outputDeviceCount = 0;
65 static void DMA_PlayAudio(_THIS); 67 static char **inputDevices = NULL;
66 static Uint8 *DMA_GetAudioBuf(_THIS); 68 static int inputDeviceCount = 0;
67 static void DMA_CloseAudio(_THIS);
68
69 /* Audio driver bootstrap functions */
70 69
71 static int 70 static int
72 Audio_Available(void) 71 test_for_mmap(int fd)
73 { 72 {
74 int available; 73 int caps = 0;
75 int fd; 74 struct audio_buf_info info;
76 75 if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
77 available = 0; 76 (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
78 77 (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0))
79 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); 78 {
80 if (fd >= 0) { 79 size_t len = info.fragstotal * info.fragsize;
81 int caps; 80 Uint8 *buf = (Uint8 *) mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
82 struct audio_buf_info info; 81 if (buf != MAP_FAILED) {
83 82 munmap(buf, len);
84 if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) && 83 return 1;
85 (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) && 84 }
86 (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) { 85 }
87 available = 1; 86 return 0;
88 } 87 }
89 close(fd); 88
90 } 89
91 return (available); 90 static inline void
92 } 91 free_device_list(char ***devs, int *count)
92 {
93 SDL_FreeUnixAudioDevices(devs, count);
94 }
95
96 static inline void
97 build_device_list(int iscapture, char ***devs, int *count)
98 {
99 const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
100 free_device_list(devs, count);
101 SDL_EnumUnixAudioDevices(flags, 0, test_for_mmap, devs, count);
102 }
103
104 static inline void
105 build_device_lists(void)
106 {
107 build_device_list(0, &outputDevices, &outputDeviceCount);
108 build_device_list(1, &inputDevices, &inputDeviceCount);
109 }
110
111
112 static inline void
113 free_device_lists(void)
114 {
115 free_device_list(&outputDevices, &outputDeviceCount);
116 free_device_list(&inputDevices, &inputDeviceCount);
117 }
118
119
120 static void DMA_Deinitialize(void)
121 {
122 free_device_lists();
123 }
124
125 static int
126 DMA_DetectDevices(int iscapture)
127 {
128 if (iscapture) {
129 build_device_list(1, &inputDevices, &inputDeviceCount);
130 return inputDeviceCount;
131 } else {
132 build_device_list(0, &outputDevices, &outputDeviceCount);
133 return outputDeviceCount;
134 }
135
136 return 0; /* shouldn't ever hit this. */
137 }
138
139
140 static const char *
141 DMA_GetDeviceName(int index, int iscapture)
142 {
143 if ((iscapture) && (index < inputDeviceCount)) {
144 return inputDevices[index];
145 } else if ((!iscapture) && (index < outputDeviceCount)) {
146 return outputDevices[index];
147 }
148
149 SDL_SetError("No such device");
150 return NULL;
151 }
152
153
154 static int
155 DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo)
156 {
157 int frag_spec;
158 int value;
159
160 /* Close and then reopen the audio device */
161 close(audio_fd);
162 audio_fd = open(audiodev, O_RDWR, 0);
163 if (audio_fd < 0) {
164 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
165 return (-1);
166 }
167
168 /* Calculate the final parameters for this audio specification */
169 SDL_CalculateAudioSpec(&this->spec);
170
171 /* Determine the power of two of the fragment size */
172 for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
173 if ((0x01 << frag_spec) != this->spec.size) {
174 SDL_SetError("Fragment size must be a power of two");
175 return (-1);
176 }
177
178 /* Set the audio buffering parameters */
179 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
180 SDL_SetError("Couldn't set audio fragment spec");
181 return (-1);
182 }
183
184 /* Set the audio format */
185 value = format;
186 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
187 SDL_SetError("Couldn't set audio format");
188 return (-1);
189 }
190
191 /* Set mono or stereo audio */
192 value = (this->spec.channels > 1);
193 if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
194 (value != stereo)) {
195 SDL_SetError("Couldn't set audio channels");
196 return (-1);
197 }
198
199 /* Set the DSP frequency */
200 value = this->spec.freq;
201 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
202 SDL_SetError("Couldn't set audio frequency");
203 return (-1);
204 }
205 this->spec.freq = value;
206
207 /* We successfully re-opened the audio */
208 return (0);
209 }
210
93 211
94 static void 212 static void
95 Audio_DeleteDevice(SDL_AudioDevice * device) 213 DMA_CloseDevice(_THIS)
96 { 214 {
97 SDL_free(device->hidden); 215 if (this->hidden != NULL) {
98 SDL_free(device); 216 if (dma_buf != NULL) {
99 } 217 munmap(dma_buf, dma_len);
100 218 dma_buf = NULL;
101 static SDL_AudioDevice * 219 }
102 Audio_CreateDevice(int devindex) 220 if (audio_fd >= 0) {
103 { 221 close(audio_fd);
104 SDL_AudioDevice *this; 222 audio_fd = -1;
223 }
224 SDL_free(this->hidden);
225 this->hidden = NULL;
226 }
227 }
228
229
230 static int
231 DMA_OpenDevice(_THIS, const char *devname, int iscapture)
232 {
233 const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
234 int format;
235 int stereo;
236 int value;
237 SDL_AudioFormat test_format;
238 struct audio_buf_info info;
239
240 /* We don't care what the devname is...we'll try to open anything. */
241 /* ...but default to first name in the list... */
242 if (devname == NULL) {
243 if ( ((iscapture) && (inputDeviceCount == 0)) ||
244 ((!iscapture) && (outputDeviceCount == 0)) ) {
245 SDL_SetError("No such audio device");
246 return 0;
247 }
248 devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
249 }
105 250
106 /* Initialize all variables that we clean on shutdown */ 251 /* Initialize all variables that we clean on shutdown */
107 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); 252 this->hidden = (struct SDL_PrivateAudioData *)
108 if (this) { 253 SDL_malloc((sizeof *this->hidden));
109 SDL_memset(this, 0, (sizeof *this)); 254 if (this->hidden == NULL) {
110 this->hidden = (struct SDL_PrivateAudioData *)
111 SDL_malloc((sizeof *this->hidden));
112 }
113 if ((this == NULL) || (this->hidden == NULL)) {
114 SDL_OutOfMemory(); 255 SDL_OutOfMemory();
115 if (this) { 256 return 0;
116 SDL_free(this);
117 }
118 return (0);
119 } 257 }
120 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 258 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
121 audio_fd = -1; 259
122 260 /* Open the audio device */
123 /* Set the function pointers */ 261 audio_fd = open(devname, flags, 0);
124 this->OpenAudio = DMA_OpenAudio; 262 if (audio_fd < 0) {
125 this->WaitAudio = DMA_WaitAudio; 263 DMA_CloseDevice(this);
126 this->PlayAudio = DMA_PlayAudio; 264 SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
127 this->GetAudioBuf = DMA_GetAudioBuf; 265 return 0;
128 this->CloseAudio = DMA_CloseAudio; 266 }
129 267 dma_buf = NULL;
130 this->free = Audio_DeleteDevice; 268 ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
131 269
132 return this; 270 /* Get a list of supported hardware formats */
133 } 271 if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
134 272 DMA_CloseDevice(this);
135 AudioBootStrap DMA_bootstrap = { 273 SDL_SetError("Couldn't get audio format list");
136 DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", 274 return 0;
137 Audio_Available, Audio_CreateDevice 275 }
138 }; 276
277 /* Try for a closest match on audio format */
278 format = 0;
279 for (test_format = SDL_FirstAudioFormat(this->spec.format);
280 !format && test_format;) {
281 #ifdef DEBUG_AUDIO
282 fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
283 #endif
284 switch (test_format) {
285 case AUDIO_U8:
286 if (value & AFMT_U8) {
287 format = AFMT_U8;
288 }
289 break;
290 case AUDIO_S8:
291 if (value & AFMT_S8) {
292 format = AFMT_S8;
293 }
294 break;
295 case AUDIO_S16LSB:
296 if (value & AFMT_S16_LE) {
297 format = AFMT_S16_LE;
298 }
299 break;
300 case AUDIO_S16MSB:
301 if (value & AFMT_S16_BE) {
302 format = AFMT_S16_BE;
303 }
304 break;
305 case AUDIO_U16LSB:
306 if (value & AFMT_U16_LE) {
307 format = AFMT_U16_LE;
308 }
309 break;
310 case AUDIO_U16MSB:
311 if (value & AFMT_U16_BE) {
312 format = AFMT_U16_BE;
313 }
314 break;
315 default:
316 format = 0;
317 break;
318 }
319 if (!format) {
320 test_format = SDL_NextAudioFormat();
321 }
322 }
323 if (format == 0) {
324 DMA_CloseDevice(this);
325 SDL_SetError("Couldn't find any hardware audio formats");
326 return 0;
327 }
328 this->spec.format = test_format;
329
330 /* Set the audio format */
331 value = format;
332 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
333 DMA_CloseDevice(this);
334 SDL_SetError("Couldn't set audio format");
335 return 0;
336 }
337
338 /* Set mono or stereo audio (currently only two channels supported) */
339 stereo = (this->spec.channels > 1);
340 ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
341 if (stereo) {
342 this->spec.channels = 2;
343 } else {
344 this->spec.channels = 1;
345 }
346
347 /* Because some drivers don't allow setting the buffer size
348 after setting the format, we must re-open the audio device
349 once we know what format and channels are supported
350 */
351 if (DMA_ReopenAudio(this, devname, format, stereo) < 0) {
352 DMA_CloseDevice(this);
353 /* Error is set by DMA_ReopenAudio() */
354 return 0;
355 }
356
357 /* Memory map the audio buffer */
358 if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
359 DMA_CloseDevice(this);
360 SDL_SetError("Couldn't get OSPACE parameters");
361 return 0;
362 }
363 this->spec.size = info.fragsize;
364 this->spec.samples = this->spec.size / ((this->spec.format & 0xFF) / 8);
365 this->spec.samples /= this->spec.channels;
366 num_buffers = info.fragstotal;
367 dma_len = num_buffers * this->spec.size;
368 dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
369 audio_fd, 0);
370 if (dma_buf == MAP_FAILED) {
371 DMA_CloseDevice(this);
372 SDL_SetError("DMA memory map failed");
373 dma_buf = NULL;
374 return 0;
375 }
376 SDL_memset(dma_buf, this->spec.silence, dma_len);
377
378 /* Check to see if we need to use select() workaround */
379 {
380 char *workaround;
381 workaround = SDL_getenv("SDL_DSP_NOSELECT");
382 if (workaround) {
383 frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
384 next_frame = SDL_GetTicks() + frame_ticks;
385 }
386 }
387
388 /* Trigger audio playback */
389 value = 0;
390 ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
391 value = PCM_ENABLE_OUTPUT;
392 if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) {
393 DMA_CloseDevice(this);
394 SDL_SetError("Couldn't trigger audio output");
395 return 0;
396 }
397
398 /* Get the parent process id (we're the parent of the audio thread) */
399 parent = getpid();
400
401 /* We're ready to rock and roll. :-) */
402 return 1;
403 }
404
139 405
140 /* This function waits until it is possible to write a full sound buffer */ 406 /* This function waits until it is possible to write a full sound buffer */
141 static void 407 static void
142 DMA_WaitAudio(_THIS) 408 DMA_WaitDevice(_THIS)
143 { 409 {
144 fd_set fdset; 410 fd_set fdset;
145 411
146 /* Check to see if the thread-parent process is still alive */ 412 /* Check to see if the thread-parent process is still alive */
147 { 413 {
187 the user know what happened. 453 the user know what happened.
188 */ 454 */
189 fprintf(stderr, "SDL: %s\n", message); 455 fprintf(stderr, "SDL: %s\n", message);
190 #ifdef AUDIO_OSPACE_HACK 456 #ifdef AUDIO_OSPACE_HACK
191 /* We may be able to use GET_OSPACE trick */ 457 /* We may be able to use GET_OSPACE trick */
192 frame_ticks = (float) (this->spec->samples * 1000) / 458 frame_ticks = (float) (this->spec.samples * 1000) /
193 this->spec->freq; 459 this->spec.freq;
194 next_frame = SDL_GetTicks() + frame_ticks; 460 next_frame = SDL_GetTicks() + frame_ticks;
195 #else 461 #else
196 this->enabled = 0; 462 this->enabled = 0;
197 /* Don't try to close - may hang */ 463 /* Don't try to close - may hang */
198 audio_fd = -1; 464 audio_fd = -1;
206 #endif 472 #endif
207 } 473 }
208 } 474 }
209 475
210 static void 476 static void
211 DMA_PlayAudio(_THIS) 477 DMA_PlayDevice(_THIS)
212 { 478 {
213 /* If timer synchronization is enabled, set the next write frame */ 479 /* If timer synchronization is enabled, set the next write frame */
214 if (frame_ticks) { 480 if (frame_ticks) {
215 next_frame += frame_ticks; 481 next_frame += frame_ticks;
216 } 482 }
217 return; 483 return;
218 } 484 }
219 485
220 static Uint8 * 486 static Uint8 *
221 DMA_GetAudioBuf(_THIS) 487 DMA_GetDeviceBuf(_THIS)
222 { 488 {
223 count_info info; 489 count_info info;
224 int playing; 490 int playing;
225 int filling; 491 int filling;
226 492
241 playing = info.ptr / this->spec.size; 507 playing = info.ptr / this->spec.size;
242 filling = (playing + 1) % num_buffers; 508 filling = (playing + 1) % num_buffers;
243 return (dma_buf + (filling * this->spec.size)); 509 return (dma_buf + (filling * this->spec.size));
244 } 510 }
245 511
246 static void
247 DMA_CloseAudio(_THIS)
248 {
249 if (dma_buf != NULL) {
250 munmap(dma_buf, dma_len);
251 dma_buf = NULL;
252 }
253 if (audio_fd >= 0) {
254 close(audio_fd);
255 audio_fd = -1;
256 }
257 }
258 512
259 static int 513 static int
260 DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, 514 DMA_Init(SDL_AudioDriverImpl *impl)
261 SDL_AudioSpec * spec) 515 {
262 { 516 /* Set the function pointers */
263 int frag_spec; 517 impl->DetectDevices = DMA_DetectDevices;
264 int value; 518 impl->GetDeviceName = DMA_GetDeviceName;
265 519 impl->OpenDevice = DMA_OpenDevice;
266 /* Close and then reopen the audio device */ 520 impl->WaitDevice = DMA_WaitDevice;
267 close(audio_fd); 521 impl->PlayDevice = DMA_PlayDevice;
268 audio_fd = open(audiodev, O_RDWR, 0); 522 impl->GetDeviceBuf = DMA_GetDeviceBuf;
269 if (audio_fd < 0) { 523 impl->CloseDevice = DMA_CloseDevice;
270 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); 524 impl->Deinitialize = DMA_Deinitialize;
271 return (-1); 525
272 } 526 build_device_lists();
273 527 return 1;
274 /* Calculate the final parameters for this audio specification */ 528 }
275 SDL_CalculateAudioSpec(spec); 529
276 530 AudioBootStrap DMA_bootstrap = {
277 /* Determine the power of two of the fragment size */ 531 DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", DMA_Init, 0
278 for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); 532 };
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 }
466 533
467 /* vi: set ts=4 sw=4 expandtab: */ 534 /* vi: set ts=4 sw=4 expandtab: */