Mercurial > sdl-ios-xcode
annotate src/audio/sun/SDL_sunaudio.c @ 4361:991e4bcfc7a8 SDL-1.2
Added an error message for when ALSA audio fails
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 19 Oct 2009 05:15:21 +0000 |
parents | a1b03ba2fcd0 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
4159 | 3 Copyright (C) 1997-2009 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1184
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1184
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 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 | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1184
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1184
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1184
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1184
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
148
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
22 #include "SDL_config.h" |
0 | 23 |
24 /* Allow access to a raw mixing buffer */ | |
25 | |
26 #include <fcntl.h> | |
27 #include <errno.h> | |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
28 #ifdef __NETBSD__ |
0 | 29 #include <sys/ioctl.h> |
30 #include <sys/audioio.h> | |
31 #endif | |
32 #ifdef __SVR4 | |
33 #include <sys/audioio.h> | |
34 #else | |
35 #include <sys/time.h> | |
36 #include <sys/types.h> | |
37 #endif | |
38 #include <unistd.h> | |
39 | |
1358
c71e05b4dc2e
More header massaging... works great on Windows. ;-)
Sam Lantinga <slouken@libsdl.org>
parents:
1338
diff
changeset
|
40 #include "SDL_timer.h" |
0 | 41 #include "SDL_audio.h" |
1361
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
42 #include "../SDL_audiomem.h" |
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
43 #include "../SDL_audio_c.h" |
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
44 #include "../SDL_audiodev_c.h" |
0 | 45 #include "SDL_sunaudio.h" |
46 | |
47 /* Open the audio device for playback, and don't block if busy */ | |
48 #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) | |
49 | |
50 /* Audio driver functions */ | |
51 static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec); | |
52 static void DSP_WaitAudio(_THIS); | |
53 static void DSP_PlayAudio(_THIS); | |
54 static Uint8 *DSP_GetAudioBuf(_THIS); | |
55 static void DSP_CloseAudio(_THIS); | |
56 | |
1464
af30090c0330
*** empty log message ***
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
57 static Uint8 snd2au(int sample); |
af30090c0330
*** empty log message ***
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
58 |
0 | 59 /* Audio driver bootstrap functions */ |
60 | |
61 static int Audio_Available(void) | |
62 { | |
63 int fd; | |
64 int available; | |
65 | |
66 available = 0; | |
67 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 1); | |
68 if ( fd >= 0 ) { | |
69 available = 1; | |
70 close(fd); | |
71 } | |
72 return(available); | |
73 } | |
74 | |
75 static void Audio_DeleteDevice(SDL_AudioDevice *device) | |
76 { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
77 SDL_free(device->hidden); |
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
78 SDL_free(device); |
0 | 79 } |
80 | |
81 static SDL_AudioDevice *Audio_CreateDevice(int devindex) | |
82 { | |
83 SDL_AudioDevice *this; | |
84 | |
85 /* Initialize all variables that we clean on shutdown */ | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
86 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); |
0 | 87 if ( this ) { |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
88 SDL_memset(this, 0, (sizeof *this)); |
0 | 89 this->hidden = (struct SDL_PrivateAudioData *) |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
90 SDL_malloc((sizeof *this->hidden)); |
0 | 91 } |
92 if ( (this == NULL) || (this->hidden == NULL) ) { | |
93 SDL_OutOfMemory(); | |
94 if ( this ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
95 SDL_free(this); |
0 | 96 } |
97 return(0); | |
98 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
99 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); |
0 | 100 audio_fd = -1; |
101 | |
102 /* Set the function pointers */ | |
103 this->OpenAudio = DSP_OpenAudio; | |
104 this->WaitAudio = DSP_WaitAudio; | |
105 this->PlayAudio = DSP_PlayAudio; | |
106 this->GetAudioBuf = DSP_GetAudioBuf; | |
107 this->CloseAudio = DSP_CloseAudio; | |
108 | |
109 this->free = Audio_DeleteDevice; | |
110 | |
111 return this; | |
112 } | |
113 | |
148
8758b8d42cd9
Audio subsystem no longer assumes sun audio API on UNIX systems
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
114 AudioBootStrap SUNAUDIO_bootstrap = { |
0 | 115 "audio", "UNIX /dev/audio interface", |
116 Audio_Available, Audio_CreateDevice | |
117 }; | |
118 | |
119 #ifdef DEBUG_AUDIO | |
120 void CheckUnderflow(_THIS) | |
121 { | |
122 #ifdef AUDIO_GETINFO | |
123 audio_info_t info; | |
124 int left; | |
125 | |
126 ioctl(audio_fd, AUDIO_GETINFO, &info); | |
127 left = (written - info.play.samples); | |
128 if ( written && (left == 0) ) { | |
129 fprintf(stderr, "audio underflow!\n"); | |
130 } | |
131 #endif | |
132 } | |
133 #endif | |
134 | |
135 void DSP_WaitAudio(_THIS) | |
136 { | |
137 #ifdef AUDIO_GETINFO | |
138 #define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */ | |
139 audio_info_t info; | |
140 Sint32 left; | |
141 | |
142 ioctl(audio_fd, AUDIO_GETINFO, &info); | |
143 left = (written - info.play.samples); | |
144 if ( left > fragsize ) { | |
145 Sint32 sleepy; | |
146 | |
147 sleepy = ((left - fragsize)/frequency); | |
148 sleepy -= SLEEP_FUDGE; | |
149 if ( sleepy > 0 ) { | |
150 SDL_Delay(sleepy); | |
151 } | |
152 } | |
153 #else | |
154 fd_set fdset; | |
155 | |
156 FD_ZERO(&fdset); | |
157 FD_SET(audio_fd, &fdset); | |
158 select(audio_fd+1, NULL, &fdset, NULL, NULL); | |
159 #endif | |
160 } | |
161 | |
162 void DSP_PlayAudio(_THIS) | |
163 { | |
164 /* Write the audio data */ | |
165 if ( ulaw_only ) { | |
166 /* Assuming that this->spec.freq >= 8000 Hz */ | |
167 int accum, incr, pos; | |
168 Uint8 *aubuf; | |
169 | |
170 accum = 0; | |
171 incr = this->spec.freq/8; | |
172 aubuf = ulaw_buf; | |
173 switch (audio_fmt & 0xFF) { | |
174 case 8: { | |
175 Uint8 *sndbuf; | |
176 | |
177 sndbuf = mixbuf; | |
178 for ( pos=0; pos < fragsize; ++pos ) { | |
179 *aubuf = snd2au((0x80-*sndbuf)*64); | |
180 accum += incr; | |
181 while ( accum > 0 ) { | |
182 accum -= 1000; | |
183 sndbuf += 1; | |
184 } | |
185 aubuf += 1; | |
186 } | |
187 } | |
188 break; | |
189 case 16: { | |
190 Sint16 *sndbuf; | |
191 | |
192 sndbuf = (Sint16 *)mixbuf; | |
193 for ( pos=0; pos < fragsize; ++pos ) { | |
194 *aubuf = snd2au(*sndbuf/4); | |
195 accum += incr; | |
196 while ( accum > 0 ) { | |
197 accum -= 1000; | |
198 sndbuf += 1; | |
199 } | |
200 aubuf += 1; | |
201 } | |
202 } | |
203 break; | |
204 } | |
205 #ifdef DEBUG_AUDIO | |
206 CheckUnderflow(this); | |
207 #endif | |
208 if ( write(audio_fd, ulaw_buf, fragsize) < 0 ) { | |
209 /* Assume fatal error, for now */ | |
210 this->enabled = 0; | |
211 } | |
212 written += fragsize; | |
213 } else { | |
214 #ifdef DEBUG_AUDIO | |
215 CheckUnderflow(this); | |
216 #endif | |
217 if ( write(audio_fd, mixbuf, this->spec.size) < 0 ) { | |
218 /* Assume fatal error, for now */ | |
219 this->enabled = 0; | |
220 } | |
221 written += fragsize; | |
222 } | |
223 } | |
224 | |
225 Uint8 *DSP_GetAudioBuf(_THIS) | |
226 { | |
227 return(mixbuf); | |
228 } | |
229 | |
230 void DSP_CloseAudio(_THIS) | |
231 { | |
232 if ( mixbuf != NULL ) { | |
233 SDL_FreeAudioMem(mixbuf); | |
234 mixbuf = NULL; | |
235 } | |
236 if ( ulaw_buf != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
237 SDL_free(ulaw_buf); |
0 | 238 ulaw_buf = NULL; |
239 } | |
240 close(audio_fd); | |
241 } | |
242 | |
243 int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec) | |
244 { | |
245 char audiodev[1024]; | |
246 #ifdef AUDIO_SETINFO | |
247 int enc; | |
248 #endif | |
249 int desired_freq = spec->freq; | |
250 | |
251 /* Initialize our freeable variables, in case we fail*/ | |
252 audio_fd = -1; | |
253 mixbuf = NULL; | |
254 ulaw_buf = NULL; | |
255 | |
256 /* Determine the audio parameters from the AudioSpec */ | |
257 switch ( spec->format & 0xFF ) { | |
258 | |
259 case 8: { /* Unsigned 8 bit audio data */ | |
260 spec->format = AUDIO_U8; | |
261 #ifdef AUDIO_SETINFO | |
262 enc = AUDIO_ENCODING_LINEAR8; | |
263 #endif | |
264 } | |
265 break; | |
266 | |
267 case 16: { /* Signed 16 bit audio data */ | |
268 spec->format = AUDIO_S16SYS; | |
269 #ifdef AUDIO_SETINFO | |
270 enc = AUDIO_ENCODING_LINEAR; | |
271 #endif | |
272 } | |
273 break; | |
274 | |
275 default: { | |
276 SDL_SetError("Unsupported audio format"); | |
277 return(-1); | |
278 } | |
279 } | |
280 audio_fmt = spec->format; | |
281 | |
282 /* Open the audio device */ | |
283 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 1); | |
284 if ( audio_fd < 0 ) { | |
285 SDL_SetError("Couldn't open %s: %s", audiodev, | |
286 strerror(errno)); | |
287 return(-1); | |
288 } | |
289 | |
290 ulaw_only = 0; /* modern Suns do support linear audio */ | |
291 #ifdef AUDIO_SETINFO | |
292 for(;;) { | |
293 audio_info_t info; | |
294 AUDIO_INITINFO(&info); /* init all fields to "no change" */ | |
295 | |
296 /* Try to set the requested settings */ | |
297 info.play.sample_rate = spec->freq; | |
298 info.play.channels = spec->channels; | |
299 info.play.precision = (enc == AUDIO_ENCODING_ULAW) | |
300 ? 8 : spec->format & 0xff; | |
301 info.play.encoding = enc; | |
302 if( ioctl(audio_fd, AUDIO_SETINFO, &info) == 0 ) { | |
303 | |
304 /* Check to be sure we got what we wanted */ | |
305 if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) { | |
306 SDL_SetError("Error getting audio parameters: %s", | |
307 strerror(errno)); | |
308 return -1; | |
309 } | |
310 if(info.play.encoding == enc | |
311 && info.play.precision == (spec->format & 0xff) | |
312 && info.play.channels == spec->channels) { | |
313 /* Yow! All seems to be well! */ | |
314 spec->freq = info.play.sample_rate; | |
315 break; | |
316 } | |
317 } | |
318 | |
319 switch(enc) { | |
320 case AUDIO_ENCODING_LINEAR8: | |
321 /* unsigned 8bit apparently not supported here */ | |
322 enc = AUDIO_ENCODING_LINEAR; | |
323 spec->format = AUDIO_S16SYS; | |
324 break; /* try again */ | |
325 | |
326 case AUDIO_ENCODING_LINEAR: | |
327 /* linear 16bit didn't work either, resort to µ-law */ | |
328 enc = AUDIO_ENCODING_ULAW; | |
329 spec->channels = 1; | |
330 spec->freq = 8000; | |
331 spec->format = AUDIO_U8; | |
332 ulaw_only = 1; | |
333 break; | |
334 | |
335 default: | |
336 /* oh well... */ | |
337 SDL_SetError("Error setting audio parameters: %s", | |
338 strerror(errno)); | |
339 return -1; | |
340 } | |
341 } | |
342 #endif /* AUDIO_SETINFO */ | |
343 written = 0; | |
344 | |
345 /* We can actually convert on-the-fly to U-Law */ | |
346 if ( ulaw_only ) { | |
347 spec->freq = desired_freq; | |
348 fragsize = (spec->samples*1000)/(spec->freq/8); | |
349 frequency = 8; | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
350 ulaw_buf = (Uint8 *)SDL_malloc(fragsize); |
0 | 351 if ( ulaw_buf == NULL ) { |
352 SDL_OutOfMemory(); | |
353 return(-1); | |
354 } | |
355 spec->channels = 1; | |
356 } else { | |
357 fragsize = spec->samples; | |
358 frequency = spec->freq/1000; | |
359 } | |
360 #ifdef DEBUG_AUDIO | |
361 fprintf(stderr, "Audio device %s U-Law only\n", | |
362 ulaw_only ? "is" : "is not"); | |
363 fprintf(stderr, "format=0x%x chan=%d freq=%d\n", | |
364 spec->format, spec->channels, spec->freq); | |
365 #endif | |
366 | |
367 /* Update the fragment size as size in bytes */ | |
368 SDL_CalculateAudioSpec(spec); | |
369 | |
370 /* Allocate mixing buffer */ | |
371 mixbuf = (Uint8 *)SDL_AllocAudioMem(spec->size); | |
372 if ( mixbuf == NULL ) { | |
373 SDL_OutOfMemory(); | |
374 return(-1); | |
375 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
376 SDL_memset(mixbuf, spec->silence, spec->size); |
0 | 377 |
378 /* We're ready to rock and roll. :-) */ | |
379 return(0); | |
380 } | |
381 | |
382 /************************************************************************/ | |
383 /* This function (snd2au()) copyrighted: */ | |
384 /************************************************************************/ | |
385 /* Copyright 1989 by Rich Gopstein and Harris Corporation */ | |
386 /* */ | |
387 /* Permission to use, copy, modify, and distribute this software */ | |
388 /* and its documentation for any purpose and without fee is */ | |
389 /* hereby granted, provided that the above copyright notice */ | |
390 /* appears in all copies and that both that copyright notice and */ | |
391 /* this permission notice appear in supporting documentation, and */ | |
392 /* that the name of Rich Gopstein and Harris Corporation not be */ | |
393 /* used in advertising or publicity pertaining to distribution */ | |
394 /* of the software without specific, written prior permission. */ | |
395 /* Rich Gopstein and Harris Corporation make no representations */ | |
396 /* about the suitability of this software for any purpose. It */ | |
397 /* provided "as is" without express or implied warranty. */ | |
398 /************************************************************************/ | |
399 | |
400 static Uint8 snd2au(int sample) | |
401 { | |
402 | |
403 int mask; | |
404 | |
405 if (sample < 0) { | |
406 sample = -sample; | |
407 mask = 0x7f; | |
408 } else { | |
409 mask = 0xff; | |
410 } | |
411 | |
412 if (sample < 32) { | |
413 sample = 0xF0 | (15 - sample / 2); | |
414 } else if (sample < 96) { | |
415 sample = 0xE0 | (15 - (sample - 32) / 4); | |
416 } else if (sample < 224) { | |
417 sample = 0xD0 | (15 - (sample - 96) / 8); | |
418 } else if (sample < 480) { | |
419 sample = 0xC0 | (15 - (sample - 224) / 16); | |
420 } else if (sample < 992) { | |
421 sample = 0xB0 | (15 - (sample - 480) / 32); | |
422 } else if (sample < 2016) { | |
423 sample = 0xA0 | (15 - (sample - 992) / 64); | |
424 } else if (sample < 4064) { | |
425 sample = 0x90 | (15 - (sample - 2016) / 128); | |
426 } else if (sample < 8160) { | |
427 sample = 0x80 | (15 - (sample - 4064) / 256); | |
428 } else { | |
429 sample = 0x80; | |
430 } | |
431 return (mask & sample); | |
432 } |