diff options
Diffstat (limited to 'apps/plugins/sdl/src/audio/bsd')
-rw-r--r-- | apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.c | 404 | ||||
-rw-r--r-- | apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.h | 58 |
2 files changed, 462 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.c b/apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.c new file mode 100644 index 0000000000..e5e0d9480a --- /dev/null +++ b/apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* | ||
25 | * Driver for native OpenBSD/NetBSD audio(4). | ||
26 | * vedge@vedge.com.ar. | ||
27 | */ | ||
28 | |||
29 | #include <errno.h> | ||
30 | #include <unistd.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <sys/time.h> | ||
33 | #include <sys/ioctl.h> | ||
34 | #include <sys/stat.h> | ||
35 | #include <sys/types.h> | ||
36 | #include <sys/audioio.h> | ||
37 | |||
38 | #include "SDL_timer.h" | ||
39 | #include "SDL_audio.h" | ||
40 | #include "../SDL_audiomem.h" | ||
41 | #include "../SDL_audio_c.h" | ||
42 | #include "../SDL_audiodev_c.h" | ||
43 | #include "SDL_bsdaudio.h" | ||
44 | |||
45 | /* The tag name used by NetBSD/OpenBSD audio */ | ||
46 | #ifdef __NetBSD__ | ||
47 | #define BSD_AUDIO_DRIVER_NAME "netbsd" | ||
48 | #define BSD_AUDIO_DRIVER_DESC "Native NetBSD audio" | ||
49 | #else | ||
50 | #define BSD_AUDIO_DRIVER_NAME "openbsd" | ||
51 | #define BSD_AUDIO_DRIVER_DESC "Native OpenBSD audio" | ||
52 | #endif | ||
53 | |||
54 | /* Open the audio device for playback, and don't block if busy */ | ||
55 | /* #define USE_BLOCKING_WRITES */ | ||
56 | |||
57 | /* Use timer for synchronization */ | ||
58 | /* #define USE_TIMER_SYNC */ | ||
59 | |||
60 | /* #define DEBUG_AUDIO */ | ||
61 | /* #define DEBUG_AUDIO_STREAM */ | ||
62 | |||
63 | #ifdef USE_BLOCKING_WRITES | ||
64 | #define OPEN_FLAGS O_WRONLY | ||
65 | #else | ||
66 | #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) | ||
67 | #endif | ||
68 | |||
69 | /* Audio driver functions */ | ||
70 | static void OBSD_WaitAudio(_THIS); | ||
71 | static int OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec); | ||
72 | static void OBSD_PlayAudio(_THIS); | ||
73 | static Uint8 *OBSD_GetAudioBuf(_THIS); | ||
74 | static void OBSD_CloseAudio(_THIS); | ||
75 | |||
76 | #ifdef DEBUG_AUDIO | ||
77 | static void OBSD_Status(_THIS); | ||
78 | #endif | ||
79 | |||
80 | /* Audio driver bootstrap functions */ | ||
81 | |||
82 | static int | ||
83 | Audio_Available(void) | ||
84 | { | ||
85 | int fd; | ||
86 | int available; | ||
87 | |||
88 | available = 0; | ||
89 | fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); | ||
90 | if(fd >= 0) { | ||
91 | available = 1; | ||
92 | close(fd); | ||
93 | } | ||
94 | return(available); | ||
95 | } | ||
96 | |||
97 | static void | ||
98 | Audio_DeleteDevice(SDL_AudioDevice *device) | ||
99 | { | ||
100 | SDL_free(device->hidden); | ||
101 | SDL_free(device); | ||
102 | } | ||
103 | |||
104 | static SDL_AudioDevice | ||
105 | *Audio_CreateDevice(int devindex) | ||
106 | { | ||
107 | SDL_AudioDevice *this; | ||
108 | |||
109 | /* Initialize all variables that we clean on shutdown */ | ||
110 | this = (SDL_AudioDevice*)SDL_malloc(sizeof(SDL_AudioDevice)); | ||
111 | if(this) { | ||
112 | SDL_memset(this, 0, (sizeof *this)); | ||
113 | this->hidden = | ||
114 | (struct SDL_PrivateAudioData*)SDL_malloc((sizeof *this->hidden)); | ||
115 | } | ||
116 | if((this == NULL) || (this->hidden == NULL)) { | ||
117 | SDL_OutOfMemory(); | ||
118 | if(this) SDL_free(this); | ||
119 | return(0); | ||
120 | } | ||
121 | SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | ||
122 | audio_fd = -1; | ||
123 | |||
124 | /* Set the function pointers */ | ||
125 | this->OpenAudio = OBSD_OpenAudio; | ||
126 | this->WaitAudio = OBSD_WaitAudio; | ||
127 | this->PlayAudio = OBSD_PlayAudio; | ||
128 | this->GetAudioBuf = OBSD_GetAudioBuf; | ||
129 | this->CloseAudio = OBSD_CloseAudio; | ||
130 | |||
131 | this->free = Audio_DeleteDevice; | ||
132 | |||
133 | return this; | ||
134 | } | ||
135 | |||
136 | AudioBootStrap BSD_AUDIO_bootstrap = { | ||
137 | BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC, | ||
138 | Audio_Available, Audio_CreateDevice | ||
139 | }; | ||
140 | |||
141 | /* This function waits until it is possible to write a full sound buffer */ | ||
142 | static void | ||
143 | OBSD_WaitAudio(_THIS) | ||
144 | { | ||
145 | #ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */ | ||
146 | /* See if we need to use timed audio synchronization */ | ||
147 | if ( frame_ticks ) { | ||
148 | /* Use timer for general audio synchronization */ | ||
149 | Sint32 ticks; | ||
150 | |||
151 | ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS; | ||
152 | if ( ticks > 0 ) { | ||
153 | SDL_Delay(ticks); | ||
154 | } | ||
155 | } else { | ||
156 | /* Use select() for audio synchronization */ | ||
157 | fd_set fdset; | ||
158 | struct timeval timeout; | ||
159 | |||
160 | FD_ZERO(&fdset); | ||
161 | FD_SET(audio_fd, &fdset); | ||
162 | timeout.tv_sec = 10; | ||
163 | timeout.tv_usec = 0; | ||
164 | #ifdef DEBUG_AUDIO | ||
165 | fprintf(stderr, "Waiting for audio to get ready\n"); | ||
166 | #endif | ||
167 | if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) { | ||
168 | const char *message = | ||
169 | "Audio timeout - buggy audio driver? (disabled)"; | ||
170 | /* In general we should never print to the screen, | ||
171 | but in this case we have no other way of letting | ||
172 | the user know what happened. | ||
173 | */ | ||
174 | fprintf(stderr, "SDL: %s\n", message); | ||
175 | this->enabled = 0; | ||
176 | /* Don't try to close - may hang */ | ||
177 | audio_fd = -1; | ||
178 | #ifdef DEBUG_AUDIO | ||
179 | fprintf(stderr, "Done disabling audio\n"); | ||
180 | #endif | ||
181 | } | ||
182 | #ifdef DEBUG_AUDIO | ||
183 | fprintf(stderr, "Ready!\n"); | ||
184 | #endif | ||
185 | } | ||
186 | #endif /* !USE_BLOCKING_WRITES */ | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | OBSD_PlayAudio(_THIS) | ||
191 | { | ||
192 | int written, p=0; | ||
193 | |||
194 | /* Write the audio data, checking for EAGAIN on broken audio drivers */ | ||
195 | do { | ||
196 | written = write(audio_fd, &mixbuf[p], mixlen-p); | ||
197 | if (written>0) | ||
198 | p += written; | ||
199 | if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) | ||
200 | { | ||
201 | /* Non recoverable error has occurred. It should be reported!!! */ | ||
202 | perror("audio"); | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | if ( p < written || ((written < 0) && ((errno == 0) || (errno == EAGAIN))) ) { | ||
207 | SDL_Delay(1); /* Let a little CPU time go by */ | ||
208 | } | ||
209 | } while ( p < written ); | ||
210 | |||
211 | /* If timer synchronization is enabled, set the next write frame */ | ||
212 | if ( frame_ticks ) { | ||
213 | next_frame += frame_ticks; | ||
214 | } | ||
215 | |||
216 | /* If we couldn't write, assume fatal error for now */ | ||
217 | if ( written < 0 ) { | ||
218 | this->enabled = 0; | ||
219 | } | ||
220 | #ifdef DEBUG_AUDIO | ||
221 | fprintf(stderr, "Wrote %d bytes of audio data\n", written); | ||
222 | #endif | ||
223 | } | ||
224 | |||
225 | static Uint8 | ||
226 | *OBSD_GetAudioBuf(_THIS) | ||
227 | { | ||
228 | return(mixbuf); | ||
229 | } | ||
230 | |||
231 | static void | ||
232 | OBSD_CloseAudio(_THIS) | ||
233 | { | ||
234 | if(mixbuf != NULL) { | ||
235 | SDL_FreeAudioMem(mixbuf); | ||
236 | mixbuf = NULL; | ||
237 | } | ||
238 | if(audio_fd >= 0) { | ||
239 | close(audio_fd); | ||
240 | audio_fd = -1; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | #ifdef DEBUG_AUDIO | ||
245 | void | ||
246 | OBSD_Status(_THIS) | ||
247 | { | ||
248 | audio_info_t info; | ||
249 | |||
250 | if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) { | ||
251 | fprintf(stderr,"AUDIO_GETINFO failed.\n"); | ||
252 | return; | ||
253 | } | ||
254 | |||
255 | fprintf(stderr,"\n" | ||
256 | "[play/record info]\n" | ||
257 | "buffer size : %d bytes\n" | ||
258 | "sample rate : %i Hz\n" | ||
259 | "channels : %i\n" | ||
260 | "precision : %i-bit\n" | ||
261 | "encoding : 0x%x\n" | ||
262 | "seek : %i\n" | ||
263 | "sample count : %i\n" | ||
264 | "EOF count : %i\n" | ||
265 | "paused : %s\n" | ||
266 | "error occured : %s\n" | ||
267 | "waiting : %s\n" | ||
268 | "active : %s\n" | ||
269 | "", | ||
270 | info.play.buffer_size, | ||
271 | info.play.sample_rate, | ||
272 | info.play.channels, | ||
273 | info.play.precision, | ||
274 | info.play.encoding, | ||
275 | info.play.seek, | ||
276 | info.play.samples, | ||
277 | info.play.eof, | ||
278 | info.play.pause ? "yes" : "no", | ||
279 | info.play.error ? "yes" : "no", | ||
280 | info.play.waiting ? "yes" : "no", | ||
281 | info.play.active ? "yes": "no"); | ||
282 | |||
283 | fprintf(stderr,"\n" | ||
284 | "[audio info]\n" | ||
285 | "monitor_gain : %i\n" | ||
286 | "hw block size : %d bytes\n" | ||
287 | "hi watermark : %i\n" | ||
288 | "lo watermark : %i\n" | ||
289 | "audio mode : %s\n" | ||
290 | "", | ||
291 | info.monitor_gain, | ||
292 | info.blocksize, | ||
293 | info.hiwat, info.lowat, | ||
294 | (info.mode == AUMODE_PLAY) ? "PLAY" | ||
295 | : (info.mode = AUMODE_RECORD) ? "RECORD" | ||
296 | : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" | ||
297 | : "?")); | ||
298 | } | ||
299 | #endif /* DEBUG_AUDIO */ | ||
300 | |||
301 | static int | ||
302 | OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec) | ||
303 | { | ||
304 | char audiodev[64]; | ||
305 | Uint16 format; | ||
306 | audio_info_t info; | ||
307 | |||
308 | AUDIO_INITINFO(&info); | ||
309 | |||
310 | /* Calculate the final parameters for this audio specification */ | ||
311 | SDL_CalculateAudioSpec(spec); | ||
312 | |||
313 | #ifdef USE_TIMER_SYNC | ||
314 | frame_ticks = 0.0; | ||
315 | #endif | ||
316 | |||
317 | /* Open the audio device */ | ||
318 | audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); | ||
319 | if(audio_fd < 0) { | ||
320 | SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); | ||
321 | return(-1); | ||
322 | } | ||
323 | |||
324 | /* Set to play mode */ | ||
325 | info.mode = AUMODE_PLAY; | ||
326 | if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) { | ||
327 | SDL_SetError("Couldn't put device into play mode"); | ||
328 | return(-1); | ||
329 | } | ||
330 | |||
331 | mixbuf = NULL; | ||
332 | AUDIO_INITINFO(&info); | ||
333 | for (format = SDL_FirstAudioFormat(spec->format); | ||
334 | format; format = SDL_NextAudioFormat()) | ||
335 | { | ||
336 | switch(format) { | ||
337 | case AUDIO_U8: | ||
338 | info.play.encoding = AUDIO_ENCODING_ULINEAR; | ||
339 | info.play.precision = 8; | ||
340 | break; | ||
341 | case AUDIO_S8: | ||
342 | info.play.encoding = AUDIO_ENCODING_SLINEAR; | ||
343 | info.play.precision = 8; | ||
344 | break; | ||
345 | case AUDIO_S16LSB: | ||
346 | info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; | ||
347 | info.play.precision = 16; | ||
348 | break; | ||
349 | case AUDIO_S16MSB: | ||
350 | info.play.encoding = AUDIO_ENCODING_SLINEAR_BE; | ||
351 | info.play.precision = 16; | ||
352 | break; | ||
353 | case AUDIO_U16LSB: | ||
354 | info.play.encoding = AUDIO_ENCODING_ULINEAR_LE; | ||
355 | info.play.precision = 16; | ||
356 | break; | ||
357 | case AUDIO_U16MSB: | ||
358 | info.play.encoding = AUDIO_ENCODING_ULINEAR_BE; | ||
359 | info.play.precision = 16; | ||
360 | break; | ||
361 | default: | ||
362 | continue; | ||
363 | } | ||
364 | if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0) | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | if(!format) { | ||
369 | SDL_SetError("No supported encoding for 0x%x", spec->format); | ||
370 | return(-1); | ||
371 | } | ||
372 | |||
373 | spec->format = format; | ||
374 | |||
375 | AUDIO_INITINFO(&info); | ||
376 | info.play.channels = spec->channels; | ||
377 | if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1) | ||
378 | spec->channels = 1; | ||
379 | AUDIO_INITINFO(&info); | ||
380 | info.play.sample_rate = spec->freq; | ||
381 | info.blocksize = spec->size; | ||
382 | info.hiwat = 5; | ||
383 | info.lowat = 3; | ||
384 | (void)ioctl(audio_fd, AUDIO_SETINFO, &info); | ||
385 | (void)ioctl(audio_fd, AUDIO_GETINFO, &info); | ||
386 | spec->freq = info.play.sample_rate; | ||
387 | /* Allocate mixing buffer */ | ||
388 | mixlen = spec->size; | ||
389 | mixbuf = (Uint8*)SDL_AllocAudioMem(mixlen); | ||
390 | if(mixbuf == NULL) { | ||
391 | return(-1); | ||
392 | } | ||
393 | SDL_memset(mixbuf, spec->silence, spec->size); | ||
394 | |||
395 | /* Get the parent process id (we're the parent of the audio thread) */ | ||
396 | parent = getpid(); | ||
397 | |||
398 | #ifdef DEBUG_AUDIO | ||
399 | OBSD_Status(this); | ||
400 | #endif | ||
401 | |||
402 | /* We're ready to rock and roll. :-) */ | ||
403 | return(0); | ||
404 | } | ||
diff --git a/apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.h b/apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.h new file mode 100644 index 0000000000..c9f69cf544 --- /dev/null +++ b/apps/plugins/sdl/src/audio/bsd/SDL_bsdaudio.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifndef _SDL_openbsdaudio_h | ||
25 | #define _SDL_openbsdaudio_h | ||
26 | |||
27 | #include "../SDL_sysaudio.h" | ||
28 | |||
29 | #define _THIS SDL_AudioDevice *this | ||
30 | |||
31 | struct SDL_PrivateAudioData | ||
32 | { | ||
33 | /* The file descriptor for the audio device */ | ||
34 | int audio_fd; | ||
35 | |||
36 | /* The parent process id, to detect when application quits */ | ||
37 | pid_t parent; | ||
38 | |||
39 | /* Raw mixing buffer */ | ||
40 | Uint8 *mixbuf; | ||
41 | int mixlen; | ||
42 | |||
43 | /* Support for audio timing using a timer, in addition to select() */ | ||
44 | float frame_ticks; | ||
45 | float next_frame; | ||
46 | }; | ||
47 | |||
48 | #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ | ||
49 | |||
50 | /* Old variable names */ | ||
51 | #define audio_fd (this->hidden->audio_fd) | ||
52 | #define parent (this->hidden->parent) | ||
53 | #define mixbuf (this->hidden->mixbuf) | ||
54 | #define mixlen (this->hidden->mixlen) | ||
55 | #define frame_ticks (this->hidden->frame_ticks) | ||
56 | #define next_frame (this->hidden->next_frame) | ||
57 | |||
58 | #endif /* _SDL_openbsdaudio_h */ | ||