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

Latest commit

 

History

History
434 lines (382 loc) · 11.2 KB

SDL_bsdaudio.c

File metadata and controls

434 lines (382 loc) · 11.2 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
64
65
66
67
68
69
/* 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
#define OPEN_FLAGS O_WRONLY
#else
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
#endif
/* Audio driver functions */
May 29, 2006
May 29, 2006
70
71
72
73
74
static void OBSD_WaitAudio(_THIS);
static int OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void OBSD_PlayAudio(_THIS);
static Uint8 *OBSD_GetAudioBuf(_THIS);
static void OBSD_CloseAudio(_THIS);
75
76
#ifdef DEBUG_AUDIO
May 29, 2006
May 29, 2006
77
static void OBSD_Status(_THIS);
78
79
80
81
82
#endif
/* Audio driver bootstrap functions */
static int
May 29, 2006
May 29, 2006
83
Audio_Available(void)
84
85
86
87
88
{
int fd;
int available;
available = 0;
May 29, 2006
May 29, 2006
89
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
May 28, 2006
May 28, 2006
90
91
if (fd >= 0) {
available = 1;
May 29, 2006
May 29, 2006
92
close(fd);
May 28, 2006
May 28, 2006
94
return (available);
95
96
97
}
static void
May 29, 2006
May 29, 2006
98
Audio_DeleteDevice(SDL_AudioDevice * device)
May 29, 2006
May 29, 2006
100
101
SDL_free(device->hidden);
SDL_free(device);
May 28, 2006
May 28, 2006
104
static SDL_AudioDevice *
May 29, 2006
May 29, 2006
105
Audio_CreateDevice(int devindex)
106
107
108
109
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
May 29, 2006
May 29, 2006
110
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
May 28, 2006
May 28, 2006
111
if (this) {
May 29, 2006
May 29, 2006
112
SDL_memset(this, 0, (sizeof *this));
May 28, 2006
May 28, 2006
113
this->hidden = (struct SDL_PrivateAudioData *)
May 29, 2006
May 29, 2006
114
SDL_malloc((sizeof *this->hidden));
May 28, 2006
May 28, 2006
116
if ((this == NULL) || (this->hidden == NULL)) {
May 29, 2006
May 29, 2006
117
SDL_OutOfMemory();
May 28, 2006
May 28, 2006
118
if (this)
May 29, 2006
May 29, 2006
119
SDL_free(this);
May 28, 2006
May 28, 2006
120
return (0);
May 29, 2006
May 29, 2006
122
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
123
124
125
126
127
128
129
130
131
132
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = OBSD_OpenAudio;
this->WaitAudio = OBSD_WaitAudio;
this->PlayAudio = OBSD_PlayAudio;
this->GetAudioBuf = OBSD_GetAudioBuf;
this->CloseAudio = OBSD_CloseAudio;
this->free = Audio_DeleteDevice;
May 28, 2006
May 28, 2006
133
134
135
136
return this;
}
Mar 22, 2006
Mar 22, 2006
137
AudioBootStrap BSD_AUDIO_bootstrap = {
May 28, 2006
May 28, 2006
138
139
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
Audio_Available, Audio_CreateDevice
140
141
142
143
};
/* This function waits until it is possible to write a full sound buffer */
static void
May 29, 2006
May 29, 2006
144
OBSD_WaitAudio(_THIS)
May 28, 2006
May 28, 2006
146
147
148
149
150
151
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */
if (frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
May 29, 2006
May 29, 2006
152
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
May 28, 2006
May 28, 2006
153
if (ticks > 0) {
May 29, 2006
May 29, 2006
154
SDL_Delay(ticks);
May 28, 2006
May 28, 2006
155
156
157
158
159
160
}
} else {
/* Use select() for audio synchronization */
fd_set fdset;
struct timeval timeout;
May 29, 2006
May 29, 2006
161
162
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
May 28, 2006
May 28, 2006
163
164
timeout.tv_sec = 10;
timeout.tv_usec = 0;
Jul 8, 2001
Jul 8, 2001
165
#ifdef DEBUG_AUDIO
May 29, 2006
May 29, 2006
166
fprintf(stderr, "Waiting for audio to get ready\n");
Jul 8, 2001
Jul 8, 2001
167
#endif
May 29, 2006
May 29, 2006
168
if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) {
May 28, 2006
May 28, 2006
169
170
171
172
173
174
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.
*/
May 29, 2006
May 29, 2006
175
fprintf(stderr, "SDL: %s\n", message);
May 28, 2006
May 28, 2006
176
177
178
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
Jul 8, 2001
Jul 8, 2001
179
#ifdef DEBUG_AUDIO
May 29, 2006
May 29, 2006
180
fprintf(stderr, "Done disabling audio\n");
Jul 8, 2001
Jul 8, 2001
181
#endif
May 28, 2006
May 28, 2006
182
}
Jul 8, 2001
Jul 8, 2001
183
#ifdef DEBUG_AUDIO
May 29, 2006
May 29, 2006
184
fprintf(stderr, "Ready!\n");
185
#endif
May 28, 2006
May 28, 2006
186
}
187
188
189
190
#endif /* !USE_BLOCKING_WRITES */
}
static void
May 29, 2006
May 29, 2006
191
OBSD_PlayAudio(_THIS)
May 28, 2006
May 28, 2006
193
194
195
196
int written, p = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
May 29, 2006
May 29, 2006
197
written = write(audio_fd, &mixbuf[p], mixlen - p);
May 28, 2006
May 28, 2006
198
199
200
201
if (written > 0)
p += written;
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
/* Non recoverable error has occurred. It should be reported!!! */
May 29, 2006
May 29, 2006
202
perror("audio");
May 28, 2006
May 28, 2006
203
204
205
206
207
break;
}
if (p < written
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
May 29, 2006
May 29, 2006
208
SDL_Delay(1); /* Let a little CPU time go by */
May 28, 2006
May 28, 2006
209
210
211
212
213
214
215
216
217
218
219
220
221
}
}
while (p < written);
/* If timer synchronization is enabled, set the next write frame */
if (frame_ticks) {
next_frame += frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
}
Jul 8, 2001
Jul 8, 2001
222
#ifdef DEBUG_AUDIO
May 29, 2006
May 29, 2006
223
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
224
225
226
#endif
}
May 28, 2006
May 28, 2006
227
static Uint8 *
May 29, 2006
May 29, 2006
228
OBSD_GetAudioBuf(_THIS)
May 28, 2006
May 28, 2006
230
return (mixbuf);
231
232
233
}
static void
May 29, 2006
May 29, 2006
234
OBSD_CloseAudio(_THIS)
May 28, 2006
May 28, 2006
236
if (mixbuf != NULL) {
May 29, 2006
May 29, 2006
237
SDL_FreeAudioMem(mixbuf);
May 28, 2006
May 28, 2006
238
mixbuf = NULL;
May 28, 2006
May 28, 2006
240
if (audio_fd >= 0) {
May 29, 2006
May 29, 2006
241
close(audio_fd);
May 28, 2006
May 28, 2006
242
audio_fd = -1;
243
244
245
246
247
}
}
#ifdef DEBUG_AUDIO
void
May 29, 2006
May 29, 2006
248
OBSD_Status(_THIS)
249
250
251
{
audio_info_t info;
May 29, 2006
May 29, 2006
252
253
if (ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
May 28, 2006
May 28, 2006
254
return;
255
256
}
May 29, 2006
May 29, 2006
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
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");
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" : "?"));
327
328
329
330
}
#endif /* DEBUG_AUDIO */
static int
May 29, 2006
May 29, 2006
331
OBSD_OpenAudio(_THIS, SDL_AudioSpec * spec)
332
333
{
char audiodev[64];
Jul 31, 2001
Jul 31, 2001
334
Uint16 format;
335
336
audio_info_t info;
May 29, 2006
May 29, 2006
337
AUDIO_INITINFO(&info);
May 28, 2006
May 28, 2006
338
339
/* Calculate the final parameters for this audio specification */
May 29, 2006
May 29, 2006
340
SDL_CalculateAudioSpec(spec);
341
342
343
344
345
346
#ifdef USE_TIMER_SYNC
frame_ticks = 0.0;
#endif
/* Open the audio device */
May 29, 2006
May 29, 2006
347
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
May 28, 2006
May 28, 2006
348
if (audio_fd < 0) {
May 29, 2006
May 29, 2006
349
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
May 28, 2006
May 28, 2006
350
return (-1);
May 28, 2006
May 28, 2006
352
353
354
/* Set to play mode */
info.mode = AUMODE_PLAY;
May 29, 2006
May 29, 2006
355
356
if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
SDL_SetError("Couldn't put device into play mode");
May 28, 2006
May 28, 2006
357
return (-1);
May 28, 2006
May 28, 2006
359
360
mixbuf = NULL;
May 29, 2006
May 29, 2006
361
362
363
AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(spec->format);
format; format = SDL_NextAudioFormat()) {
May 28, 2006
May 28, 2006
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
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;
}
May 29, 2006
May 29, 2006
392
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
May 28, 2006
May 28, 2006
393
break;
394
395
}
May 28, 2006
May 28, 2006
396
if (!format) {
May 29, 2006
May 29, 2006
397
SDL_SetError("No supported encoding for 0x%x", spec->format);
May 28, 2006
May 28, 2006
398
return (-1);
399
400
}
Jul 31, 2001
Jul 31, 2001
401
spec->format = format;
May 29, 2006
May 29, 2006
403
AUDIO_INITINFO(&info);
404
info.play.channels = spec->channels;
May 29, 2006
May 29, 2006
405
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1)
May 28, 2006
May 28, 2006
406
spec->channels = 1;
May 29, 2006
May 29, 2006
407
AUDIO_INITINFO(&info);
408
info.play.sample_rate = spec->freq;
Mar 21, 2006
Mar 21, 2006
409
410
411
info.blocksize = spec->size;
info.hiwat = 5;
info.lowat = 3;
May 29, 2006
May 29, 2006
412
413
(void) ioctl(audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(audio_fd, AUDIO_GETINFO, &info);
May 28, 2006
May 28, 2006
414
spec->freq = info.play.sample_rate;
415
416
/* Allocate mixing buffer */
mixlen = spec->size;
May 29, 2006
May 29, 2006
417
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
May 28, 2006
May 28, 2006
418
419
if (mixbuf == NULL) {
return (-1);
May 29, 2006
May 29, 2006
421
SDL_memset(mixbuf, spec->silence, spec->size);
May 28, 2006
May 28, 2006
422
423
/* Get the parent process id (we're the parent of the audio thread) */
May 29, 2006
May 29, 2006
424
parent = getpid();
425
426
#ifdef DEBUG_AUDIO
May 29, 2006
May 29, 2006
427
OBSD_Status(this);
428
429
430
#endif
/* We're ready to rock and roll. :-) */
May 28, 2006
May 28, 2006
431
return (0);
May 28, 2006
May 28, 2006
433
434
/* vi: set ts=4 sw=4 expandtab: */