Properly initialize with the default distance model
[openal-soft.git] / Alc / backends / sndio.c
blob47e05353902e695c3016a5847ae24ff6014bdd83
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "threads.h"
31 #include "backends/base.h"
33 #include <sndio.h>
38 typedef struct ALCsndioBackend {
39 DERIVE_FROM_TYPE(ALCbackend);
41 struct sio_hdl *sndHandle;
43 ALvoid *mix_data;
44 ALsizei data_size;
46 volatile int killNow;
47 althrd_t thread;
48 } ALCsndioBackend;
50 static int ALCsndioBackend_mixerProc(void *ptr);
52 static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device);
53 static void ALCsndioBackend_Destruct(ALCsndioBackend *self);
54 static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name);
55 static void ALCsndioBackend_close(ALCsndioBackend *self);
56 static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self);
57 static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self);
58 static void ALCsndioBackend_stop(ALCsndioBackend *self);
59 static DECLARE_FORWARD2(ALCsndioBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
60 static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ALCuint, availableSamples)
61 static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ClockLatency, getClockLatency)
62 static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, lock)
63 static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, unlock)
64 DECLARE_DEFAULT_ALLOCATORS(ALCsndioBackend)
66 DEFINE_ALCBACKEND_VTABLE(ALCsndioBackend);
69 static const ALCchar sndio_device[] = "SndIO Default";
72 static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device)
74 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
75 SET_VTABLE2(ALCsndioBackend, ALCbackend, self);
78 static void ALCsndioBackend_Destruct(ALCsndioBackend *self)
80 if(self->sndHandle)
81 sio_close(self->sndHandle);
82 self->sndHandle = NULL;
84 al_free(self->mix_data);
85 self->mix_data = NULL;
87 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
91 static int ALCsndioBackend_mixerProc(void *ptr)
93 ALCsndioBackend *self = (ALCsndioBackend*)ptr;
94 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
95 ALsizei frameSize;
96 size_t wrote;
98 SetRTPriority();
99 althrd_setname(althrd_current(), MIXER_THREAD_NAME);
101 frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
103 while(!self->killNow && device->Connected)
105 ALsizei len = self->data_size;
106 ALubyte *WritePtr = self->mix_data;
108 ALCsndioBackend_lock(self);
109 aluMixData(device, WritePtr, len/frameSize);
110 ALCsndioBackend_unlock(self);
111 while(len > 0 && !self->killNow)
113 wrote = sio_write(self->sndHandle, WritePtr, len);
114 if(wrote == 0)
116 ERR("sio_write failed\n");
117 ALCdevice_Lock(device);
118 aluHandleDisconnect(device);
119 ALCdevice_Unlock(device);
120 break;
123 len -= wrote;
124 WritePtr += wrote;
128 return 0;
132 static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name)
134 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
136 if(!name)
137 name = sndio_device;
138 else if(strcmp(name, sndio_device) != 0)
139 return ALC_INVALID_VALUE;
141 self->sndHandle = sio_open(NULL, SIO_PLAY, 0);
142 if(self->sndHandle == NULL)
144 ERR("Could not open device\n");
145 return ALC_INVALID_VALUE;
148 alstr_copy_cstr(&device->DeviceName, name);
150 return ALC_NO_ERROR;
153 static void ALCsndioBackend_close(ALCsndioBackend *self)
155 sio_close(self->sndHandle);
156 self->sndHandle = NULL;
159 static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self)
161 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
162 struct sio_par par;
164 sio_initpar(&par);
166 par.rate = device->Frequency;
167 par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1);
169 switch(device->FmtType)
171 case DevFmtByte:
172 par.bits = 8;
173 par.sig = 1;
174 break;
175 case DevFmtUByte:
176 par.bits = 8;
177 par.sig = 0;
178 break;
179 case DevFmtFloat:
180 case DevFmtShort:
181 par.bits = 16;
182 par.sig = 1;
183 break;
184 case DevFmtUShort:
185 par.bits = 16;
186 par.sig = 0;
187 break;
188 case DevFmtInt:
189 par.bits = 32;
190 par.sig = 1;
191 break;
192 case DevFmtUInt:
193 par.bits = 32;
194 par.sig = 0;
195 break;
197 par.le = SIO_LE_NATIVE;
199 par.round = device->UpdateSize;
200 par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
201 if(!par.appbufsz) par.appbufsz = device->UpdateSize;
203 if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par))
205 ERR("Failed to set device parameters\n");
206 return ALC_FALSE;
209 if(par.bits != par.bps*8)
211 ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
212 return ALC_FALSE;
215 device->Frequency = par.rate;
216 device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
218 if(par.bits == 8 && par.sig == 1)
219 device->FmtType = DevFmtByte;
220 else if(par.bits == 8 && par.sig == 0)
221 device->FmtType = DevFmtUByte;
222 else if(par.bits == 16 && par.sig == 1)
223 device->FmtType = DevFmtShort;
224 else if(par.bits == 16 && par.sig == 0)
225 device->FmtType = DevFmtUShort;
226 else if(par.bits == 32 && par.sig == 1)
227 device->FmtType = DevFmtInt;
228 else if(par.bits == 32 && par.sig == 0)
229 device->FmtType = DevFmtUInt;
230 else
232 ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
233 return ALC_FALSE;
236 device->UpdateSize = par.round;
237 device->NumUpdates = (par.bufsz/par.round) + 1;
239 SetDefaultChannelOrder(device);
241 return ALC_TRUE;
244 static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self)
246 ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
248 self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
249 device->FmtChans, device->FmtType, device->AmbiOrder
251 al_free(self->mix_data);
252 self->mix_data = al_calloc(16, self->data_size);
254 if(!sio_start(self->sndHandle))
256 ERR("Error starting playback\n");
257 return ALC_FALSE;
260 self->killNow = 0;
261 if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success)
263 sio_stop(self->sndHandle);
264 return ALC_FALSE;
267 return ALC_TRUE;
270 static void ALCsndioBackend_stop(ALCsndioBackend *self)
272 int res;
274 if(self->killNow)
275 return;
277 self->killNow = 1;
278 althrd_join(self->thread, &res);
280 if(!sio_stop(self->sndHandle))
281 ERR("Error stopping device\n");
283 al_free(self->mix_data);
284 self->mix_data = NULL;
288 typedef struct ALCsndioBackendFactory {
289 DERIVE_FROM_TYPE(ALCbackendFactory);
290 } ALCsndioBackendFactory;
291 #define ALCSNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsndioBackendFactory, ALCbackendFactory) } }
293 ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
295 static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory *self);
296 static DECLARE_FORWARD(ALCsndioBackendFactory, ALCbackendFactory, void, deinit)
297 static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory *self, ALCbackend_Type type);
298 static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory *self, enum DevProbe type);
299 static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
300 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsndioBackendFactory);
303 ALCbackendFactory *ALCsndioBackendFactory_getFactory(void)
305 static ALCsndioBackendFactory factory = ALCSNDIOBACKENDFACTORY_INITIALIZER;
306 return STATIC_CAST(ALCbackendFactory, &factory);
310 static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory* UNUSED(self))
312 /* No dynamic loading */
313 return ALC_TRUE;
316 static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory* UNUSED(self), ALCbackend_Type type)
318 if(type == ALCbackend_Playback)
319 return ALC_TRUE;
320 return ALC_FALSE;
323 static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), enum DevProbe type)
325 switch(type)
327 case ALL_DEVICE_PROBE:
328 AppendAllDevicesList(sndio_device);
329 break;
330 case CAPTURE_DEVICE_PROBE:
331 break;
335 static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
337 if(type == ALCbackend_Playback)
339 ALCsndioBackend *backend;
340 NEW_OBJ(backend, ALCsndioBackend)(device);
341 if(!backend) return NULL;
342 return STATIC_CAST(ALCbackend, backend);
345 return NULL;