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
33 static const ALCchar sndio_device
[] = "SndIO Default";
36 static void *sndio_handle
;
38 #define MAKE_FUNC(x) static typeof(x) * p##x
39 MAKE_FUNC(sio_initpar
);
42 MAKE_FUNC(sio_setpar
);
43 MAKE_FUNC(sio_getpar
);
44 MAKE_FUNC(sio_getcap
);
45 MAKE_FUNC(sio_onmove
);
51 MAKE_FUNC(sio_pollfd
);
52 MAKE_FUNC(sio_revents
);
54 MAKE_FUNC(sio_setvol
);
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
77 static ALCboolean
sndio_load(void)
82 sndio_handle
= LoadLib("libsndio.so");
86 #define LOAD_FUNC(f) do { \
87 p##f = GetSymbol(sndio_handle, #f); \
89 CloseLib(sndio_handle); \
90 sndio_handle = NULL; \
94 LOAD_FUNC(sio_initpar
);
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
);
103 LOAD_FUNC(sio_start
);
106 LOAD_FUNC(sio_pollfd
);
107 LOAD_FUNC(sio_revents
);
109 LOAD_FUNC(sio_setvol
);
110 LOAD_FUNC(sio_onvol
);
113 sndio_handle
= (void*)0xDEADBEEF;
121 struct sio_hdl
*sndHandle
;
126 volatile int killNow
;
131 static ALuint
sndio_proc(ALvoid
*ptr
)
133 ALCdevice
*device
= ptr
;
134 sndio_data
*data
= device
->ExtraData
;
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
);
153 ERR("sio_write failed\n");
154 aluHandleDisconnect(device
);
168 static ALCenum
sndio_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
173 deviceName
= sndio_device
;
174 else if(strcmp(deviceName
, sndio_device
) != 0)
175 return ALC_INVALID_VALUE
;
177 data
= calloc(1, sizeof(*data
));
180 data
->sndHandle
= sio_open(NULL
, SIO_PLAY
, 0);
181 if(data
->sndHandle
== NULL
)
184 ERR("Could not open device\n");
185 return ALC_INVALID_VALUE
;
188 device
->szDeviceName
= strdup(deviceName
);
189 device
->ExtraData
= data
;
194 static void sndio_close_playback(ALCdevice
*device
)
196 sndio_data
*data
= device
->ExtraData
;
198 sio_close(data
->sndHandle
);
200 device
->ExtraData
= NULL
;
203 static ALCboolean
sndio_reset_playback(ALCdevice
*device
)
205 sndio_data
*data
= device
->ExtraData
;
210 par
.rate
= device
->Frequency
;
212 par
.pchan
= ((device
->FmtChans
!= DevFmtMono
) ? 2 : 1);
214 switch(device
->FmtType
)
225 device
->FmtType
= DevFmtShort
;
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
))
245 ERR("Failed to set device parameters\n");
249 if(par
.rate
!= device
->Frequency
)
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
;
257 if(par
.pchan
!= ChannelsFromDevFmt(device
->FmtChans
))
259 if(par
.pchan
!= 1 && par
.pchan
!= 2)
261 ERR("Unhandled channel count: %u\n", par
.pchan
);
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
);
270 if(par
.bits
!= par
.bps
*8)
272 ERR("Padded samples not supported (%u of %u bits)\n", par
.bits
, par
.bps
*8);
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
;
286 ERR("Unhandled sample format: %s %u-bit\n", (par
.sig
?"signed":"unsigned"), par
.bits
);
291 device
->UpdateSize
= par
.round
;
292 device
->NumUpdates
= (par
.bufsz
/par
.round
) + 1;
294 SetDefaultChannelOrder(device
);
297 if(!sio_start(data
->sndHandle
))
299 ERR("Error starting playback\n");
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
)
309 sio_stop(data
->sndHandle
);
310 free(data
->mix_data
);
311 data
->mix_data
= NULL
;
318 static void sndio_stop_playback(ALCdevice
*device
)
320 sndio_data
*data
= device
->ExtraData
;
326 StopThread(data
->thread
);
330 if(!sio_stop(data
->sndHandle
))
331 ERR("Error stopping device\n");
333 free(data
->mix_data
);
334 data
->mix_data
= NULL
;
338 static const BackendFuncs sndio_funcs
= {
340 sndio_close_playback
,
341 sndio_reset_playback
,
351 ALCboolean
alc_sndio_init(BackendFuncs
*func_list
)
355 *func_list
= sndio_funcs
;
359 void alc_sndio_deinit(void)
363 CloseLib(sndio_handle
);
368 void alc_sndio_probe(enum DevProbe type
)
373 AppendDeviceList(sndio_device
);
375 case ALL_DEVICE_PROBE
:
376 AppendAllDeviceList(sndio_device
);
378 case CAPTURE_DEVICE_PROBE
: