SDL  2.0
SDL_sndioaudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 <unistd.h>
37 
38 #include "SDL_audio.h"
39 #include "../SDL_audiomem.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 static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int);
48 static void (*SNDIO_sio_close)(struct sio_hdl *);
49 static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *);
50 static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *);
51 static int (*SNDIO_sio_start)(struct sio_hdl *);
52 static int (*SNDIO_sio_stop)(struct sio_hdl *);
53 static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t);
54 static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t);
55 static void (*SNDIO_sio_initpar)(struct sio_par *);
56 
57 #ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
58 static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC;
59 static void *sndio_handle = NULL;
60 
61 static int
62 load_sndio_sym(const char *fn, void **addr)
63 {
64  *addr = SDL_LoadFunction(sndio_handle, fn);
65  if (*addr == NULL) {
66  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
67  return 0;
68  }
69 
70  return 1;
71 }
72 
73 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
74 #define SDL_SNDIO_SYM(x) \
75  if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1
76 #else
77 #define SDL_SNDIO_SYM(x) SNDIO_##x = x
78 #endif
79 
80 static int
81 load_sndio_syms(void)
82 {
83  SDL_SNDIO_SYM(sio_open);
84  SDL_SNDIO_SYM(sio_close);
85  SDL_SNDIO_SYM(sio_setpar);
86  SDL_SNDIO_SYM(sio_getpar);
87  SDL_SNDIO_SYM(sio_start);
88  SDL_SNDIO_SYM(sio_stop);
89  SDL_SNDIO_SYM(sio_read);
90  SDL_SNDIO_SYM(sio_write);
91  SDL_SNDIO_SYM(sio_initpar);
92  return 0;
93 }
94 
95 #undef SDL_SNDIO_SYM
96 
97 #ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
98 
99 static void
100 UnloadSNDIOLibrary(void)
101 {
102  if (sndio_handle != NULL) {
103  SDL_UnloadObject(sndio_handle);
104  sndio_handle = NULL;
105  }
106 }
107 
108 static int
109 LoadSNDIOLibrary(void)
110 {
111  int retval = 0;
112  if (sndio_handle == NULL) {
113  sndio_handle = SDL_LoadObject(sndio_library);
114  if (sndio_handle == NULL) {
115  retval = -1;
116  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
117  } else {
118  retval = load_sndio_syms();
119  if (retval < 0) {
120  UnloadSNDIOLibrary();
121  }
122  }
123  }
124  return retval;
125 }
126 
127 #else
128 
129 static void
130 UnloadSNDIOLibrary(void)
131 {
132 }
133 
134 static int
135 LoadSNDIOLibrary(void)
136 {
137  load_sndio_syms();
138  return 0;
139 }
140 
141 #endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
142 
143 
144 
145 
146 static void
147 SNDIO_WaitDevice(_THIS)
148 {
149  /* no-op; SNDIO_sio_write() blocks if necessary. */
150 }
151 
152 static void
153 SNDIO_PlayDevice(_THIS)
154 {
155  const int written = SNDIO_sio_write(this->hidden->dev,
156  this->hidden->mixbuf,
157  this->hidden->mixlen);
158 
159  /* If we couldn't write, assume fatal error for now */
160  if ( written == 0 ) {
162  }
163 #ifdef DEBUG_AUDIO
164  fprintf(stderr, "Wrote %d bytes of audio data\n", written);
165 #endif
166 }
167 
168 static Uint8 *
169 SNDIO_GetDeviceBuf(_THIS)
170 {
171  return this->hidden->mixbuf;
172 }
173 
174 static void
175 SNDIO_WaitDone(_THIS)
176 {
177  SNDIO_sio_stop(this->hidden->dev);
178 }
179 
180 static void
181 SNDIO_CloseDevice(_THIS)
182 {
183  if (this->hidden != NULL) {
184  SDL_FreeAudioMem(this->hidden->mixbuf);
185  this->hidden->mixbuf = NULL;
186  if ( this->hidden->dev != NULL ) {
187  SNDIO_sio_close(this->hidden->dev);
188  this->hidden->dev = NULL;
189  }
190  SDL_free(this->hidden);
191  this->hidden = NULL;
192  }
193 }
194 
195 static int
196 SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
197 {
198  SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
199  struct sio_par par;
200  int status;
201 
202  this->hidden = (struct SDL_PrivateAudioData *)
203  SDL_malloc(sizeof(*this->hidden));
204  if (this->hidden == NULL) {
205  return SDL_OutOfMemory();
206  }
207  SDL_memset(this->hidden, 0, sizeof(*this->hidden));
208 
209  this->hidden->mixlen = this->spec.size;
210 
211  /* !!! FIXME: SIO_DEVANY can be a specific device... */
212  if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) {
213  SNDIO_CloseDevice(this);
214  return SDL_SetError("sio_open() failed");
215  }
216 
217  SNDIO_sio_initpar(&par);
218 
219  par.rate = this->spec.freq;
220  par.pchan = this->spec.channels;
221  par.round = this->spec.samples;
222  par.appbufsz = par.round * 2;
223 
224  /* Try for a closest match on audio format */
225  status = -1;
226  while (test_format && (status < 0)) {
227  if (!SDL_AUDIO_ISFLOAT(test_format)) {
228  par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
229  par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
230  par.bits = SDL_AUDIO_BITSIZE(test_format);
231 
232  if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
233  continue;
234  }
235  if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
236  SNDIO_CloseDevice(this);
237  return SDL_SetError("sio_getpar() failed");
238  }
239  if (par.bps != SIO_BPS(par.bits)) {
240  continue;
241  }
242  if ((par.bits == 8 * par.bps) || (par.msb)) {
243  status = 0;
244  break;
245  }
246  }
247  test_format = SDL_NextAudioFormat();
248  }
249 
250  if (status < 0) {
251  SNDIO_CloseDevice(this);
252  return SDL_SetError("sndio: Couldn't find any hardware audio formats");
253  }
254 
255  if ((par.bps == 4) && (par.sig) && (par.le))
256  this->spec.format = AUDIO_S32LSB;
257  else if ((par.bps == 4) && (par.sig) && (!par.le))
258  this->spec.format = AUDIO_S32MSB;
259  else if ((par.bps == 2) && (par.sig) && (par.le))
260  this->spec.format = AUDIO_S16LSB;
261  else if ((par.bps == 2) && (par.sig) && (!par.le))
262  this->spec.format = AUDIO_S16MSB;
263  else if ((par.bps == 2) && (!par.sig) && (par.le))
264  this->spec.format = AUDIO_U16LSB;
265  else if ((par.bps == 2) && (!par.sig) && (!par.le))
266  this->spec.format = AUDIO_U16MSB;
267  else if ((par.bps == 1) && (par.sig))
268  this->spec.format = AUDIO_S8;
269  else if ((par.bps == 1) && (!par.sig))
270  this->spec.format = AUDIO_U8;
271  else {
272  SNDIO_CloseDevice(this);
273  return SDL_SetError("sndio: Got unsupported hardware audio format.");
274  }
275 
276  this->spec.freq = par.rate;
277  this->spec.channels = par.pchan;
278  this->spec.samples = par.round;
279 
280  /* Calculate the final parameters for this audio specification */
282 
283  /* Allocate mixing buffer */
284  this->hidden->mixlen = this->spec.size;
285  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
286  if (this->hidden->mixbuf == NULL) {
287  SNDIO_CloseDevice(this);
288  return SDL_OutOfMemory();
289  }
290  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
291 
292  if (!SNDIO_sio_start(this->hidden->dev)) {
293  return SDL_SetError("sio_start() failed");
294  }
295 
296  /* We're ready to rock and roll. :-) */
297  return 0;
298 }
299 
300 static void
301 SNDIO_Deinitialize(void)
302 {
303  UnloadSNDIOLibrary();
304 }
305 
306 static int
307 SNDIO_Init(SDL_AudioDriverImpl * impl)
308 {
309  if (LoadSNDIOLibrary() < 0) {
310  return 0;
311  }
312 
313  /* Set the function pointers */
314  impl->OpenDevice = SNDIO_OpenDevice;
315  impl->WaitDevice = SNDIO_WaitDevice;
316  impl->PlayDevice = SNDIO_PlayDevice;
317  impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
318  impl->WaitDone = SNDIO_WaitDone;
319  impl->CloseDevice = SNDIO_CloseDevice;
320  impl->Deinitialize = SNDIO_Deinitialize;
321  impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: sndio can handle multiple devices. */
322 
323  return 1; /* this audio target is available. */
324 }
325 
327  "sndio", "OpenBSD sndio", SNDIO_Init, 0
328 };
329 
330 #endif /* SDL_AUDIO_DRIVER_SNDIO */
331 
332 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_AUDIO_ISLITTLEENDIAN(x)
Definition: SDL_audio.h:80
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1398
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:75
Uint16 samples
Definition: SDL_audio.h:174
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:74
#define SDL_AUDIO_ISSIGNED(x)
Definition: SDL_audio.h:78
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Definition: SDL_audio.c:364
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
#define SDL_LoadObject
#define SDL_UnloadObject
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1410
SDL_AudioSpec spec
Definition: loopwave.c:35
#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
Uint8 channels
Definition: SDL_audio.h:172
#define _THIS
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
void SDL_free(void *mem)
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:1419
#define SDL_AllocAudioMem
Definition: SDL_audiomem.h:23
Uint32 size
Definition: SDL_audio.h:176
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:72
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
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
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:79
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
SDL_AudioFormat format
Definition: SDL_audio.h:171
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:77
#define SDL_malloc
void * SDL_LoadFunction(void *handle, const char *name)
#define AUDIO_S8
Definition: SDL_audio.h:90
#define SDL_memset
void(* WaitDone)(_THIS)
Definition: SDL_sysaudio.h:78
AudioBootStrap SNDIO_bootstrap
#define AUDIO_U16MSB
Definition: SDL_audio.h:93