Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
465 lines (402 loc) · 13 KB

SDL_bsdaudio.c

File metadata and controls

465 lines (402 loc) · 13 KB
 
1
2
/*
SDL - Simple DirectMedia Layer
Jan 4, 2004
Jan 4, 2004
3
Copyright (C) 1997-2004 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Feb 21, 2006
Feb 21, 2006
22
#include "SDL_config.h"
Mar 21, 2006
Mar 21, 2006
25
* Driver for native OpenBSD/NetBSD audio(4).
26
27
28
29
30
31
32
33
34
35
36
37
* vedge@vedge.com.ar.
*/
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/audioio.h>
Feb 10, 2006
Feb 10, 2006
38
#include "SDL_timer.h"
39
#include "SDL_audio.h"
Feb 16, 2006
Feb 16, 2006
40
41
42
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
Mar 22, 2006
Mar 22, 2006
43
#include "SDL_bsdaudio.h"
Mar 21, 2006
Mar 21, 2006
45
/* The tag name used by NetBSD/OpenBSD audio */
Mar 21, 2006
Mar 21, 2006
46
47
48
#ifdef __NetBSD__
#define BSD_AUDIO_DRIVER_NAME "netbsd"
#define BSD_AUDIO_DRIVER_DESC "Native NetBSD audio"
Mar 21, 2006
Mar 21, 2006
49
#else
Mar 21, 2006
Mar 21, 2006
50
51
#define BSD_AUDIO_DRIVER_NAME "openbsd"
#define BSD_AUDIO_DRIVER_DESC "Native OpenBSD audio"
Mar 21, 2006
Mar 21, 2006
52
#endif
53
54
55
56
57
58
59
60
61
62
63
/* Open the audio device for playback, and don't block if busy */
/* #define USE_BLOCKING_WRITES */
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
#ifdef USE_BLOCKING_WRITES
Oct 7, 2006
Oct 7, 2006
64
65
#define OPEN_FLAGS_OUTPUT O_WRONLY
#define OPEN_FLAGS_INPUT O_RDONLY
Oct 7, 2006
Oct 7, 2006
67
68
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
69
70
#endif
Oct 7, 2006
Oct 7, 2006
71
72
73
74
75
/* !!! FIXME: so much cut and paste with dsp/dma drivers... */
static char **outputDevices = NULL;
static int outputDeviceCount = 0;
static char **inputDevices = NULL;
static int inputDeviceCount = 0;
Oct 7, 2006
Oct 7, 2006
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
static inline void
free_device_list(char ***devs, int *count)
{
SDL_FreeUnixAudioDevices(devs, count);
}
static inline void
build_device_list(int iscapture, char ***devs, int *count)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
free_device_list(devs, count);
SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
}
static inline void
build_device_lists(void)
{
build_device_list(0, &outputDevices, &outputDeviceCount);
build_device_list(1, &inputDevices, &inputDeviceCount);
}
static inline void
free_device_lists(void)
{
free_device_list(&outputDevices, &outputDeviceCount);
free_device_list(&inputDevices, &inputDeviceCount);
}
105
106
107
static int
Oct 7, 2006
Oct 7, 2006
108
BSDAUDIO_Available(void)
Oct 7, 2006
Oct 7, 2006
110
111
112
113
114
int available = 0;
build_device_lists();
available = ((outputDeviceCount > 0) || (inputDeviceCount > 0));
free_device_lists();
return available;
Oct 7, 2006
Oct 7, 2006
117
118
static void
Oct 7, 2006
Oct 7, 2006
119
BSDAUDIO_Deinitialize(void)
Oct 7, 2006
Oct 7, 2006
121
free_device_lists();
122
123
124
}
Oct 7, 2006
Oct 7, 2006
125
126
127
128
129
130
131
132
133
static int
BSDAUDIO_DetectDevices(int iscapture)
{
if (iscapture) {
build_device_list(1, &inputDevices, &inputDeviceCount);
return inputDeviceCount;
} else {
build_device_list(0, &outputDevices, &outputDeviceCount);
return outputDeviceCount;
Oct 7, 2006
Oct 7, 2006
135
136
137
138
139
140
141
142
143
144
145
return 0; /* shouldn't ever hit this. */
}
static const char *
BSDAUDIO_GetDeviceName(int index, int iscapture)
{
if ((iscapture) && (index < inputDeviceCount)) {
return inputDevices[index];
} else if ((!iscapture) && (index < outputDeviceCount)) {
return outputDevices[index];
146
147
}
Oct 7, 2006
Oct 7, 2006
148
149
150
151
SDL_SetError("No such device");
return NULL;
}
Oct 7, 2006
Oct 7, 2006
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
static void
BSDAUDIO_Status(_THIS)
{
#ifdef DEBUG_AUDIO
audio_info_t info;
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
fprintf(stderr, "\n"
"[play/record info]\n"
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
"precision : %i-bit\n"
"encoding : 0x%x\n"
"seek : %i\n"
"sample count : %i\n"
"EOF count : %i\n"
"paused : %s\n"
"error occured : %s\n"
"waiting : %s\n"
"active : %s\n"
"",
info.play.buffer_size,
info.play.sample_rate,
info.play.channels,
info.play.precision,
info.play.encoding,
info.play.seek,
info.play.samples,
info.play.eof,
info.play.pause ? "yes" : "no",
info.play.error ? "yes" : "no",
info.play.waiting ? "yes" : "no",
info.play.active ? "yes" : "no");
Jul 10, 2006
Jul 10, 2006
191
Oct 7, 2006
Oct 7, 2006
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
fprintf(stderr, "\n"
"[audio info]\n"
"monitor_gain : %i\n"
"hw block size : %d bytes\n"
"hi watermark : %i\n"
"lo watermark : %i\n"
"audio mode : %s\n"
"",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
#endif /* DEBUG_AUDIO */
207
208
209
210
211
}
/* This function waits until it is possible to write a full sound buffer */
static void
Oct 7, 2006
Oct 7, 2006
212
BSDAUDIO_WaitDevice(_THIS)
Jul 10, 2006
Jul 10, 2006
214
215
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */
Oct 7, 2006
Oct 7, 2006
216
if (this->hidden->frame_ticks) {
Jul 10, 2006
Jul 10, 2006
217
218
219
/* Use timer for general audio synchronization */
Sint32 ticks;
Oct 7, 2006
Oct 7, 2006
220
ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS;
Jul 10, 2006
Jul 10, 2006
221
222
223
224
225
226
227
228
229
if (ticks > 0) {
SDL_Delay(ticks);
}
} else {
/* Use select() for audio synchronization */
fd_set fdset;
struct timeval timeout;
FD_ZERO(&fdset);
Oct 7, 2006
Oct 7, 2006
230
FD_SET(this->hidden->audio_fd, &fdset);
Jul 10, 2006
Jul 10, 2006
231
232
timeout.tv_sec = 10;
timeout.tv_usec = 0;
Jul 8, 2001
Jul 8, 2001
233
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
234
fprintf(stderr, "Waiting for audio to get ready\n");
Jul 8, 2001
Jul 8, 2001
235
#endif
Oct 7, 2006
Oct 7, 2006
236
if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) {
Jul 10, 2006
Jul 10, 2006
237
238
239
240
241
242
243
244
245
const char *message =
"Audio timeout - buggy audio driver? (disabled)";
/* In general we should never print to the screen,
but in this case we have no other way of letting
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
this->enabled = 0;
/* Don't try to close - may hang */
Oct 7, 2006
Oct 7, 2006
246
this->hidden->audio_fd = -1;
Jul 8, 2001
Jul 8, 2001
247
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
248
fprintf(stderr, "Done disabling audio\n");
Jul 8, 2001
Jul 8, 2001
249
#endif
Jul 10, 2006
Jul 10, 2006
250
}
Jul 8, 2001
Jul 8, 2001
251
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
252
fprintf(stderr, "Ready!\n");
253
#endif
Jul 10, 2006
Jul 10, 2006
254
}
255
256
257
258
#endif /* !USE_BLOCKING_WRITES */
}
static void
Oct 7, 2006
Oct 7, 2006
259
BSDAUDIO_PlayDevice(_THIS)
Jul 10, 2006
Jul 10, 2006
261
262
263
264
int written, p = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
Oct 7, 2006
Oct 7, 2006
265
266
267
268
written = write(this->hidden->audio_fd,
&this->hidden->mixbuf[p],
this->hidden->mixlen - p);
Jul 10, 2006
Jul 10, 2006
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
if (written > 0)
p += written;
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
break;
}
if (p < written
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
}
while (p < written);
/* If timer synchronization is enabled, set the next write frame */
Oct 7, 2006
Oct 7, 2006
285
286
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
Jul 10, 2006
Jul 10, 2006
287
288
289
290
291
292
}
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
}
Jul 8, 2001
Jul 8, 2001
293
#ifdef DEBUG_AUDIO
Jul 10, 2006
Jul 10, 2006
294
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
295
296
297
#endif
}
Jul 10, 2006
Jul 10, 2006
298
static Uint8 *
Oct 7, 2006
Oct 7, 2006
299
BSDAUDIO_GetDeviceBuf(_THIS)
Oct 7, 2006
Oct 7, 2006
301
return (this->hidden->mixbuf);
302
303
304
}
static void
Oct 7, 2006
Oct 7, 2006
305
BSDAUDIO_CloseDevice(_THIS)
Oct 7, 2006
Oct 7, 2006
307
308
309
310
311
312
313
314
315
316
317
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
318
319
320
}
}
Oct 7, 2006
Oct 7, 2006
321
322
static int
BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
Oct 7, 2006
Oct 7, 2006
324
325
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
326
327
audio_info_t info;
Oct 7, 2006
Oct 7, 2006
328
329
330
331
332
333
334
335
336
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
if ( ((iscapture) && (inputDeviceCount == 0)) ||
((!iscapture) && (outputDeviceCount == 0)) ) {
SDL_SetError("No such audio device");
return 0;
}
devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
337
338
}
Oct 7, 2006
Oct 7, 2006
339
340
341
342
343
344
345
346
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
Oct 7, 2006
Oct 7, 2006
348
349
350
351
352
353
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
return 0;
}
354
355
AUDIO_INITINFO(&info);
Jul 10, 2006
Jul 10, 2006
356
357
/* Calculate the final parameters for this audio specification */
Oct 7, 2006
Oct 7, 2006
358
SDL_CalculateAudioSpec(&this->spec);
Jul 10, 2006
Jul 10, 2006
359
360
361
/* Set to play mode */
info.mode = AUMODE_PLAY;
Oct 7, 2006
Oct 7, 2006
362
363
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
BSDAUDIO_CloseDevice(this);
Jul 10, 2006
Jul 10, 2006
364
SDL_SetError("Couldn't put device into play mode");
Oct 7, 2006
Oct 7, 2006
365
return 0;
Jul 10, 2006
Jul 10, 2006
367
Jul 31, 2001
Jul 31, 2001
368
AUDIO_INITINFO(&info);
Oct 7, 2006
Oct 7, 2006
369
for (format = SDL_FirstAudioFormat(this->spec.format);
Jul 10, 2006
Jul 10, 2006
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
format; format = SDL_NextAudioFormat()) {
switch (format) {
case AUDIO_U8:
info.play.encoding = AUDIO_ENCODING_ULINEAR;
info.play.precision = 8;
break;
case AUDIO_S8:
info.play.encoding = AUDIO_ENCODING_SLINEAR;
info.play.precision = 8;
break;
case AUDIO_S16LSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
info.play.precision = 16;
break;
case AUDIO_S16MSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
info.play.precision = 16;
break;
case AUDIO_U16LSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
info.play.precision = 16;
break;
case AUDIO_U16MSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
info.play.precision = 16;
break;
default:
continue;
}
Oct 7, 2006
Oct 7, 2006
399
400
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
Jul 10, 2006
Jul 10, 2006
401
break;
Oct 7, 2006
Oct 7, 2006
402
}
403
404
}
Jul 10, 2006
Jul 10, 2006
405
if (!format) {
Oct 7, 2006
Oct 7, 2006
406
407
408
BSDAUDIO_CloseDevice(this);
SDL_SetError("No supported encoding for 0x%x", this->spec.format);
return 0;
409
410
}
Oct 7, 2006
Oct 7, 2006
411
this->spec.format = format;
Jul 31, 2001
Jul 31, 2001
413
AUDIO_INITINFO(&info);
Oct 7, 2006
Oct 7, 2006
414
415
416
417
info.play.channels = this->spec.channels;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
Jul 31, 2001
Jul 31, 2001
418
AUDIO_INITINFO(&info);
Oct 7, 2006
Oct 7, 2006
419
420
info.play.sample_rate = this->spec.freq;
info.blocksize = this->spec.size;
Mar 21, 2006
Mar 21, 2006
421
422
info.hiwat = 5;
info.lowat = 3;
Oct 7, 2006
Oct 7, 2006
423
424
425
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
this->spec.freq = info.play.sample_rate;
426
/* Allocate mixing buffer */
Oct 7, 2006
Oct 7, 2006
427
428
429
430
431
432
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
BSDAUDIO_CloseDevice(this);
SDL_OutOfMemory();
return 0;
Oct 7, 2006
Oct 7, 2006
434
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
Oct 7, 2006
Oct 7, 2006
436
BSDAUDIO_Status(this);
437
438
/* We're ready to rock and roll. :-) */
Jul 10, 2006
Jul 10, 2006
439
return (0);
Jul 10, 2006
Jul 10, 2006
441
Oct 7, 2006
Oct 7, 2006
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
static int
BSDAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->GetDeviceName = DSP_GetDeviceName;
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->WaitDevice = DSP_WaitDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->Deinitialize = DSP_Deinitialize;
build_device_lists();
return 1;
}
AudioBootStrap BSD_AUDIO_bootstrap = {
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
BSDAUDIO_Available, BSDAUDIO_Init, 0
};
Jul 10, 2006
Jul 10, 2006
465
/* vi: set ts=4 sw=4 expandtab: */