comparison src/audio/dsp/SDL_dspaudio.c @ 1895:c121d94672cb

SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 10 Jul 2006 21:04:37 +0000
parents 97d0966f4bf7
children 3b4ce57c6215
comparison
equal deleted inserted replaced
1894:c69cee13dd76 1895:c121d94672cb
24 */ 24 */
25 #include "SDL_config.h" 25 #include "SDL_config.h"
26 26
27 /* Allow access to a raw mixing buffer */ 27 /* Allow access to a raw mixing buffer */
28 28
29 #include <stdio.h> /* For perror() */ 29 #include <stdio.h> /* For perror() */
30 #include <string.h> /* For strerror() */ 30 #include <string.h> /* For strerror() */
31 #include <errno.h> 31 #include <errno.h>
32 #include <unistd.h> 32 #include <unistd.h>
33 #include <fcntl.h> 33 #include <fcntl.h>
34 #include <signal.h> 34 #include <signal.h>
35 #include <sys/time.h> 35 #include <sys/time.h>
56 56
57 /* Open the audio device for playback, and don't block if busy */ 57 /* Open the audio device for playback, and don't block if busy */
58 #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) 58 #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
59 59
60 /* Audio driver functions */ 60 /* Audio driver functions */
61 static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec); 61 static int DSP_OpenAudio(_THIS, SDL_AudioSpec * spec);
62 static void DSP_WaitAudio(_THIS); 62 static void DSP_WaitAudio(_THIS);
63 static void DSP_PlayAudio(_THIS); 63 static void DSP_PlayAudio(_THIS);
64 static Uint8 *DSP_GetAudioBuf(_THIS); 64 static Uint8 *DSP_GetAudioBuf(_THIS);
65 static void DSP_CloseAudio(_THIS); 65 static void DSP_CloseAudio(_THIS);
66 66
67 /* Audio driver bootstrap functions */ 67 /* Audio driver bootstrap functions */
68 68
69 static int Audio_Available(void) 69 static int
70 { 70 Audio_Available(void)
71 int fd; 71 {
72 int available; 72 int fd;
73 73 int available;
74 available = 0; 74
75 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); 75 available = 0;
76 if ( fd >= 0 ) { 76 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
77 available = 1; 77 if (fd >= 0) {
78 close(fd); 78 available = 1;
79 } 79 close(fd);
80 return(available); 80 }
81 } 81 return (available);
82 82 }
83 static void Audio_DeleteDevice(SDL_AudioDevice *device) 83
84 { 84 static void
85 SDL_free(device->hidden); 85 Audio_DeleteDevice(SDL_AudioDevice * device)
86 SDL_free(device); 86 {
87 } 87 SDL_free(device->hidden);
88 88 SDL_free(device);
89 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 89 }
90 { 90
91 SDL_AudioDevice *this; 91 static SDL_AudioDevice *
92 92 Audio_CreateDevice(int devindex)
93 /* Initialize all variables that we clean on shutdown */ 93 {
94 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 94 SDL_AudioDevice *this;
95 if ( this ) { 95
96 SDL_memset(this, 0, (sizeof *this)); 96 /* Initialize all variables that we clean on shutdown */
97 this->hidden = (struct SDL_PrivateAudioData *) 97 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
98 SDL_malloc((sizeof *this->hidden)); 98 if (this) {
99 } 99 SDL_memset(this, 0, (sizeof *this));
100 if ( (this == NULL) || (this->hidden == NULL) ) { 100 this->hidden = (struct SDL_PrivateAudioData *)
101 SDL_OutOfMemory(); 101 SDL_malloc((sizeof *this->hidden));
102 if ( this ) { 102 }
103 SDL_free(this); 103 if ((this == NULL) || (this->hidden == NULL)) {
104 } 104 SDL_OutOfMemory();
105 return(0); 105 if (this) {
106 } 106 SDL_free(this);
107 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 107 }
108 audio_fd = -1; 108 return (0);
109 109 }
110 /* Set the function pointers */ 110 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
111 this->OpenAudio = DSP_OpenAudio; 111 audio_fd = -1;
112 this->WaitAudio = DSP_WaitAudio; 112
113 this->PlayAudio = DSP_PlayAudio; 113 /* Set the function pointers */
114 this->GetAudioBuf = DSP_GetAudioBuf; 114 this->OpenAudio = DSP_OpenAudio;
115 this->CloseAudio = DSP_CloseAudio; 115 this->WaitAudio = DSP_WaitAudio;
116 116 this->PlayAudio = DSP_PlayAudio;
117 this->free = Audio_DeleteDevice; 117 this->GetAudioBuf = DSP_GetAudioBuf;
118 118 this->CloseAudio = DSP_CloseAudio;
119 return this; 119
120 this->free = Audio_DeleteDevice;
121
122 return this;
120 } 123 }
121 124
122 AudioBootStrap DSP_bootstrap = { 125 AudioBootStrap DSP_bootstrap = {
123 DSP_DRIVER_NAME, "OSS /dev/dsp standard audio", 126 DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
124 Audio_Available, Audio_CreateDevice 127 Audio_Available, Audio_CreateDevice
125 }; 128 };
126 129
127 /* This function waits until it is possible to write a full sound buffer */ 130 /* This function waits until it is possible to write a full sound buffer */
128 static void DSP_WaitAudio(_THIS) 131 static void
129 { 132 DSP_WaitAudio(_THIS)
130 /* Not needed at all since OSS handles waiting automagically */ 133 {
131 } 134 /* Not needed at all since OSS handles waiting automagically */
132 135 }
133 static void DSP_PlayAudio(_THIS) 136
134 { 137 static void
135 if (write(audio_fd, mixbuf, mixlen)==-1) 138 DSP_PlayAudio(_THIS)
136 { 139 {
137 perror("Audio write"); 140 if (write(audio_fd, mixbuf, mixlen) == -1) {
138 this->enabled = 0; 141 perror("Audio write");
139 } 142 this->enabled = 0;
140 143 }
141 #ifdef DEBUG_AUDIO 144 #ifdef DEBUG_AUDIO
142 fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); 145 fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
143 #endif 146 #endif
144 } 147 }
145 148
146 static Uint8 *DSP_GetAudioBuf(_THIS) 149 static Uint8 *
147 { 150 DSP_GetAudioBuf(_THIS)
148 return(mixbuf); 151 {
149 } 152 return (mixbuf);
150 153 }
151 static void DSP_CloseAudio(_THIS) 154
152 { 155 static void
153 if ( mixbuf != NULL ) { 156 DSP_CloseAudio(_THIS)
154 SDL_FreeAudioMem(mixbuf); 157 {
155 mixbuf = NULL; 158 if (mixbuf != NULL) {
156 } 159 SDL_FreeAudioMem(mixbuf);
157 if ( audio_fd >= 0 ) { 160 mixbuf = NULL;
158 close(audio_fd); 161 }
159 audio_fd = -1; 162 if (audio_fd >= 0) {
160 } 163 close(audio_fd);
161 } 164 audio_fd = -1;
162 165 }
163 static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec) 166 }
164 { 167
165 char audiodev[1024]; 168 static int
166 int format; 169 DSP_OpenAudio(_THIS, SDL_AudioSpec * spec)
167 int value; 170 {
168 int frag_spec; 171 char audiodev[1024];
169 Uint16 test_format; 172 int format;
170 173 int value;
171 /* Open the audio device */ 174 int frag_spec;
172 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); 175 Uint16 test_format;
173 if ( audio_fd < 0 ) { 176
174 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); 177 /* Open the audio device */
175 return(-1); 178 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
176 } 179 if (audio_fd < 0) {
177 mixbuf = NULL; 180 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
178 181 return (-1);
179 /* Make the file descriptor use blocking writes with fcntl() */ 182 }
180 { long flags; 183 mixbuf = NULL;
181 flags = fcntl(audio_fd, F_GETFL); 184
182 flags &= ~O_NONBLOCK; 185 /* Make the file descriptor use blocking writes with fcntl() */
183 if ( fcntl(audio_fd, F_SETFL, flags) < 0 ) { 186 {
184 SDL_SetError("Couldn't set audio blocking mode"); 187 long flags;
185 DSP_CloseAudio(this); 188 flags = fcntl(audio_fd, F_GETFL);
186 return(-1); 189 flags &= ~O_NONBLOCK;
187 } 190 if (fcntl(audio_fd, F_SETFL, flags) < 0) {
188 } 191 SDL_SetError("Couldn't set audio blocking mode");
189 192 DSP_CloseAudio(this);
190 /* Get a list of supported hardware formats */ 193 return (-1);
191 if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) { 194 }
192 perror("SNDCTL_DSP_GETFMTS"); 195 }
193 SDL_SetError("Couldn't get audio format list"); 196
194 DSP_CloseAudio(this); 197 /* Get a list of supported hardware formats */
195 return(-1); 198 if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
196 } 199 perror("SNDCTL_DSP_GETFMTS");
197 200 SDL_SetError("Couldn't get audio format list");
198 /* Try for a closest match on audio format */ 201 DSP_CloseAudio(this);
199 format = 0; 202 return (-1);
200 for ( test_format = SDL_FirstAudioFormat(spec->format); 203 }
201 ! format && test_format; ) { 204
205 /* Try for a closest match on audio format */
206 format = 0;
207 for (test_format = SDL_FirstAudioFormat(spec->format);
208 !format && test_format;) {
202 #ifdef DEBUG_AUDIO 209 #ifdef DEBUG_AUDIO
203 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); 210 fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
204 #endif 211 #endif
205 switch ( test_format ) { 212 switch (test_format) {
206 case AUDIO_U8: 213 case AUDIO_U8:
207 if ( value & AFMT_U8 ) { 214 if (value & AFMT_U8) {
208 format = AFMT_U8; 215 format = AFMT_U8;
209 } 216 }
210 break; 217 break;
211 case AUDIO_S16LSB: 218 case AUDIO_S16LSB:
212 if ( value & AFMT_S16_LE ) { 219 if (value & AFMT_S16_LE) {
213 format = AFMT_S16_LE; 220 format = AFMT_S16_LE;
214 } 221 }
215 break; 222 break;
216 case AUDIO_S16MSB: 223 case AUDIO_S16MSB:
217 if ( value & AFMT_S16_BE ) { 224 if (value & AFMT_S16_BE) {
218 format = AFMT_S16_BE; 225 format = AFMT_S16_BE;
219 } 226 }
220 break; 227 break;
221 #if 0 228 #if 0
222 /* 229 /*
223 * These formats are not used by any real life systems so they are not 230 * These formats are not used by any real life systems so they are not
224 * needed here. 231 * needed here.
225 */ 232 */
226 case AUDIO_S8: 233 case AUDIO_S8:
227 if ( value & AFMT_S8 ) { 234 if (value & AFMT_S8) {
228 format = AFMT_S8; 235 format = AFMT_S8;
229 } 236 }
230 break; 237 break;
231 case AUDIO_U16LSB: 238 case AUDIO_U16LSB:
232 if ( value & AFMT_U16_LE ) { 239 if (value & AFMT_U16_LE) {
233 format = AFMT_U16_LE; 240 format = AFMT_U16_LE;
234 } 241 }
235 break; 242 break;
236 case AUDIO_U16MSB: 243 case AUDIO_U16MSB:
237 if ( value & AFMT_U16_BE ) { 244 if (value & AFMT_U16_BE) {
238 format = AFMT_U16_BE; 245 format = AFMT_U16_BE;
239 } 246 }
240 break; 247 break;
241 #endif 248 #endif
242 default: 249 default:
243 format = 0; 250 format = 0;
244 break; 251 break;
245 } 252 }
246 if ( ! format ) { 253 if (!format) {
247 test_format = SDL_NextAudioFormat(); 254 test_format = SDL_NextAudioFormat();
248 } 255 }
249 } 256 }
250 if ( format == 0 ) { 257 if (format == 0) {
251 SDL_SetError("Couldn't find any hardware audio formats"); 258 SDL_SetError("Couldn't find any hardware audio formats");
252 DSP_CloseAudio(this); 259 DSP_CloseAudio(this);
253 return(-1); 260 return (-1);
254 } 261 }
255 spec->format = test_format; 262 spec->format = test_format;
256 263
257 /* Set the audio format */ 264 /* Set the audio format */
258 value = format; 265 value = format;
259 if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || 266 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) {
260 (value != format) ) { 267 perror("SNDCTL_DSP_SETFMT");
261 perror("SNDCTL_DSP_SETFMT"); 268 SDL_SetError("Couldn't set audio format");
262 SDL_SetError("Couldn't set audio format"); 269 DSP_CloseAudio(this);
263 DSP_CloseAudio(this); 270 return (-1);
264 return(-1); 271 }
265 } 272
266 273 /* Set the number of channels of output */
267 /* Set the number of channels of output */ 274 value = spec->channels;
268 value = spec->channels; 275 if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
269 if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) { 276 perror("SNDCTL_DSP_CHANNELS");
270 perror("SNDCTL_DSP_CHANNELS"); 277 SDL_SetError("Cannot set the number of channels");
271 SDL_SetError("Cannot set the number of channels"); 278 DSP_CloseAudio(this);
272 DSP_CloseAudio(this); 279 return (-1);
273 return(-1); 280 }
274 } 281 spec->channels = value;
275 spec->channels = value; 282
276 283 /* Set the DSP frequency */
277 /* Set the DSP frequency */ 284 value = spec->freq;
278 value = spec->freq; 285 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
279 if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) { 286 perror("SNDCTL_DSP_SPEED");
280 perror("SNDCTL_DSP_SPEED"); 287 SDL_SetError("Couldn't set audio frequency");
281 SDL_SetError("Couldn't set audio frequency"); 288 DSP_CloseAudio(this);
282 DSP_CloseAudio(this); 289 return (-1);
283 return(-1); 290 }
284 } 291 spec->freq = value;
285 spec->freq = value; 292
286 293 /* Calculate the final parameters for this audio specification */
287 /* Calculate the final parameters for this audio specification */ 294 SDL_CalculateAudioSpec(spec);
288 SDL_CalculateAudioSpec(spec); 295
289 296 /* Determine the power of two of the fragment size */
290 /* Determine the power of two of the fragment size */ 297 for (frag_spec = 0; (0x01U << frag_spec) < spec->size; ++frag_spec);
291 for ( frag_spec = 0; (0x01U<<frag_spec) < spec->size; ++frag_spec ); 298 if ((0x01U << frag_spec) != spec->size) {
292 if ( (0x01U<<frag_spec) != spec->size ) { 299 SDL_SetError("Fragment size must be a power of two");
293 SDL_SetError("Fragment size must be a power of two"); 300 DSP_CloseAudio(this);
294 DSP_CloseAudio(this); 301 return (-1);
295 return(-1); 302 }
296 } 303 frag_spec |= 0x00020000; /* two fragments, for low latency */
297 frag_spec |= 0x00020000; /* two fragments, for low latency */ 304
298 305 /* Set the audio buffering parameters */
299 /* Set the audio buffering parameters */
300 #ifdef DEBUG_AUDIO 306 #ifdef DEBUG_AUDIO
301 fprintf(stderr, "Requesting %d fragments of size %d\n", 307 fprintf(stderr, "Requesting %d fragments of size %d\n",
302 (frag_spec >> 16), 1<<(frag_spec&0xFFFF)); 308 (frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
303 #endif 309 #endif
304 if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) { 310 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
305 perror("SNDCTL_DSP_SETFRAGMENT"); 311 perror("SNDCTL_DSP_SETFRAGMENT");
306 } 312 }
307 #ifdef DEBUG_AUDIO 313 #ifdef DEBUG_AUDIO
308 { audio_buf_info info; 314 {
309 ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info); 315 audio_buf_info info;
310 fprintf(stderr, "fragments = %d\n", info.fragments); 316 ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
311 fprintf(stderr, "fragstotal = %d\n", info.fragstotal); 317 fprintf(stderr, "fragments = %d\n", info.fragments);
312 fprintf(stderr, "fragsize = %d\n", info.fragsize); 318 fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
313 fprintf(stderr, "bytes = %d\n", info.bytes); 319 fprintf(stderr, "fragsize = %d\n", info.fragsize);
314 } 320 fprintf(stderr, "bytes = %d\n", info.bytes);
315 #endif 321 }
316 322 #endif
317 /* Allocate mixing buffer */ 323
318 mixlen = spec->size; 324 /* Allocate mixing buffer */
319 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); 325 mixlen = spec->size;
320 if ( mixbuf == NULL ) { 326 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
321 DSP_CloseAudio(this); 327 if (mixbuf == NULL) {
322 return(-1); 328 DSP_CloseAudio(this);
323 } 329 return (-1);
324 SDL_memset(mixbuf, spec->silence, spec->size); 330 }
325 331 SDL_memset(mixbuf, spec->silence, spec->size);
326 /* Get the parent process id (we're the parent of the audio thread) */ 332
327 parent = getpid(); 333 /* Get the parent process id (we're the parent of the audio thread) */
328 334 parent = getpid();
329 /* We're ready to rock and roll. :-) */ 335
330 return(0); 336 /* We're ready to rock and roll. :-) */
331 } 337 return (0);
338 }
339
340 /* vi: set ts=4 sw=4 expandtab: */