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