Mercurial > audio-send
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Alc/backends/sndio.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,381 @@ 1.4 +/** 1.5 + * OpenAL cross platform audio library 1.6 + * Copyright (C) 1999-2007 by authors. 1.7 + * This library is free software; you can redistribute it and/or 1.8 + * modify it under the terms of the GNU Library General Public 1.9 + * License as published by the Free Software Foundation; either 1.10 + * version 2 of the License, or (at your option) any later version. 1.11 + * 1.12 + * This library is distributed in the hope that it will be useful, 1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.15 + * Library General Public License for more details. 1.16 + * 1.17 + * You should have received a copy of the GNU Library General Public 1.18 + * License along with this library; if not, write to the 1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 1.20 + * Boston, MA 02111-1307, USA. 1.21 + * Or go to http://www.gnu.org/copyleft/lgpl.html 1.22 + */ 1.23 + 1.24 +#include "config.h" 1.25 + 1.26 +#include <stdio.h> 1.27 +#include <stdlib.h> 1.28 +#include <string.h> 1.29 +#include "alMain.h" 1.30 +#include "AL/al.h" 1.31 +#include "AL/alc.h" 1.32 + 1.33 +#include <sndio.h> 1.34 + 1.35 + 1.36 +static const ALCchar sndio_device[] = "SndIO Default"; 1.37 + 1.38 + 1.39 +static void *sndio_handle; 1.40 +#ifdef HAVE_DYNLOAD 1.41 +#define MAKE_FUNC(x) static typeof(x) * p##x 1.42 +MAKE_FUNC(sio_initpar); 1.43 +MAKE_FUNC(sio_open); 1.44 +MAKE_FUNC(sio_close); 1.45 +MAKE_FUNC(sio_setpar); 1.46 +MAKE_FUNC(sio_getpar); 1.47 +MAKE_FUNC(sio_getcap); 1.48 +MAKE_FUNC(sio_onmove); 1.49 +MAKE_FUNC(sio_write); 1.50 +MAKE_FUNC(sio_read); 1.51 +MAKE_FUNC(sio_start); 1.52 +MAKE_FUNC(sio_stop); 1.53 +MAKE_FUNC(sio_nfds); 1.54 +MAKE_FUNC(sio_pollfd); 1.55 +MAKE_FUNC(sio_revents); 1.56 +MAKE_FUNC(sio_eof); 1.57 +MAKE_FUNC(sio_setvol); 1.58 +MAKE_FUNC(sio_onvol); 1.59 + 1.60 +#define sio_initpar psio_initpar 1.61 +#define sio_open psio_open 1.62 +#define sio_close psio_close 1.63 +#define sio_setpar psio_setpar 1.64 +#define sio_getpar psio_getpar 1.65 +#define sio_getcap psio_getcap 1.66 +#define sio_onmove psio_onmove 1.67 +#define sio_write psio_write 1.68 +#define sio_read psio_read 1.69 +#define sio_start psio_start 1.70 +#define sio_stop psio_stop 1.71 +#define sio_nfds psio_nfds 1.72 +#define sio_pollfd psio_pollfd 1.73 +#define sio_revents psio_revents 1.74 +#define sio_eof psio_eof 1.75 +#define sio_setvol psio_setvol 1.76 +#define sio_onvol psio_onvol 1.77 +#endif 1.78 + 1.79 + 1.80 +static ALCboolean sndio_load(void) 1.81 +{ 1.82 + if(!sndio_handle) 1.83 + { 1.84 +#ifdef HAVE_DYNLOAD 1.85 + sndio_handle = LoadLib("libsndio.so"); 1.86 + if(!sndio_handle) 1.87 + return ALC_FALSE; 1.88 + 1.89 +#define LOAD_FUNC(f) do { \ 1.90 + p##f = GetSymbol(sndio_handle, #f); \ 1.91 + if(p##f == NULL) { \ 1.92 + CloseLib(sndio_handle); \ 1.93 + sndio_handle = NULL; \ 1.94 + return ALC_FALSE; \ 1.95 + } \ 1.96 +} while(0) 1.97 + LOAD_FUNC(sio_initpar); 1.98 + LOAD_FUNC(sio_open); 1.99 + LOAD_FUNC(sio_close); 1.100 + LOAD_FUNC(sio_setpar); 1.101 + LOAD_FUNC(sio_getpar); 1.102 + LOAD_FUNC(sio_getcap); 1.103 + LOAD_FUNC(sio_onmove); 1.104 + LOAD_FUNC(sio_write); 1.105 + LOAD_FUNC(sio_read); 1.106 + LOAD_FUNC(sio_start); 1.107 + LOAD_FUNC(sio_stop); 1.108 + LOAD_FUNC(sio_nfds); 1.109 + LOAD_FUNC(sio_pollfd); 1.110 + LOAD_FUNC(sio_revents); 1.111 + LOAD_FUNC(sio_eof); 1.112 + LOAD_FUNC(sio_setvol); 1.113 + LOAD_FUNC(sio_onvol); 1.114 +#undef LOAD_FUNC 1.115 +#else 1.116 + sndio_handle = (void*)0xDEADBEEF; 1.117 +#endif 1.118 + } 1.119 + return ALC_TRUE; 1.120 +} 1.121 + 1.122 + 1.123 +typedef struct { 1.124 + struct sio_hdl *sndHandle; 1.125 + 1.126 + ALvoid *mix_data; 1.127 + ALsizei data_size; 1.128 + 1.129 + volatile int killNow; 1.130 + ALvoid *thread; 1.131 +} sndio_data; 1.132 + 1.133 + 1.134 +static ALuint sndio_proc(ALvoid *ptr) 1.135 +{ 1.136 + ALCdevice *device = ptr; 1.137 + sndio_data *data = device->ExtraData; 1.138 + ALsizei frameSize; 1.139 + size_t wrote; 1.140 + 1.141 + SetRTPriority(); 1.142 + 1.143 + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); 1.144 + 1.145 + while(!data->killNow && device->Connected) 1.146 + { 1.147 + ALsizei len = data->data_size; 1.148 + ALubyte *WritePtr = data->mix_data; 1.149 + 1.150 + aluMixData(device, WritePtr, len/frameSize); 1.151 + while(len > 0 && !data->killNow) 1.152 + { 1.153 + wrote = sio_write(data->sndHandle, WritePtr, len); 1.154 + if(wrote == 0) 1.155 + { 1.156 + ERR("sio_write failed\n"); 1.157 + aluHandleDisconnect(device); 1.158 + break; 1.159 + } 1.160 + 1.161 + len -= wrote; 1.162 + WritePtr += wrote; 1.163 + } 1.164 + } 1.165 + 1.166 + return 0; 1.167 +} 1.168 + 1.169 + 1.170 + 1.171 +static ALCboolean sndio_open_playback(ALCdevice *device, const ALCchar *deviceName) 1.172 +{ 1.173 + sndio_data *data; 1.174 + 1.175 + if(!deviceName) 1.176 + deviceName = sndio_device; 1.177 + else if(strcmp(deviceName, sndio_device) != 0) 1.178 + return ALC_FALSE; 1.179 + 1.180 + data = calloc(1, sizeof(*data)); 1.181 + data->killNow = 0; 1.182 + 1.183 + data->sndHandle = sio_open(NULL, SIO_PLAY, 0); 1.184 + if(data->sndHandle == NULL) 1.185 + { 1.186 + free(data); 1.187 + ERR("Could not open device\n"); 1.188 + return ALC_FALSE; 1.189 + } 1.190 + 1.191 + device->szDeviceName = strdup(deviceName); 1.192 + device->ExtraData = data; 1.193 + 1.194 + return ALC_TRUE; 1.195 +} 1.196 + 1.197 +static void sndio_close_playback(ALCdevice *device) 1.198 +{ 1.199 + sndio_data *data = device->ExtraData; 1.200 + 1.201 + sio_close(data->sndHandle); 1.202 + free(data); 1.203 + device->ExtraData = NULL; 1.204 +} 1.205 + 1.206 +static ALCboolean sndio_reset_playback(ALCdevice *device) 1.207 +{ 1.208 + sndio_data *data = device->ExtraData; 1.209 + struct sio_par par; 1.210 + 1.211 + sio_initpar(&par); 1.212 + 1.213 + par.rate = device->Frequency; 1.214 + 1.215 + par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); 1.216 + 1.217 + switch(device->FmtType) 1.218 + { 1.219 + case DevFmtByte: 1.220 + par.bits = 8; 1.221 + par.sig = 1; 1.222 + break; 1.223 + case DevFmtUByte: 1.224 + par.bits = 8; 1.225 + par.sig = 0; 1.226 + break; 1.227 + case DevFmtFloat: 1.228 + device->FmtType = DevFmtShort; 1.229 + /* fall-through */ 1.230 + case DevFmtShort: 1.231 + par.bits = 16; 1.232 + par.sig = 1; 1.233 + break; 1.234 + case DevFmtUShort: 1.235 + par.bits = 16; 1.236 + par.sig = 0; 1.237 + break; 1.238 + } 1.239 + par.le = SIO_LE_NATIVE; 1.240 + 1.241 + par.round = device->UpdateSize; 1.242 + par.appbufsz = device->UpdateSize * (device->NumUpdates-1); 1.243 + if(!par.appbufsz) par.appbufsz = device->UpdateSize; 1.244 + 1.245 + 1.246 + if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par)) 1.247 + { 1.248 + ERR("Failed to set device parameters\n"); 1.249 + return ALC_FALSE; 1.250 + } 1.251 + 1.252 + if(par.rate != device->Frequency) 1.253 + { 1.254 + if((device->Flags&DEVICE_FREQUENCY_REQUEST)) 1.255 + ERR("Failed to set frequency %uhz, got %uhz instead\n", device->Frequency, par.rate); 1.256 + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; 1.257 + device->Frequency = par.rate; 1.258 + } 1.259 + 1.260 + if(par.pchan != ChannelsFromDevFmt(device->FmtChans)) 1.261 + { 1.262 + if(par.pchan != 1 && par.pchan != 2) 1.263 + { 1.264 + ERR("Unhandled channel count: %u\n", par.pchan); 1.265 + return ALC_FALSE; 1.266 + } 1.267 + if((device->Flags&DEVICE_CHANNELS_REQUEST)) 1.268 + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), par.pchan); 1.269 + device->Flags &= ~DEVICE_CHANNELS_REQUEST; 1.270 + device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); 1.271 + } 1.272 + 1.273 + if(par.bits != par.bps*8) 1.274 + { 1.275 + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); 1.276 + return ALC_FALSE; 1.277 + } 1.278 + 1.279 + if(par.bits == 8 && par.sig == 1) 1.280 + device->FmtType = DevFmtByte; 1.281 + else if(par.bits == 8 && par.sig == 0) 1.282 + device->FmtType = DevFmtUByte; 1.283 + else if(par.bits == 16 && par.sig == 1) 1.284 + device->FmtType = DevFmtShort; 1.285 + else if(par.bits == 16 && par.sig == 0) 1.286 + device->FmtType = DevFmtUShort; 1.287 + else 1.288 + { 1.289 + ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); 1.290 + return ALC_FALSE; 1.291 + } 1.292 + 1.293 + 1.294 + device->UpdateSize = par.round; 1.295 + device->NumUpdates = (par.bufsz/par.round) + 1; 1.296 + 1.297 + SetDefaultChannelOrder(device); 1.298 + 1.299 + 1.300 + if(!sio_start(data->sndHandle)) 1.301 + { 1.302 + ERR("Error starting playback\n"); 1.303 + return ALC_FALSE; 1.304 + } 1.305 + 1.306 + data->data_size = device->UpdateSize * par.bps * par.pchan; 1.307 + data->mix_data = calloc(1, data->data_size); 1.308 + 1.309 + data->thread = StartThread(sndio_proc, device); 1.310 + if(data->thread == NULL) 1.311 + { 1.312 + sio_stop(data->sndHandle); 1.313 + free(data->mix_data); 1.314 + data->mix_data = NULL; 1.315 + return ALC_FALSE; 1.316 + } 1.317 + 1.318 + return ALC_TRUE; 1.319 +} 1.320 + 1.321 +static void sndio_stop_playback(ALCdevice *device) 1.322 +{ 1.323 + sndio_data *data = device->ExtraData; 1.324 + 1.325 + if(!data->thread) 1.326 + return; 1.327 + 1.328 + data->killNow = 1; 1.329 + StopThread(data->thread); 1.330 + data->thread = NULL; 1.331 + 1.332 + data->killNow = 0; 1.333 + if(!sio_stop(data->sndHandle)) 1.334 + ERR("Error stopping device\n"); 1.335 + 1.336 + free(data->mix_data); 1.337 + data->mix_data = NULL; 1.338 +} 1.339 + 1.340 + 1.341 +static const BackendFuncs sndio_funcs = { 1.342 + sndio_open_playback, 1.343 + sndio_close_playback, 1.344 + sndio_reset_playback, 1.345 + sndio_stop_playback, 1.346 + NULL, 1.347 + NULL, 1.348 + NULL, 1.349 + NULL, 1.350 + NULL, 1.351 + NULL 1.352 +}; 1.353 + 1.354 +ALCboolean alc_sndio_init(BackendFuncs *func_list) 1.355 +{ 1.356 + if(!sndio_load()) 1.357 + return ALC_FALSE; 1.358 + *func_list = sndio_funcs; 1.359 + return ALC_TRUE; 1.360 +} 1.361 + 1.362 +void alc_sndio_deinit(void) 1.363 +{ 1.364 +#ifdef HAVE_DYNLOAD 1.365 + if(sndio_handle) 1.366 + CloseLib(sndio_handle); 1.367 + sndio_handle = NULL; 1.368 +#endif 1.369 +} 1.370 + 1.371 +void alc_sndio_probe(enum DevProbe type) 1.372 +{ 1.373 + switch(type) 1.374 + { 1.375 + case DEVICE_PROBE: 1.376 + AppendDeviceList(sndio_device); 1.377 + break; 1.378 + case ALL_DEVICE_PROBE: 1.379 + AppendAllDeviceList(sndio_device); 1.380 + break; 1.381 + case CAPTURE_DEVICE_PROBE: 1.382 + break; 1.383 + } 1.384 +}