Skip to content

Latest commit

 

History

History
382 lines (319 loc) · 10.2 KB

SDL_sndioaudio.c

File metadata and controls

382 lines (319 loc) · 10.2 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 3, 2018
Jan 3, 2018
3
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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"
#if SDL_AUDIO_DRIVER_SNDIO
/* OpenBSD sndio target */
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
Jul 20, 2017
Jul 20, 2017
36
#include <poll.h>
37
38
39
40
41
42
43
44
45
46
#include <unistd.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_sndioaudio.h"
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
#include "SDL_loadso.h"
#endif
Aug 7, 2017
Aug 7, 2017
47
48
49
50
#ifndef INFTIM
#define INFTIM -1
#endif
Sep 2, 2017
Sep 2, 2017
51
52
53
54
#ifndef SIO_DEVANY
#define SIO_DEVANY "default"
#endif
55
56
57
58
59
60
61
62
static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int);
static void (*SNDIO_sio_close)(struct sio_hdl *);
static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *);
static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *);
static int (*SNDIO_sio_start)(struct sio_hdl *);
static int (*SNDIO_sio_stop)(struct sio_hdl *);
static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t);
static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t);
Jul 20, 2017
Jul 20, 2017
63
64
65
66
static int (*SNDIO_sio_nfds)(struct sio_hdl *);
static int (*SNDIO_sio_pollfd)(struct sio_hdl *, struct pollfd *, int);
static int (*SNDIO_sio_revents)(struct sio_hdl *, struct pollfd *);
static int (*SNDIO_sio_eof)(struct sio_hdl *);
67
68
69
70
71
72
73
74
75
76
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
static void (*SNDIO_sio_initpar)(struct sio_par *);
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC;
static void *sndio_handle = NULL;
static int
load_sndio_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(sndio_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_SNDIO_SYM(x) \
if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1
#else
#define SDL_SNDIO_SYM(x) SNDIO_##x = x
#endif
static int
load_sndio_syms(void)
{
SDL_SNDIO_SYM(sio_open);
SDL_SNDIO_SYM(sio_close);
SDL_SNDIO_SYM(sio_setpar);
SDL_SNDIO_SYM(sio_getpar);
SDL_SNDIO_SYM(sio_start);
SDL_SNDIO_SYM(sio_stop);
SDL_SNDIO_SYM(sio_read);
SDL_SNDIO_SYM(sio_write);
Jul 20, 2017
Jul 20, 2017
103
104
105
106
SDL_SNDIO_SYM(sio_nfds);
SDL_SNDIO_SYM(sio_pollfd);
SDL_SNDIO_SYM(sio_revents);
SDL_SNDIO_SYM(sio_eof);
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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
172
173
174
175
176
177
178
179
180
181
182
183
SDL_SNDIO_SYM(sio_initpar);
return 0;
}
#undef SDL_SNDIO_SYM
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
static void
UnloadSNDIOLibrary(void)
{
if (sndio_handle != NULL) {
SDL_UnloadObject(sndio_handle);
sndio_handle = NULL;
}
}
static int
LoadSNDIOLibrary(void)
{
int retval = 0;
if (sndio_handle == NULL) {
sndio_handle = SDL_LoadObject(sndio_library);
if (sndio_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
retval = load_sndio_syms();
if (retval < 0) {
UnloadSNDIOLibrary();
}
}
}
return retval;
}
#else
static void
UnloadSNDIOLibrary(void)
{
}
static int
LoadSNDIOLibrary(void)
{
load_sndio_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
static void
SNDIO_WaitDevice(_THIS)
{
/* no-op; SNDIO_sio_write() blocks if necessary. */
}
static void
SNDIO_PlayDevice(_THIS)
{
const int written = SNDIO_sio_write(this->hidden->dev,
this->hidden->mixbuf,
this->hidden->mixlen);
/* If we couldn't write, assume fatal error for now */
if ( written == 0 ) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
Jul 20, 2017
Jul 20, 2017
184
185
186
static int
SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
Jul 20, 2017
Jul 20, 2017
187
size_t r;
Jul 20, 2017
Jul 20, 2017
188
189
190
191
int revents;
int nfds;
/* Emulate a blocking read */
Jul 20, 2017
Jul 20, 2017
192
193
r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
while (r == 0 && !SNDIO_sio_eof(this->hidden->dev)) {
Jul 20, 2017
Jul 20, 2017
194
if ((nfds = SNDIO_sio_pollfd(this->hidden->dev, this->hidden->pfd, POLLIN)) <= 0
Jul 21, 2017
Jul 21, 2017
195
|| poll(this->hidden->pfd, nfds, INFTIM) < 0) {
Jul 20, 2017
Jul 20, 2017
196
return -1;
Jul 20, 2017
Jul 20, 2017
197
}
Jul 20, 2017
Jul 20, 2017
198
revents = SNDIO_sio_revents(this->hidden->dev, this->hidden->pfd);
Jul 20, 2017
Jul 20, 2017
199
if (revents & POLLIN) {
Jul 20, 2017
Jul 20, 2017
200
r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
Jul 20, 2017
Jul 20, 2017
201
202
203
204
205
}
if (revents & POLLHUP) {
break;
}
}
Jul 20, 2017
Jul 20, 2017
206
return (int) r;
Jul 20, 2017
Jul 20, 2017
207
208
209
210
211
212
213
214
215
216
217
218
}
static void
SNDIO_FlushCapture(_THIS)
{
char buf[512];
while (SNDIO_sio_read(this->hidden->dev, buf, sizeof(buf)) != 0) {
/* do nothing */;
}
}
219
220
221
222
223
224
225
226
227
static Uint8 *
SNDIO_GetDeviceBuf(_THIS)
{
return this->hidden->mixbuf;
}
static void
SNDIO_CloseDevice(_THIS)
{
Jul 20, 2017
Jul 20, 2017
228
229
230
if ( this->hidden->pfd != NULL ) {
SDL_free(this->hidden->pfd);
}
Aug 5, 2016
Aug 5, 2016
231
if ( this->hidden->dev != NULL ) {
Oct 7, 2016
Oct 7, 2016
232
SNDIO_sio_stop(this->hidden->dev);
Aug 5, 2016
Aug 5, 2016
233
SNDIO_sio_close(this->hidden->dev);
Aug 5, 2016
Aug 5, 2016
235
SDL_free(this->hidden->mixbuf);
Aug 5, 2016
Aug 5, 2016
236
SDL_free(this->hidden);
237
238
239
240
241
242
243
244
245
246
247
248
249
250
}
static int
SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
struct sio_par par;
int status;
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
Aug 5, 2016
Aug 5, 2016
251
SDL_zerop(this->hidden);
252
253
254
this->hidden->mixlen = this->spec.size;
Jul 20, 2017
Jul 20, 2017
255
256
/* Capture devices must be non-blocking for SNDIO_FlushCapture */
if ((this->hidden->dev =
Jul 20, 2017
Jul 20, 2017
257
SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
Jul 20, 2017
Jul 20, 2017
258
iscapture ? SIO_REC : SIO_PLAY, iscapture)) == NULL) {
259
260
261
return SDL_SetError("sio_open() failed");
}
Jul 20, 2017
Jul 20, 2017
262
263
264
265
266
267
/* Allocate the pollfd array for capture devices */
if (iscapture && (this->hidden->pfd =
SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(this->hidden->dev))) == NULL) {
return SDL_OutOfMemory();
}
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
327
328
329
330
331
332
SNDIO_sio_initpar(&par);
par.rate = this->spec.freq;
par.pchan = this->spec.channels;
par.round = this->spec.samples;
par.appbufsz = par.round * 2;
/* Try for a closest match on audio format */
status = -1;
while (test_format && (status < 0)) {
if (!SDL_AUDIO_ISFLOAT(test_format)) {
par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
par.bits = SDL_AUDIO_BITSIZE(test_format);
if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
continue;
}
if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
return SDL_SetError("sio_getpar() failed");
}
if (par.bps != SIO_BPS(par.bits)) {
continue;
}
if ((par.bits == 8 * par.bps) || (par.msb)) {
status = 0;
break;
}
}
test_format = SDL_NextAudioFormat();
}
if (status < 0) {
return SDL_SetError("sndio: Couldn't find any hardware audio formats");
}
if ((par.bps == 4) && (par.sig) && (par.le))
this->spec.format = AUDIO_S32LSB;
else if ((par.bps == 4) && (par.sig) && (!par.le))
this->spec.format = AUDIO_S32MSB;
else if ((par.bps == 2) && (par.sig) && (par.le))
this->spec.format = AUDIO_S16LSB;
else if ((par.bps == 2) && (par.sig) && (!par.le))
this->spec.format = AUDIO_S16MSB;
else if ((par.bps == 2) && (!par.sig) && (par.le))
this->spec.format = AUDIO_U16LSB;
else if ((par.bps == 2) && (!par.sig) && (!par.le))
this->spec.format = AUDIO_U16MSB;
else if ((par.bps == 1) && (par.sig))
this->spec.format = AUDIO_S8;
else if ((par.bps == 1) && (!par.sig))
this->spec.format = AUDIO_U8;
else {
return SDL_SetError("sndio: Got unsupported hardware audio format.");
}
this->spec.freq = par.rate;
this->spec.channels = par.pchan;
this->spec.samples = par.round;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
Aug 5, 2016
Aug 5, 2016
333
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
if (!SNDIO_sio_start(this->hidden->dev)) {
return SDL_SetError("sio_start() failed");
}
/* We're ready to rock and roll. :-) */
return 0;
}
static void
SNDIO_Deinitialize(void)
{
UnloadSNDIOLibrary();
}
static int
SNDIO_Init(SDL_AudioDriverImpl * impl)
{
if (LoadSNDIOLibrary() < 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = SNDIO_OpenDevice;
impl->WaitDevice = SNDIO_WaitDevice;
impl->PlayDevice = SNDIO_PlayDevice;
impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
impl->CloseDevice = SNDIO_CloseDevice;
Jul 20, 2017
Jul 20, 2017
366
367
impl->CaptureFromDevice = SNDIO_CaptureFromDevice;
impl->FlushCapture = SNDIO_FlushCapture;
368
impl->Deinitialize = SNDIO_Deinitialize;
Jul 20, 2017
Jul 20, 2017
369
370
371
impl->AllowsArbitraryDeviceNames = 1;
impl->HasCaptureSupport = SDL_TRUE;
372
373
374
375
376
377
378
379
380
381
382
return 1; /* this audio target is available. */
}
AudioBootStrap SNDIO_bootstrap = {
"sndio", "OpenBSD sndio", SNDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_SNDIO */
/* vi: set ts=4 sw=4 expandtab: */