SDL  2.0
SDL_sndioaudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #include "../../SDL_internal.h"
23 
24 #if SDL_AUDIO_DRIVER_SNDIO
25 
26 /* OpenBSD sndio target */
27 
28 #if HAVE_STDIO_H
29 #include <stdio.h>
30 #endif
31 
32 #ifdef HAVE_SIGNAL_H
33 #include <signal.h>
34 #endif
35 
36 #include <poll.h>
37 #include <unistd.h>
38 
39 #include "SDL_audio.h"
40 #include "../SDL_audio_c.h"
41 #include "SDL_sndioaudio.h"
42 
43 #ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
44 #include "SDL_loadso.h"
45 #endif
46 
47 #ifndef INFTIM
48 #define INFTIM -1
49 #endif
50 
51 #ifndef SIO_DEVANY
52 #define SIO_DEVANY "default"
53 #endif
54 
55 static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int);
56 static void (*SNDIO_sio_close)(struct sio_hdl *);
57 static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *);
58 static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *);
59 static int (*SNDIO_sio_start)(struct sio_hdl *);
60 static int (*SNDIO_sio_stop)(struct sio_hdl *);
61 static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t);
62 static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t);
63 static int (*SNDIO_sio_nfds)(struct sio_hdl *);
64 static int (*SNDIO_sio_pollfd)(struct sio_hdl *, struct pollfd *, int);
65 static int (*SNDIO_sio_revents)(struct sio_hdl *, struct pollfd *);
66 static int (*SNDIO_sio_eof)(struct sio_hdl *);
67 static void (*SNDIO_sio_initpar)(struct sio_par *);
68 
69 #ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
70 static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC;
71 static void *sndio_handle = NULL;
72 
73 static int
74 load_sndio_sym(const char *fn, void **addr)
75 {
76  *addr = SDL_LoadFunction(sndio_handle, fn);
77  if (*addr == NULL) {
78  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
79  return 0;
80  }
81 
82  return 1;
83 }
84 
85 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
86 #define SDL_SNDIO_SYM(x) \
87  if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1
88 #else
89 #define SDL_SNDIO_SYM(x) SNDIO_##x = x
90 #endif
91 
92 static int
93 load_sndio_syms(void)
94 {
95  SDL_SNDIO_SYM(sio_open);
96  SDL_SNDIO_SYM(sio_close);
97  SDL_SNDIO_SYM(sio_setpar);
98  SDL_SNDIO_SYM(sio_getpar);
99  SDL_SNDIO_SYM(sio_start);
100  SDL_SNDIO_SYM(sio_stop);
101  SDL_SNDIO_SYM(sio_read);
102  SDL_SNDIO_SYM(sio_write);
103  SDL_SNDIO_SYM(sio_nfds);
104  SDL_SNDIO_SYM(sio_pollfd);
105  SDL_SNDIO_SYM(sio_revents);
106  SDL_SNDIO_SYM(sio_eof);
107  SDL_SNDIO_SYM(sio_initpar);
108  return 0;
109 }
110 
111 #undef SDL_SNDIO_SYM
112 
113 #ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
114 
115 static void
116 UnloadSNDIOLibrary(void)
117 {
118  if (sndio_handle != NULL) {
119  SDL_UnloadObject(sndio_handle);
120  sndio_handle = NULL;
121  }
122 }
123 
124 static int
125 LoadSNDIOLibrary(void)
126 {
127  int retval = 0;
128  if (sndio_handle == NULL) {
129  sndio_handle = SDL_LoadObject(sndio_library);
130  if (sndio_handle == NULL) {
131  retval = -1;
132  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
133  } else {
134  retval = load_sndio_syms();
135  if (retval < 0) {
136  UnloadSNDIOLibrary();
137  }
138  }
139  }
140  return retval;
141 }
142 
143 #else
144 
145 static void
146 UnloadSNDIOLibrary(void)
147 {
148 }
149 
150 static int
151 LoadSNDIOLibrary(void)
152 {
153  load_sndio_syms();
154  return 0;
155 }
156 
157 #endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
158 
159 
160 
161 
162 static void
163 SNDIO_WaitDevice(_THIS)
164 {
165  /* no-op; SNDIO_sio_write() blocks if necessary. */
166 }
167 
168 static void
169 SNDIO_PlayDevice(_THIS)
170 {
171  const int written = SNDIO_sio_write(this->hidden->dev,
172  this->hidden->mixbuf,
173  this->hidden->mixlen);
174 
175  /* If we couldn't write, assume fatal error for now */
176  if ( written == 0 ) {
178  }
179 #ifdef DEBUG_AUDIO
180  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
181 #endif
182 }
183 
184 static int
185 SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
186 {
187  size_t r;
188  int revents;
189  int nfds;
190 
191  /* Emulate a blocking read */
192  r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
193  while (r == 0 && !SNDIO_sio_eof(this->hidden->dev)) {
194  if ((nfds = SNDIO_sio_pollfd(this->hidden->dev, this->hidden->pfd, POLLIN)) <= 0
195  || poll(this->hidden->pfd, nfds, INFTIM) < 0) {
196  return -1;
197  }
198  revents = SNDIO_sio_revents(this->hidden->dev, this->hidden->pfd);
199  if (revents & POLLIN) {
200  r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
201  }
202  if (revents & POLLHUP) {
203  break;
204  }
205  }
206  return (int) r;
207 }
208 
209 static void
210 SNDIO_FlushCapture(_THIS)
211 {
212  char buf[512];
213 
214  while (SNDIO_sio_read(this->hidden->dev, buf, sizeof(buf)) != 0) {
215  /* do nothing */;
216  }
217 }
218 
219 static Uint8 *
220 SNDIO_GetDeviceBuf(_THIS)
221 {
222  return this->hidden->mixbuf;
223 }
224 
225 static void
226 SNDIO_CloseDevice(_THIS)
227 {
228  if ( this->hidden->pfd != NULL ) {
229  SDL_free(this->hidden->pfd);
230  }
231  if ( this->hidden->dev != NULL ) {
232  SNDIO_sio_stop(this->hidden->dev);
233  SNDIO_sio_close(this->hidden->dev);
234  }
235  SDL_free(this->hidden->mixbuf);
236  SDL_free(this->hidden);
237 }
238 
239 static int
240 SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
241 {
242  SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
243  struct sio_par par;
244  int status;
245 
246  this->hidden = (struct SDL_PrivateAudioData *)
247  SDL_malloc(sizeof(*this->hidden));
248  if (this->hidden == NULL) {
249  return SDL_OutOfMemory();
250  }
251  SDL_zerop(this->hidden);
252 
253  this->hidden->mixlen = this->spec.size;
254 
255  /* Capture devices must be non-blocking for SNDIO_FlushCapture */
256  if ((this->hidden->dev =
257  SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
258  iscapture ? SIO_REC : SIO_PLAY, iscapture)) == NULL) {
259  return SDL_SetError("sio_open() failed");
260  }
261 
262  /* Allocate the pollfd array for capture devices */
263  if (iscapture && (this->hidden->pfd =
264  SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(this->hidden->dev))) == NULL) {
265  return SDL_OutOfMemory();
266  }
267 
268  SNDIO_sio_initpar(&par);
269 
270  par.rate = this->spec.freq;
271  par.pchan = this->spec.channels;
272  par.round = this->spec.samples;
273  par.appbufsz = par.round * 2;
274 
275  /* Try for a closest match on audio format */
276  status = -1;
277  while (test_format && (status < 0)) {
278  if (!SDL_AUDIO_ISFLOAT(test_format)) {
279  par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
280  par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
281  par.bits = SDL_AUDIO_BITSIZE(test_format);
282 
283  if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
284  continue;
285  }
286  if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
287  return SDL_SetError("sio_getpar() failed");
288  }
289  if (par.bps != SIO_BPS(par.bits)) {
290  continue;
291  }
292  if ((par.bits == 8 * par.bps) || (par.msb)) {
293  status = 0;
294  break;
295  }
296  }
297  test_format = SDL_NextAudioFormat();
298  }
299 
300  if (status < 0) {
301  return SDL_SetError("sndio: Couldn't find any hardware audio formats");
302  }
303 
304  if ((par.bps == 4) && (par.sig) && (par.le))
305  this->spec.format = AUDIO_S32LSB;
306  else if ((par.bps == 4) && (par.sig) && (!par.le))
307  this->spec.format = AUDIO_S32MSB;
308  else if ((par.bps == 2) && (par.sig) && (par.le))
309  this->spec.format = AUDIO_S16LSB;
310  else if ((par.bps == 2) && (par.sig) && (!par.le))
311  this->spec.format = AUDIO_S16MSB;
312  else if ((par.bps == 2) && (!par.sig) && (par.le))
313  this->spec.format = AUDIO_U16LSB;
314  else if ((par.bps == 2) && (!par.sig) && (!par.le))
315  this->spec.format = AUDIO_U16MSB;
316  else if ((par.bps == 1) && (par.sig))
317  this->spec.format = AUDIO_S8;
318  else if ((par.bps == 1) && (!par.sig))
319  this->spec.format = AUDIO_U8;
320  else {
321  return SDL_SetError("sndio: Got unsupported hardware audio format.");
322  }
323 
324  this->spec.freq = par.rate;
325  this->spec.channels = par.pchan;
326  this->spec.samples = par.round;
327 
328  /* Calculate the final parameters for this audio specification */
330 
331  /* Allocate mixing buffer */
332  this->hidden->mixlen = this->spec.size;
333  this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
334  if (this->hidden->mixbuf == NULL) {
335  return SDL_OutOfMemory();
336  }
337  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
338 
339  if (!SNDIO_sio_start(this->hidden->dev)) {
340  return SDL_SetError("sio_start() failed");
341  }
342 
343  /* We're ready to rock and roll. :-) */
344  return 0;
345 }
346 
347 static void
348 SNDIO_Deinitialize(void)
349 {
350  UnloadSNDIOLibrary();
351 }
352 
353 static int
354 SNDIO_Init(SDL_AudioDriverImpl * impl)
355 {
356  if (LoadSNDIOLibrary() < 0) {
357  return 0;
358  }
359 
360  /* Set the function pointers */
361  impl->OpenDevice = SNDIO_OpenDevice;
362  impl->WaitDevice = SNDIO_WaitDevice;
363  impl->PlayDevice = SNDIO_PlayDevice;
364  impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
365  impl->CloseDevice = SNDIO_CloseDevice;
366  impl->CaptureFromDevice = SNDIO_CaptureFromDevice;
367  impl->FlushCapture = SNDIO_FlushCapture;
368  impl->Deinitialize = SNDIO_Deinitialize;
369 
370  impl->AllowsArbitraryDeviceNames = 1;
371  impl->HasCaptureSupport = SDL_TRUE;
372 
373  return 1; /* this audio target is available. */
374 }
375 
377  "sndio", "OpenBSD sndio", SNDIO_Init, 0
378 };
379 
380 #endif /* SDL_AUDIO_DRIVER_SNDIO */
381 
382 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_AUDIO_ISLITTLEENDIAN(x)
Definition: SDL_audio.h:80
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1584
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:73
Uint16 samples
Definition: SDL_audio.h:183
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:72
#define SDL_AUDIO_ISSIGNED(x)
Definition: SDL_audio.h:78
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:449
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
AudioBootStrap SNDIO_bootstrap
#define SDL_LoadObject
#define SDL_UnloadObject
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1596
SDL_AudioSpec spec
Definition: loopwave.c:31
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
unsigned int size_t
SDL_bool retval
#define AUDIO_U8
Definition: SDL_audio.h:89
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
Uint8 channels
Definition: SDL_audio.h:181
#define _THIS
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
GLenum const void * addr
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:83
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1605
GLenum GLuint GLenum GLsizei const GLchar * buf
Uint32 size
Definition: SDL_audio.h:185
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:68
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
GLuint buffer
int(* CaptureFromDevice)(_THIS, void *buffer, int buflen)
Definition: SDL_sysaudio.h:76
#define SDL_SetError
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:79
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
SDL_AudioFormat format
Definition: SDL_audio.h:180
void(* FlushCapture)(_THIS)
Definition: SDL_sysaudio.h:77
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:75
#define SDL_malloc
void * SDL_LoadFunction(void *handle, const char *name)
#define AUDIO_S8
Definition: SDL_audio.h:90
#define SDL_memset
#define AUDIO_U16MSB
Definition: SDL_audio.h:93