Skip to content

Latest commit

 

History

History
412 lines (353 loc) · 12 KB

SDL_netbsdaudio.c

File metadata and controls

412 lines (353 loc) · 12 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
* 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"
Aug 15, 2017
Aug 15, 2017
41
#include "../../core/unix/SDL_poll.h"
42
43
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
Jun 29, 2017
Jun 29, 2017
44
#include "SDL_netbsdaudio.h"
45
46
47
48
49
50
51
52
53
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
static void
May 24, 2017
May 24, 2017
54
NETBSDAUDIO_DetectDevices(void)
55
56
57
58
59
60
{
SDL_EnumUnixAudioDevices(0, NULL);
}
static void
May 24, 2017
May 24, 2017
61
NETBSDAUDIO_Status(_THIS)
62
63
64
65
{
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */
audio_info_t info;
Aug 3, 2016
Aug 3, 2016
66
const audio_prinfo *prinfo;
67
68
69
70
71
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
Aug 3, 2016
Aug 3, 2016
72
73
74
prinfo = this->iscapture ? &info.play : &info.record;
75
fprintf(stderr, "\n"
Aug 3, 2016
Aug 3, 2016
76
"[%s info]\n"
77
78
79
80
81
82
83
84
85
86
87
88
89
"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
90
91
92
93
94
95
96
97
98
99
100
101
102
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");
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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
125
NETBSDAUDIO_WaitDevice(_THIS)
126
127
128
129
130
131
132
133
134
135
136
137
{
#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 {
Aug 15, 2017
Aug 15, 2017
138
/* Use SDL_IOReady() for audio synchronization */
139
140
141
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
Aug 15, 2017
Aug 15, 2017
142
if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, 10 * 1000)
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<= 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
166
NETBSDAUDIO_PlayDevice(_THIS)
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
{
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
183
184
185
186
187
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
if (p < this->hidden->mixlen
188
189
190
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
Aug 3, 2016
Aug 3, 2016
191
} while (p < this->hidden->mixlen);
192
193
194
195
196
197
198
199
200
201
202
203
204
/* 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
205
NETBSDAUDIO_GetDeviceBuf(_THIS)
206
207
208
209
{
return (this->hidden->mixbuf);
}
Aug 3, 2016
Aug 3, 2016
210
211
static int
May 24, 2017
May 24, 2017
212
NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
Aug 3, 2016
Aug 3, 2016
213
214
215
216
{
Uint8 *buffer = (Uint8 *) _buffer;
int br, p = 0;
Jul 1, 2017
Jul 1, 2017
217
/* Capture the audio data, checking for EAGAIN on broken audio drivers */
Aug 3, 2016
Aug 3, 2016
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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
240
NETBSDAUDIO_FlushCapture(_THIS)
Aug 3, 2016
Aug 3, 2016
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
{
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
262
NETBSDAUDIO_CloseDevice(_THIS)
Aug 5, 2016
Aug 5, 2016
264
265
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
Aug 5, 2016
Aug 5, 2016
267
SDL_free(this->hidden->mixbuf);
Aug 5, 2016
Aug 5, 2016
268
SDL_free(this->hidden);
May 24, 2017
May 24, 2017
272
NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
Aug 3, 2016
Aug 3, 2016
274
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
275
276
SDL_AudioFormat format = 0;
audio_info_t info;
Aug 3, 2016
Aug 3, 2016
277
audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* 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
294
SDL_zerop(this->hidden);
295
296
297
298
299
300
301
302
303
304
305
306
307
/* 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
308
info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
309
310
311
312
313
314
315
316
317
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
318
319
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
prinfo->precision = 8;
320
321
break;
case AUDIO_S8:
Aug 3, 2016
Aug 3, 2016
322
323
prinfo->encoding = AUDIO_ENCODING_SLINEAR;
prinfo->precision = 8;
324
325
break;
case AUDIO_S16LSB:
Aug 3, 2016
Aug 3, 2016
326
327
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
prinfo->precision = 16;
328
329
break;
case AUDIO_S16MSB:
Aug 3, 2016
Aug 3, 2016
330
331
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 16;
332
333
break;
case AUDIO_U16LSB:
Aug 3, 2016
Aug 3, 2016
334
335
prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
prinfo->precision = 16;
336
337
break;
case AUDIO_U16MSB:
Aug 3, 2016
Aug 3, 2016
338
339
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
prinfo->precision = 16;
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
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
357
prinfo->channels = this->spec.channels;
358
359
360
361
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
AUDIO_INITINFO(&info);
Aug 3, 2016
Aug 3, 2016
362
prinfo->sample_rate = this->spec.freq;
363
364
365
366
367
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
368
369
370
371
372
this->spec.freq = prinfo->sample_rate;
if (!iscapture) {
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
Aug 5, 2016
Aug 5, 2016
373
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
Aug 3, 2016
Aug 3, 2016
374
375
376
377
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
380
NETBSDAUDIO_Status(this);
381
382
383
384
385
386
/* We're ready to rock and roll. :-) */
return 0;
}
static int
May 24, 2017
May 24, 2017
387
NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl)
388
389
{
/* Set the function pointers */
May 24, 2017
May 24, 2017
390
391
392
393
394
395
396
397
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
399
impl->HasCaptureSupport = SDL_TRUE;
400
401
402
403
404
405
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
May 24, 2017
May 24, 2017
406
407
AudioBootStrap NETBSDAUDIO_bootstrap = {
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0
May 24, 2017
May 24, 2017
410
#endif /* SDL_AUDIO_DRIVER_NETBSD */
411
412
/* vi: set ts=4 sw=4 expandtab: */