Skip to content

Latest commit

 

History

History
418 lines (358 loc) · 12.1 KB

SDL_netbsdaudio.c

File metadata and controls

418 lines (358 loc) · 12.1 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 2, 2017
Jan 2, 2017
3
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
May 24, 2017
May 24, 2017
23
#if SDL_AUDIO_DRIVER_NETBSD
May 24, 2017
May 24, 2017
26
* Driver for native NetBSD audio(4).
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
* 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>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
Jun 29, 2017
Jun 29, 2017
43
#include "SDL_netbsdaudio.h"
44
45
46
47
48
49
50
51
52
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
static void
May 24, 2017
May 24, 2017
53
NETBSDAUDIO_DetectDevices(void)
54
55
56
57
58
59
{
SDL_EnumUnixAudioDevices(0, NULL);
}
static void
May 24, 2017
May 24, 2017
60
NETBSDAUDIO_Status(_THIS)
61
62
63
64
{
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */
audio_info_t info;
Aug 3, 2016
Aug 3, 2016
65
const audio_prinfo *prinfo;
66
67
68
69
70
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
Aug 3, 2016
Aug 3, 2016
71
72
73
prinfo = this->iscapture ? &info.play : &info.record;
74
fprintf(stderr, "\n"
Aug 3, 2016
Aug 3, 2016
75
"[%s info]\n"
76
77
78
79
80
81
82
83
84
85
86
87
88
"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"
"",
Aug 3, 2016
Aug 3, 2016
89
90
91
92
93
94
95
96
97
98
99
100
101
this->iscapture ? "record" : "play",
prinfo->buffer_size,
prinfo->sample_rate,
prinfo->channels,
prinfo->precision,
prinfo->encoding,
prinfo->seek,
prinfo->samples,
prinfo->eof,
prinfo->pause ? "yes" : "no",
prinfo->error ? "yes" : "no",
prinfo->waiting ? "yes" : "no",
prinfo->active ? "yes" : "no");
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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" : "?"));
/* *INDENT-ON* */
#endif /* DEBUG_AUDIO */
}
/* This function waits until it is possible to write a full sound buffer */
static void
May 24, 2017
May 24, 2017
124
NETBSDAUDIO_WaitDevice(_THIS)
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */
if (this->hidden->frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
} else {
/* Use select() for audio synchronization */
fd_set fdset;
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(this->hidden->audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
<= 0) {
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);
SDL_OpenedAudioDeviceDisconnected(this);
/* Don't try to close - may hang */
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
#endif /* !USE_BLOCKING_WRITES */
}
static void
May 24, 2017
May 24, 2017
172
NETBSDAUDIO_PlayDevice(_THIS)
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
{
int written, p = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(this->hidden->audio_fd,
&this->hidden->mixbuf[p], this->hidden->mixlen - p);
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;
}
Aug 3, 2016
Aug 3, 2016
189
190
191
192
193
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
if (p < this->hidden->mixlen
194
195
196
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
Aug 3, 2016
Aug 3, 2016
197
} while (p < this->hidden->mixlen);
198
199
200
201
202
203
204
205
206
207
208
209
210
/* If timer synchronization is enabled, set the next write frame */
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
static Uint8 *
May 24, 2017
May 24, 2017
211
NETBSDAUDIO_GetDeviceBuf(_THIS)
212
213
214
215
{
return (this->hidden->mixbuf);
}
Aug 3, 2016
Aug 3, 2016
216
217
static int
May 24, 2017
May 24, 2017
218
NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
Aug 3, 2016
Aug 3, 2016
219
220
221
222
{
Uint8 *buffer = (Uint8 *) _buffer;
int br, p = 0;
Jul 1, 2017
Jul 1, 2017
223
/* Capture the audio data, checking for EAGAIN on broken audio drivers */
Aug 3, 2016
Aug 3, 2016
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
do {
br = read(this->hidden->audio_fd, buffer + p, buflen - p);
if (br > 0)
p += br;
if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
return p ? p : -1;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Captured %d bytes of audio data\n", br);
#endif
if (p < buflen
|| ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while (p < buflen);
}
static void
May 24, 2017
May 24, 2017
246
NETBSDAUDIO_FlushCapture(_THIS)
Aug 3, 2016
Aug 3, 2016
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
{
audio_info_t info;
size_t remain;
Uint8 buf[512];
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return; /* oh well. */
}
remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8));
while (remain > 0) {
const size_t len = SDL_min(sizeof (buf), remain);
const int br = read(this->hidden->audio_fd, buf, len);
if (br <= 0) {
return; /* oh well. */
}
remain -= br;
}
}
May 24, 2017
May 24, 2017
268
NETBSDAUDIO_CloseDevice(_THIS)
Aug 5, 2016
Aug 5, 2016
270
271
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
Aug 5, 2016
Aug 5, 2016
273
SDL_free(this->hidden->mixbuf);
Aug 5, 2016
Aug 5, 2016
274
SDL_free(this->hidden);
May 24, 2017
May 24, 2017
278
NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
Aug 3, 2016
Aug 3, 2016
280
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
281
282
SDL_AudioFormat format = 0;
audio_info_t info;
Aug 3, 2016
Aug 3, 2016
283
audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/* 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) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
}
}
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
Aug 5, 2016
Aug 5, 2016
300
SDL_zerop(this->hidden);
301
302
303
304
305
306
307
308
309
310
311
312
313
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
AUDIO_INITINFO(&info);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Set to play mode */
Aug 3, 2016
Aug 3, 2016
314
info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
315
316
317
318
319
320
321
322
323
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
return SDL_SetError("Couldn't put device into play mode");
}
AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(this->spec.format);
format; format = SDL_NextAudioFormat()) {
switch (format) {
case AUDIO_U8:
Aug 3, 2016
Aug 3, 2016
324
325
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
prinfo->precision = 8;
326
327
break;
case AUDIO_S8:
Aug 3, 2016
Aug 3, 2016
328
329
prinfo->encoding = AUDIO_ENCODING_SLINEAR;
prinfo->precision = 8;
330
331
break;
case AUDIO_S16LSB:
Aug 3, 2016
Aug 3, 2016
332
333
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
prinfo->precision = 16;
334
335
break;
case AUDIO_S16MSB:
Aug 3, 2016
Aug 3, 2016
336
337
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 16;
338
339
break;
case AUDIO_U16LSB:
Aug 3, 2016
Aug 3, 2016
340
341
prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
prinfo->precision = 16;
342
343
break;
case AUDIO_U16MSB:
Aug 3, 2016
Aug 3, 2016
344
345
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
prinfo->precision = 16;
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
break;
default:
continue;
}
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
break;
}
}
if (!format) {
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
}
this->spec.format = format;
AUDIO_INITINFO(&info);
Aug 3, 2016
Aug 3, 2016
363
prinfo->channels = this->spec.channels;
364
365
366
367
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
AUDIO_INITINFO(&info);
Aug 3, 2016
Aug 3, 2016
368
prinfo->sample_rate = this->spec.freq;
369
370
371
372
373
info.blocksize = this->spec.size;
info.hiwat = 5;
info.lowat = 3;
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
Aug 3, 2016
Aug 3, 2016
374
375
376
377
378
this->spec.freq = prinfo->sample_rate;
if (!iscapture) {
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
Aug 5, 2016
Aug 5, 2016
379
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
Aug 3, 2016
Aug 3, 2016
380
381
382
383
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
May 24, 2017
May 24, 2017
386
NETBSDAUDIO_Status(this);
387
388
389
390
391
392
/* We're ready to rock and roll. :-) */
return 0;
}
static int
May 24, 2017
May 24, 2017
393
NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl)
394
395
{
/* Set the function pointers */
May 24, 2017
May 24, 2017
396
397
398
399
400
401
402
403
impl->DetectDevices = NETBSDAUDIO_DetectDevices;
impl->OpenDevice = NETBSDAUDIO_OpenDevice;
impl->PlayDevice = NETBSDAUDIO_PlayDevice;
impl->WaitDevice = NETBSDAUDIO_WaitDevice;
impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
impl->CloseDevice = NETBSDAUDIO_CloseDevice;
impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;
impl->FlushCapture = NETBSDAUDIO_FlushCapture;
Aug 3, 2016
Aug 3, 2016
405
impl->HasCaptureSupport = SDL_TRUE;
406
407
408
409
410
411
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
May 24, 2017
May 24, 2017
412
413
AudioBootStrap NETBSDAUDIO_bootstrap = {
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0
May 24, 2017
May 24, 2017
416
#endif /* SDL_AUDIO_DRIVER_NETBSD */
417
418
/* vi: set ts=4 sw=4 expandtab: */