view Alc/backends/sndio.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
line wrap: on
line source
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
19 */
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
30 #include <sndio.h>
33 static const ALCchar sndio_device[] = "SndIO Default";
36 static void *sndio_handle;
37 #ifdef HAVE_DYNLOAD
38 #define MAKE_FUNC(x) static typeof(x) * p##x
39 MAKE_FUNC(sio_initpar);
40 MAKE_FUNC(sio_open);
41 MAKE_FUNC(sio_close);
42 MAKE_FUNC(sio_setpar);
43 MAKE_FUNC(sio_getpar);
44 MAKE_FUNC(sio_getcap);
45 MAKE_FUNC(sio_onmove);
46 MAKE_FUNC(sio_write);
47 MAKE_FUNC(sio_read);
48 MAKE_FUNC(sio_start);
49 MAKE_FUNC(sio_stop);
50 MAKE_FUNC(sio_nfds);
51 MAKE_FUNC(sio_pollfd);
52 MAKE_FUNC(sio_revents);
53 MAKE_FUNC(sio_eof);
54 MAKE_FUNC(sio_setvol);
55 MAKE_FUNC(sio_onvol);
57 #define sio_initpar psio_initpar
58 #define sio_open psio_open
59 #define sio_close psio_close
60 #define sio_setpar psio_setpar
61 #define sio_getpar psio_getpar
62 #define sio_getcap psio_getcap
63 #define sio_onmove psio_onmove
64 #define sio_write psio_write
65 #define sio_read psio_read
66 #define sio_start psio_start
67 #define sio_stop psio_stop
68 #define sio_nfds psio_nfds
69 #define sio_pollfd psio_pollfd
70 #define sio_revents psio_revents
71 #define sio_eof psio_eof
72 #define sio_setvol psio_setvol
73 #define sio_onvol psio_onvol
74 #endif
77 static ALCboolean sndio_load(void)
78 {
79 if(!sndio_handle)
80 {
81 #ifdef HAVE_DYNLOAD
82 sndio_handle = LoadLib("libsndio.so");
83 if(!sndio_handle)
84 return ALC_FALSE;
86 #define LOAD_FUNC(f) do { \
87 p##f = GetSymbol(sndio_handle, #f); \
88 if(p##f == NULL) { \
89 CloseLib(sndio_handle); \
90 sndio_handle = NULL; \
91 return ALC_FALSE; \
92 } \
93 } while(0)
94 LOAD_FUNC(sio_initpar);
95 LOAD_FUNC(sio_open);
96 LOAD_FUNC(sio_close);
97 LOAD_FUNC(sio_setpar);
98 LOAD_FUNC(sio_getpar);
99 LOAD_FUNC(sio_getcap);
100 LOAD_FUNC(sio_onmove);
101 LOAD_FUNC(sio_write);
102 LOAD_FUNC(sio_read);
103 LOAD_FUNC(sio_start);
104 LOAD_FUNC(sio_stop);
105 LOAD_FUNC(sio_nfds);
106 LOAD_FUNC(sio_pollfd);
107 LOAD_FUNC(sio_revents);
108 LOAD_FUNC(sio_eof);
109 LOAD_FUNC(sio_setvol);
110 LOAD_FUNC(sio_onvol);
111 #undef LOAD_FUNC
112 #else
113 sndio_handle = (void*)0xDEADBEEF;
114 #endif
115 }
116 return ALC_TRUE;
117 }
120 typedef struct {
121 struct sio_hdl *sndHandle;
123 ALvoid *mix_data;
124 ALsizei data_size;
126 volatile int killNow;
127 ALvoid *thread;
128 } sndio_data;
131 static ALuint sndio_proc(ALvoid *ptr)
132 {
133 ALCdevice *device = ptr;
134 sndio_data *data = device->ExtraData;
135 ALsizei frameSize;
136 size_t wrote;
138 SetRTPriority();
140 frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
142 while(!data->killNow && device->Connected)
143 {
144 ALsizei len = data->data_size;
145 ALubyte *WritePtr = data->mix_data;
147 aluMixData(device, WritePtr, len/frameSize);
148 while(len > 0 && !data->killNow)
149 {
150 wrote = sio_write(data->sndHandle, WritePtr, len);
151 if(wrote == 0)
152 {
153 ERR("sio_write failed\n");
154 aluHandleDisconnect(device);
155 break;
156 }
158 len -= wrote;
159 WritePtr += wrote;
160 }
161 }
163 return 0;
164 }
168 static ALCboolean sndio_open_playback(ALCdevice *device, const ALCchar *deviceName)
169 {
170 sndio_data *data;
172 if(!deviceName)
173 deviceName = sndio_device;
174 else if(strcmp(deviceName, sndio_device) != 0)
175 return ALC_FALSE;
177 data = calloc(1, sizeof(*data));
178 data->killNow = 0;
180 data->sndHandle = sio_open(NULL, SIO_PLAY, 0);
181 if(data->sndHandle == NULL)
182 {
183 free(data);
184 ERR("Could not open device\n");
185 return ALC_FALSE;
186 }
188 device->szDeviceName = strdup(deviceName);
189 device->ExtraData = data;
191 return ALC_TRUE;
192 }
194 static void sndio_close_playback(ALCdevice *device)
195 {
196 sndio_data *data = device->ExtraData;
198 sio_close(data->sndHandle);
199 free(data);
200 device->ExtraData = NULL;
201 }
203 static ALCboolean sndio_reset_playback(ALCdevice *device)
204 {
205 sndio_data *data = device->ExtraData;
206 struct sio_par par;
208 sio_initpar(&par);
210 par.rate = device->Frequency;
212 par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1);
214 switch(device->FmtType)
215 {
216 case DevFmtByte:
217 par.bits = 8;
218 par.sig = 1;
219 break;
220 case DevFmtUByte:
221 par.bits = 8;
222 par.sig = 0;
223 break;
224 case DevFmtFloat:
225 device->FmtType = DevFmtShort;
226 /* fall-through */
227 case DevFmtShort:
228 par.bits = 16;
229 par.sig = 1;
230 break;
231 case DevFmtUShort:
232 par.bits = 16;
233 par.sig = 0;
234 break;
235 }
236 par.le = SIO_LE_NATIVE;
238 par.round = device->UpdateSize;
239 par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
240 if(!par.appbufsz) par.appbufsz = device->UpdateSize;
243 if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par))
244 {
245 ERR("Failed to set device parameters\n");
246 return ALC_FALSE;
247 }
249 if(par.rate != device->Frequency)
250 {
251 if((device->Flags&DEVICE_FREQUENCY_REQUEST))
252 ERR("Failed to set frequency %uhz, got %uhz instead\n", device->Frequency, par.rate);
253 device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
254 device->Frequency = par.rate;
255 }
257 if(par.pchan != ChannelsFromDevFmt(device->FmtChans))
258 {
259 if(par.pchan != 1 && par.pchan != 2)
260 {
261 ERR("Unhandled channel count: %u\n", par.pchan);
262 return ALC_FALSE;
263 }
264 if((device->Flags&DEVICE_CHANNELS_REQUEST))
265 ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), par.pchan);
266 device->Flags &= ~DEVICE_CHANNELS_REQUEST;
267 device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
268 }
270 if(par.bits != par.bps*8)
271 {
272 ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
273 return ALC_FALSE;
274 }
276 if(par.bits == 8 && par.sig == 1)
277 device->FmtType = DevFmtByte;
278 else if(par.bits == 8 && par.sig == 0)
279 device->FmtType = DevFmtUByte;
280 else if(par.bits == 16 && par.sig == 1)
281 device->FmtType = DevFmtShort;
282 else if(par.bits == 16 && par.sig == 0)
283 device->FmtType = DevFmtUShort;
284 else
285 {
286 ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
287 return ALC_FALSE;
288 }
291 device->UpdateSize = par.round;
292 device->NumUpdates = (par.bufsz/par.round) + 1;
294 SetDefaultChannelOrder(device);
297 if(!sio_start(data->sndHandle))
298 {
299 ERR("Error starting playback\n");
300 return ALC_FALSE;
301 }
303 data->data_size = device->UpdateSize * par.bps * par.pchan;
304 data->mix_data = calloc(1, data->data_size);
306 data->thread = StartThread(sndio_proc, device);
307 if(data->thread == NULL)
308 {
309 sio_stop(data->sndHandle);
310 free(data->mix_data);
311 data->mix_data = NULL;
312 return ALC_FALSE;
313 }
315 return ALC_TRUE;
316 }
318 static void sndio_stop_playback(ALCdevice *device)
319 {
320 sndio_data *data = device->ExtraData;
322 if(!data->thread)
323 return;
325 data->killNow = 1;
326 StopThread(data->thread);
327 data->thread = NULL;
329 data->killNow = 0;
330 if(!sio_stop(data->sndHandle))
331 ERR("Error stopping device\n");
333 free(data->mix_data);
334 data->mix_data = NULL;
335 }
338 static const BackendFuncs sndio_funcs = {
339 sndio_open_playback,
340 sndio_close_playback,
341 sndio_reset_playback,
342 sndio_stop_playback,
343 NULL,
344 NULL,
345 NULL,
346 NULL,
347 NULL,
348 NULL
349 };
351 ALCboolean alc_sndio_init(BackendFuncs *func_list)
352 {
353 if(!sndio_load())
354 return ALC_FALSE;
355 *func_list = sndio_funcs;
356 return ALC_TRUE;
357 }
359 void alc_sndio_deinit(void)
360 {
361 #ifdef HAVE_DYNLOAD
362 if(sndio_handle)
363 CloseLib(sndio_handle);
364 sndio_handle = NULL;
365 #endif
366 }
368 void alc_sndio_probe(enum DevProbe type)
369 {
370 switch(type)
371 {
372 case DEVICE_PROBE:
373 AppendDeviceList(sndio_device);
374 break;
375 case ALL_DEVICE_PROBE:
376 AppendAllDeviceList(sndio_device);
377 break;
378 case CAPTURE_DEVICE_PROBE:
379 break;
380 }
381 }