zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_sndioaudio.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.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 ) {
161  this->enabled = 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, 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(NULL, 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) == 1) {
233  status = 0;
234  break;
235  }
236  }
237  test_format = SDL_NextAudioFormat();
238  }
239 
240  if (status < 0) {
241  SNDIO_CloseDevice(this);
242  return SDL_SetError("sndio: Couldn't find any hardware audio formats");
243  }
244 
245  if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
246  SNDIO_CloseDevice(this);
247  return SDL_SetError("sio_getpar() failed");
248  }
249 
250  if ((par.bits == 32) && (par.sig) && (par.le))
251  this->spec.format = AUDIO_S32LSB;
252  else if ((par.bits == 32) && (par.sig) && (!par.le))
253  this->spec.format = AUDIO_S32MSB;
254  else if ((par.bits == 16) && (par.sig) && (par.le))
255  this->spec.format = AUDIO_S16LSB;
256  else if ((par.bits == 16) && (par.sig) && (!par.le))
257  this->spec.format = AUDIO_S16MSB;
258  else if ((par.bits == 16) && (!par.sig) && (par.le))
259  this->spec.format = AUDIO_U16LSB;
260  else if ((par.bits == 16) && (!par.sig) && (!par.le))
261  this->spec.format = AUDIO_U16MSB;
262  else if ((par.bits == 8) && (par.sig))
263  this->spec.format = AUDIO_S8;
264  else if ((par.bits == 8) && (!par.sig))
265  this->spec.format = AUDIO_U8;
266  else {
267  SNDIO_CloseDevice(this);
268  return SDL_SetError("sndio: Got unsupported hardware audio format.");
269  }
270 
271  this->spec.freq = par.rate;
272  this->spec.channels = par.pchan;
273  this->spec.samples = par.round;
274 
275  /* Calculate the final parameters for this audio specification */
276  SDL_CalculateAudioSpec(&this->spec);
277 
278  /* Allocate mixing buffer */
279  this->hidden->mixlen = this->spec.size;
280  this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
281  if (this->hidden->mixbuf == NULL) {
282  SNDIO_CloseDevice(this);
283  return SDL_OutOfMemory();
284  }
285  SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
286 
287  if (!SNDIO_sio_start(this->hidden->dev)) {
288  return SDL_SetError("sio_start() failed");
289  }
290 
291  /* We're ready to rock and roll. :-) */
292  return 0;
293 }
294 
295 static void
296 SNDIO_Deinitialize(void)
297 {
298  UnloadSNDIOLibrary();
299 }
300 
301 static int
302 SNDIO_Init(SDL_AudioDriverImpl * impl)
303 {
304  if (LoadSNDIOLibrary() < 0) {
305  return 0;
306  }
307 
308  /* Set the function pointers */
309  impl->OpenDevice = SNDIO_OpenDevice;
310  impl->WaitDevice = SNDIO_WaitDevice;
311  impl->PlayDevice = SNDIO_PlayDevice;
312  impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
313  impl->WaitDone = SNDIO_WaitDone;
314  impl->CloseDevice = SNDIO_CloseDevice;
315  impl->Deinitialize = SNDIO_Deinitialize;
316  impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: sndio can handle multiple devices. */
317 
318  return 1; /* this audio target is available. */
319 }
320 
322  "sndio", "OpenBSD sndio", SNDIO_Init, 0
323 };
324 
325 #endif /* SDL_AUDIO_DRIVER_SNDIO */
326 
327 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
#define SDL_AUDIO_ISLITTLEENDIAN(x)
Definition: SDL_audio.h:80
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1226
#define AUDIO_S32MSB
Definition: SDL_audio.h:104
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
#define NULL
Definition: ftobjs.h:61
#define AUDIO_U16LSB
Definition: SDL_audio.h:91
GLenum GLvoid * addr
Definition: glew.h:10667
GLenum GLsizei const GLuint GLboolean enabled
Definition: glew.h:2538
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
#define SDL_FreeAudioMem
Definition: SDL_audiomem.h:24
DECLSPEC void SDLCALL SDL_free(void *mem)
#define SDL_AUDIO_ISSIGNED(x)
Definition: SDL_audio.h:78
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
void(* WaitDone)(_THIS)
Definition: SDL_sysaudio.h:44
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:39
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
#define AUDIO_U8
Definition: SDL_audio.h:89
int
Definition: SDL_systhread.c:37
#define _THIS
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
#define AUDIO_S32LSB
Definition: SDL_audio.h:103
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1247
void(* Deinitialize)(void)
Definition: SDL_sysaudio.h:48
#define SDL_AllocAudioMem
Definition: SDL_audiomem.h:23
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define AUDIO_S16MSB
Definition: SDL_audio.h:94
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
#define AUDIO_S16LSB
Definition: SDL_audio.h:92
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)
#define AUDIO_S8
Definition: SDL_audio.h:90
AudioBootStrap SNDIO_bootstrap
unsigned int size_t
#define AUDIO_U16MSB
Definition: SDL_audio.h:93