comparison src/audio/dsp/SDL_dspaudio.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
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_DetectDevices(int iscapture);
62 static void DSP_WaitAudio(_THIS); 62 static const char *DSP_GetDeviceName(int index, int iscapture);
63 static void DSP_PlayAudio(_THIS); 63 static int DSP_OpenDevice(_THIS, const char *devname, int iscapture);
64 static Uint8 *DSP_GetAudioBuf(_THIS); 64 static void DSP_WaitDevice(_THIS);
65 static void DSP_CloseAudio(_THIS); 65 static void DSP_PlayDevice(_THIS);
66 static Uint8 *DSP_GetDeviceBuf(_THIS);
67 static void DSP_CloseDevice(_THIS);
66 68
67 /* Audio driver bootstrap functions */ 69 /* Audio driver bootstrap functions */
68 70
69 static int 71 static int
70 Audio_Available(void) 72 DSP_Available(void)
71 { 73 {
72 int fd; 74 /*
73 int available; 75 * !!! FIXME: maybe change this to always available, and move this to
74 76 * !!! FIXME: to device enumeration and opening?
75 available = 0; 77 */
76 fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); 78 int fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
79 int available = 0;
77 if (fd >= 0) { 80 if (fd >= 0) {
78 available = 1; 81 available = 1;
79 close(fd); 82 close(fd);
80 } 83 }
81 return (available); 84 return (available);
82 } 85 }
83 86
84 static void 87
85 Audio_DeleteDevice(SDL_AudioDevice * device) 88 static int
86 { 89 DSP_Init(SDL_AudioDriverImpl *impl)
87 SDL_free(device->hidden); 90 {
88 SDL_free(device);
89 }
90
91 static SDL_AudioDevice *
92 Audio_CreateDevice(int devindex)
93 {
94 SDL_AudioDevice *this;
95
96 /* Initialize all variables that we clean on shutdown */
97 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
98 if (this) {
99 SDL_memset(this, 0, (sizeof *this));
100 this->hidden = (struct SDL_PrivateAudioData *)
101 SDL_malloc((sizeof *this->hidden));
102 }
103 if ((this == NULL) || (this->hidden == NULL)) {
104 SDL_OutOfMemory();
105 if (this) {
106 SDL_free(this);
107 }
108 return (0);
109 }
110 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
111 audio_fd = -1;
112
113 /* Set the function pointers */ 91 /* Set the function pointers */
114 this->OpenAudio = DSP_OpenAudio; 92 impl->DetectDevices = DSP_DetectDevices;
115 this->WaitAudio = DSP_WaitAudio; 93 impl->GetDeviceName = DSP_GetDeviceName;
116 this->PlayAudio = DSP_PlayAudio; 94 impl->OpenDevice = DSP_OpenDevice;
117 this->GetAudioBuf = DSP_GetAudioBuf; 95 impl->WaitDevice = DSP_WaitDevice;
118 this->CloseAudio = DSP_CloseAudio; 96 impl->PlayDevice = DSP_PlayDevice;
119 97 impl->GetDeviceBuf = DSP_GetDeviceBuf;
120 this->free = Audio_DeleteDevice; 98 impl->CloseDevice = DSP_CloseDevice;
121 99
122 return this; 100 return 1;
123 } 101 }
102
124 103
125 AudioBootStrap DSP_bootstrap = { 104 AudioBootStrap DSP_bootstrap = {
126 DSP_DRIVER_NAME, "OSS /dev/dsp standard audio", 105 DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
127 Audio_Available, Audio_CreateDevice 106 DSP_Available, DSP_Init
128 }; 107 };
129 108
130 /* This function waits until it is possible to write a full sound buffer */
131 static void
132 DSP_WaitAudio(_THIS)
133 {
134 /* Not needed at all since OSS handles waiting automagically */
135 }
136
137 static void
138 DSP_PlayAudio(_THIS)
139 {
140 if (write(audio_fd, mixbuf, mixlen) == -1) {
141 perror("Audio write");
142 this->enabled = 0;
143 }
144 #ifdef DEBUG_AUDIO
145 fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
146 #endif
147 }
148
149 static Uint8 *
150 DSP_GetAudioBuf(_THIS)
151 {
152 return (mixbuf);
153 }
154
155 static void
156 DSP_CloseAudio(_THIS)
157 {
158 if (mixbuf != NULL) {
159 SDL_FreeAudioMem(mixbuf);
160 mixbuf = NULL;
161 }
162 if (audio_fd >= 0) {
163 close(audio_fd);
164 audio_fd = -1;
165 }
166 }
167 109
168 static int 110 static int
169 DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) 111 DSP_DetectDevices(int iscapture)
170 { 112 {
171 char audiodev[1024]; 113 return -1; /* !!! FIXME */
114 }
115
116
117 static const char *
118 DSP_GetDeviceName(int index, int iscapture)
119 {
120 SDL_SetError("No such device"); /* !!! FIXME */
121 return NULL;
122 }
123
124
125 static int
126 DSP_OpenDevice(_THIS, const char *devname, int iscapture)
127 {
128 char dev[1024];
172 int format; 129 int format;
173 int value; 130 int value;
174 int frag_spec; 131 int frag_spec;
175 SDL_AudioFormat test_format; 132 SDL_AudioFormat test_format;
176 133
134 /* Initialize all variables that we clean on shutdown */
135 this->hidden = (struct SDL_PrivateAudioData *)
136 SDL_malloc((sizeof *this->hidden));
137 if (this->hidden == NULL) {
138 SDL_OutOfMemory();
139 return 0;
140 }
141 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
142 this->hidden->audio_fd = -1;
143
144 /* !!! FIXME: handle devname */
145 /* !!! FIXME: handle iscapture */
146
177 /* Open the audio device */ 147 /* Open the audio device */
178 audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); 148 this->hidden->audio_fd = SDL_OpenAudioPath(dev, sizeof(dev), OPEN_FLAGS, 0);
179 if (audio_fd < 0) { 149 if (this->hidden->audio_fd < 0) {
180 SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); 150 SDL_SetError("Couldn't open %s: %s", dev, strerror(errno));
181 return (-1); 151 return 0;
182 } 152 }
183 mixbuf = NULL; 153 this->hidden->mixbuf = NULL;
184 154
185 /* Make the file descriptor use blocking writes with fcntl() */ 155 /* Make the file descriptor use blocking writes with fcntl() */
186 { 156 {
187 long flags; 157 long flags;
188 flags = fcntl(audio_fd, F_GETFL); 158 flags = fcntl(this->hidden->audio_fd, F_GETFL);
189 flags &= ~O_NONBLOCK; 159 flags &= ~O_NONBLOCK;
190 if (fcntl(audio_fd, F_SETFL, flags) < 0) { 160 if (fcntl(this->hidden->audio_fd, F_SETFL, flags) < 0) {
191 SDL_SetError("Couldn't set audio blocking mode"); 161 SDL_SetError("Couldn't set audio blocking mode");
192 DSP_CloseAudio(this); 162 DSP_CloseDevice(this);
193 return (-1); 163 return 0;
194 } 164 }
195 } 165 }
196 166
197 /* Get a list of supported hardware formats */ 167 /* Get a list of supported hardware formats */
198 if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { 168 if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
199 perror("SNDCTL_DSP_GETFMTS"); 169 perror("SNDCTL_DSP_GETFMTS");
200 SDL_SetError("Couldn't get audio format list"); 170 SDL_SetError("Couldn't get audio format list");
201 DSP_CloseAudio(this); 171 DSP_CloseDevice(this);
202 return (-1); 172 return 0;
203 } 173 }
204 174
205 /* Try for a closest match on audio format */ 175 /* Try for a closest match on audio format */
206 format = 0; 176 format = 0;
207 for (test_format = SDL_FirstAudioFormat(spec->format); 177 for (test_format = SDL_FirstAudioFormat(this->spec.format);
208 !format && test_format;) { 178 !format && test_format;) {
209 #ifdef DEBUG_AUDIO 179 #ifdef DEBUG_AUDIO
210 fprintf(stderr, "Trying format 0x%4.4x\n", test_format); 180 fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
211 #endif 181 #endif
212 switch (test_format) { 182 switch (test_format) {
254 test_format = SDL_NextAudioFormat(); 224 test_format = SDL_NextAudioFormat();
255 } 225 }
256 } 226 }
257 if (format == 0) { 227 if (format == 0) {
258 SDL_SetError("Couldn't find any hardware audio formats"); 228 SDL_SetError("Couldn't find any hardware audio formats");
259 DSP_CloseAudio(this); 229 DSP_CloseDevice(this);
260 return (-1); 230 return 0;
261 } 231 }
262 spec->format = test_format; 232 this->spec.format = test_format;
263 233
264 /* Set the audio format */ 234 /* Set the audio format */
265 value = format; 235 value = format;
266 if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { 236 if ( (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
237 (value != format) ) {
267 perror("SNDCTL_DSP_SETFMT"); 238 perror("SNDCTL_DSP_SETFMT");
268 SDL_SetError("Couldn't set audio format"); 239 SDL_SetError("Couldn't set audio format");
269 DSP_CloseAudio(this); 240 DSP_CloseDevice(this);
270 return (-1); 241 return 0;
271 } 242 }
272 243
273 /* Set the number of channels of output */ 244 /* Set the number of channels of output */
274 value = spec->channels; 245 value = this->spec.channels;
275 if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) { 246 if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
276 perror("SNDCTL_DSP_CHANNELS"); 247 perror("SNDCTL_DSP_CHANNELS");
277 SDL_SetError("Cannot set the number of channels"); 248 SDL_SetError("Cannot set the number of channels");
278 DSP_CloseAudio(this); 249 DSP_CloseDevice(this);
279 return (-1); 250 return 0;
280 } 251 }
281 spec->channels = value; 252 this->spec.channels = value;
282 253
283 /* Set the DSP frequency */ 254 /* Set the DSP frequency */
284 value = spec->freq; 255 value = this->spec.freq;
285 if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { 256 if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
286 perror("SNDCTL_DSP_SPEED"); 257 perror("SNDCTL_DSP_SPEED");
287 SDL_SetError("Couldn't set audio frequency"); 258 SDL_SetError("Couldn't set audio frequency");
288 DSP_CloseAudio(this); 259 DSP_CloseDevice(this);
289 return (-1); 260 return 0;
290 } 261 }
291 spec->freq = value; 262 this->spec.freq = value;
292 263
293 /* Calculate the final parameters for this audio specification */ 264 /* Calculate the final parameters for this audio specification */
294 SDL_CalculateAudioSpec(spec); 265 SDL_CalculateAudioSpec(&this->spec);
295 266
296 /* Determine the power of two of the fragment size */ 267 /* Determine the power of two of the fragment size */
297 for (frag_spec = 0; (0x01U << frag_spec) < spec->size; ++frag_spec); 268 for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
298 if ((0x01U << frag_spec) != spec->size) { 269 if ((0x01U << frag_spec) != this->spec.size) {
299 SDL_SetError("Fragment size must be a power of two"); 270 SDL_SetError("Fragment size must be a power of two");
300 DSP_CloseAudio(this); 271 DSP_CloseDevice(this);
301 return (-1); 272 return 0;
302 } 273 }
303 frag_spec |= 0x00020000; /* two fragments, for low latency */ 274 frag_spec |= 0x00020000; /* two fragments, for low latency */
304 275
305 /* Set the audio buffering parameters */ 276 /* Set the audio buffering parameters */
306 #ifdef DEBUG_AUDIO 277 #ifdef DEBUG_AUDIO
307 fprintf(stderr, "Requesting %d fragments of size %d\n", 278 fprintf(stderr, "Requesting %d fragments of size %d\n",
308 (frag_spec >> 16), 1 << (frag_spec & 0xFFFF)); 279 (frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
309 #endif 280 #endif
310 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { 281 if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
311 perror("SNDCTL_DSP_SETFRAGMENT"); 282 perror("SNDCTL_DSP_SETFRAGMENT");
312 } 283 }
313 #ifdef DEBUG_AUDIO 284 #ifdef DEBUG_AUDIO
314 { 285 {
315 audio_buf_info info; 286 audio_buf_info info;
316 ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info); 287 ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
317 fprintf(stderr, "fragments = %d\n", info.fragments); 288 fprintf(stderr, "fragments = %d\n", info.fragments);
318 fprintf(stderr, "fragstotal = %d\n", info.fragstotal); 289 fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
319 fprintf(stderr, "fragsize = %d\n", info.fragsize); 290 fprintf(stderr, "fragsize = %d\n", info.fragsize);
320 fprintf(stderr, "bytes = %d\n", info.bytes); 291 fprintf(stderr, "bytes = %d\n", info.bytes);
321 } 292 }
322 #endif 293 #endif
323 294
324 /* Allocate mixing buffer */ 295 /* Allocate mixing buffer */
325 mixlen = spec->size; 296 this->hidden->mixlen = this->spec.size;
326 mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); 297 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
327 if (mixbuf == NULL) { 298 if (this->hidden->mixbuf == NULL) {
328 DSP_CloseAudio(this); 299 DSP_CloseDevice(this);
329 return (-1); 300 return 0;
330 } 301 }
331 SDL_memset(mixbuf, spec->silence, spec->size); 302 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
332
333 /* Get the parent process id (we're the parent of the audio thread) */
334 parent = getpid();
335 303
336 /* We're ready to rock and roll. :-) */ 304 /* We're ready to rock and roll. :-) */
337 return (0); 305 return 1;
306 }
307
308
309 /* This function waits until it is possible to write a full sound buffer */
310 static void
311 DSP_WaitDevice(_THIS)
312 {
313 /* Not needed at all since OSS handles waiting automagically */
314 }
315
316
317 static void
318 DSP_PlayDevice(_THIS)
319 {
320 const Uint8 *mixbuf = this->hidden->mixbuf;
321 const int mixlen = this->hidden->mixlen;
322 if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
323 perror("Audio write");
324 this->enabled = 0;
325 }
326 #ifdef DEBUG_AUDIO
327 fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
328 #endif
329 }
330
331 static Uint8 *
332 DSP_GetDeviceBuf(_THIS)
333 {
334 return (this->hidden->mixbuf);
335 }
336
337 static void
338 DSP_CloseDevice(_THIS)
339 {
340 if (this->hidden != NULL) {
341 if (this->hidden->mixbuf != NULL) {
342 SDL_FreeAudioMem(this->hidden->mixbuf);
343 this->hidden->mixbuf = NULL;
344 }
345 if (this->hidden->audio_fd >= 0) {
346 close(this->hidden->audio_fd);
347 this->hidden->audio_fd = -1;
348 }
349 SDL_free(this->hidden);
350 this->hidden = NULL;
351 }
338 } 352 }
339 353
340 /* vi: set ts=4 sw=4 expandtab: */ 354 /* vi: set ts=4 sw=4 expandtab: */