Mercurial > audio-send
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 library3 * Copyright (C) 1999-2007 by authors.4 * This library is free software; you can redistribute it and/or5 * modify it under the terms of the GNU Library General Public6 * License as published by the Free Software Foundation; either7 * 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 of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12 * Library General Public License for more details.13 *14 * You should have received a copy of the GNU Library General Public15 * License along with this library; if not, write to the16 * 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.html19 */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_DYNLOAD38 #define MAKE_FUNC(x) static typeof(x) * p##x39 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_initpar58 #define sio_open psio_open59 #define sio_close psio_close60 #define sio_setpar psio_setpar61 #define sio_getpar psio_getpar62 #define sio_getcap psio_getcap63 #define sio_onmove psio_onmove64 #define sio_write psio_write65 #define sio_read psio_read66 #define sio_start psio_start67 #define sio_stop psio_stop68 #define sio_nfds psio_nfds69 #define sio_pollfd psio_pollfd70 #define sio_revents psio_revents71 #define sio_eof psio_eof72 #define sio_setvol psio_setvol73 #define sio_onvol psio_onvol74 #endif77 static ALCboolean sndio_load(void)78 {79 if(!sndio_handle)80 {81 #ifdef HAVE_DYNLOAD82 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_FUNC112 #else113 sndio_handle = (void*)0xDEADBEEF;114 #endif115 }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 else285 {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 NULL349 };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_DYNLOAD362 if(sndio_handle)363 CloseLib(sndio_handle);364 sndio_handle = NULL;365 #endif366 }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 }