Always use "OpenAL Soft" for the short device enumeration list
[openal-soft.git] / Alc / backends / sndio.c
blob4866a0a5313baf4e7b567ce76ea16ad9868a1f66
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.
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.
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
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)
79 if(!sndio_handle)
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
116 return ALC_TRUE;
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)
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)
144 ALsizei len = data->data_size;
145 ALubyte *WritePtr = data->mix_data;
147 aluMixData(device, WritePtr, len/frameSize);
148 while(len > 0 && !data->killNow)
150 wrote = sio_write(data->sndHandle, WritePtr, len);
151 if(wrote == 0)
153 ERR("sio_write failed\n");
154 aluHandleDisconnect(device);
155 break;
158 len -= wrote;
159 WritePtr += wrote;
163 return 0;
168 static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName)
170 sndio_data *data;
172 if(!deviceName)
173 deviceName = sndio_device;
174 else if(strcmp(deviceName, sndio_device) != 0)
175 return ALC_INVALID_VALUE;
177 data = calloc(1, sizeof(*data));
178 data->killNow = 0;
180 data->sndHandle = sio_open(NULL, SIO_PLAY, 0);
181 if(data->sndHandle == NULL)
183 free(data);
184 ERR("Could not open device\n");
185 return ALC_INVALID_VALUE;
188 device->szDeviceName = strdup(deviceName);
189 device->ExtraData = data;
191 return ALC_NO_ERROR;
194 static void sndio_close_playback(ALCdevice *device)
196 sndio_data *data = device->ExtraData;
198 sio_close(data->sndHandle);
199 free(data);
200 device->ExtraData = NULL;
203 static ALCboolean sndio_reset_playback(ALCdevice *device)
205 sndio_data *data = device->ExtraData;
206 struct sio_par par;
208 sio_initpar(&par);
210 par.rate = device->Frequency;
211 par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1);
213 switch(device->FmtType)
215 case DevFmtByte:
216 par.bits = 8;
217 par.sig = 1;
218 break;
219 case DevFmtUByte:
220 par.bits = 8;
221 par.sig = 0;
222 break;
223 case DevFmtFloat:
224 case DevFmtShort:
225 par.bits = 16;
226 par.sig = 1;
227 break;
228 case DevFmtUShort:
229 par.bits = 16;
230 par.sig = 0;
231 break;
232 case DevFmtInt:
233 par.bits = 32;
234 par.sig = 1;
235 break;
236 case DevFmtUInt:
237 par.bits = 32;
238 par.sig = 0;
239 break;
241 par.le = SIO_LE_NATIVE;
243 par.round = device->UpdateSize;
244 par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
245 if(!par.appbufsz) par.appbufsz = device->UpdateSize;
247 if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par))
249 ERR("Failed to set device parameters\n");
250 return ALC_FALSE;
253 if(par.bits != par.bps*8)
255 ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
256 return ALC_FALSE;
259 device->Frequency = par.rate;
260 device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
262 if(par.bits == 8 && par.sig == 1)
263 device->FmtType = DevFmtByte;
264 else if(par.bits == 8 && par.sig == 0)
265 device->FmtType = DevFmtUByte;
266 else if(par.bits == 16 && par.sig == 1)
267 device->FmtType = DevFmtShort;
268 else if(par.bits == 16 && par.sig == 0)
269 device->FmtType = DevFmtUShort;
270 else if(par.bits == 32 && par.sig == 1)
271 device->FmtType = DevFmtInt;
272 else if(par.bits == 32 && par.sig == 0)
273 device->FmtType = DevFmtUInt;
274 else
276 ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
277 return ALC_FALSE;
280 device->UpdateSize = par.round;
281 device->NumUpdates = (par.bufsz/par.round) + 1;
283 SetDefaultChannelOrder(device);
285 if(!sio_start(data->sndHandle))
287 ERR("Error starting playback\n");
288 return ALC_FALSE;
291 data->data_size = device->UpdateSize * par.bps * par.pchan;
292 data->mix_data = calloc(1, data->data_size);
294 data->thread = StartThread(sndio_proc, device);
295 if(data->thread == NULL)
297 sio_stop(data->sndHandle);
298 free(data->mix_data);
299 data->mix_data = NULL;
300 return ALC_FALSE;
303 return ALC_TRUE;
306 static void sndio_stop_playback(ALCdevice *device)
308 sndio_data *data = device->ExtraData;
310 if(!data->thread)
311 return;
313 data->killNow = 1;
314 StopThread(data->thread);
315 data->thread = NULL;
317 data->killNow = 0;
318 if(!sio_stop(data->sndHandle))
319 ERR("Error stopping device\n");
321 free(data->mix_data);
322 data->mix_data = NULL;
326 static const BackendFuncs sndio_funcs = {
327 sndio_open_playback,
328 sndio_close_playback,
329 sndio_reset_playback,
330 sndio_stop_playback,
331 NULL,
332 NULL,
333 NULL,
334 NULL,
335 NULL,
336 NULL
339 ALCboolean alc_sndio_init(BackendFuncs *func_list)
341 if(!sndio_load())
342 return ALC_FALSE;
343 *func_list = sndio_funcs;
344 return ALC_TRUE;
347 void alc_sndio_deinit(void)
349 #ifdef HAVE_DYNLOAD
350 if(sndio_handle)
351 CloseLib(sndio_handle);
352 sndio_handle = NULL;
353 #endif
356 void alc_sndio_probe(enum DevProbe type)
358 switch(type)
360 case ALL_DEVICE_PROBE:
361 AppendAllDeviceList(sndio_device);
362 break;
363 case CAPTURE_DEVICE_PROBE:
364 break;