annotate 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
rev   line source
rlm@0 1 /**
rlm@0 2 * OpenAL cross platform audio library
rlm@0 3 * Copyright (C) 1999-2007 by authors.
rlm@0 4 * This library is free software; you can redistribute it and/or
rlm@0 5 * modify it under the terms of the GNU Library General Public
rlm@0 6 * License as published by the Free Software Foundation; either
rlm@0 7 * version 2 of the License, or (at your option) any later version.
rlm@0 8 *
rlm@0 9 * This library is distributed in the hope that it will be useful,
rlm@0 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rlm@0 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
rlm@0 12 * Library General Public License for more details.
rlm@0 13 *
rlm@0 14 * You should have received a copy of the GNU Library General Public
rlm@0 15 * License along with this library; if not, write to the
rlm@0 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
rlm@0 17 * Boston, MA 02111-1307, USA.
rlm@0 18 * Or go to http://www.gnu.org/copyleft/lgpl.html
rlm@0 19 */
rlm@0 20
rlm@0 21 #include "config.h"
rlm@0 22
rlm@0 23 #include <stdio.h>
rlm@0 24 #include <stdlib.h>
rlm@0 25 #include <string.h>
rlm@0 26 #include "alMain.h"
rlm@0 27 #include "AL/al.h"
rlm@0 28 #include "AL/alc.h"
rlm@0 29
rlm@0 30 #include <sndio.h>
rlm@0 31
rlm@0 32
rlm@0 33 static const ALCchar sndio_device[] = "SndIO Default";
rlm@0 34
rlm@0 35
rlm@0 36 static void *sndio_handle;
rlm@0 37 #ifdef HAVE_DYNLOAD
rlm@0 38 #define MAKE_FUNC(x) static typeof(x) * p##x
rlm@0 39 MAKE_FUNC(sio_initpar);
rlm@0 40 MAKE_FUNC(sio_open);
rlm@0 41 MAKE_FUNC(sio_close);
rlm@0 42 MAKE_FUNC(sio_setpar);
rlm@0 43 MAKE_FUNC(sio_getpar);
rlm@0 44 MAKE_FUNC(sio_getcap);
rlm@0 45 MAKE_FUNC(sio_onmove);
rlm@0 46 MAKE_FUNC(sio_write);
rlm@0 47 MAKE_FUNC(sio_read);
rlm@0 48 MAKE_FUNC(sio_start);
rlm@0 49 MAKE_FUNC(sio_stop);
rlm@0 50 MAKE_FUNC(sio_nfds);
rlm@0 51 MAKE_FUNC(sio_pollfd);
rlm@0 52 MAKE_FUNC(sio_revents);
rlm@0 53 MAKE_FUNC(sio_eof);
rlm@0 54 MAKE_FUNC(sio_setvol);
rlm@0 55 MAKE_FUNC(sio_onvol);
rlm@0 56
rlm@0 57 #define sio_initpar psio_initpar
rlm@0 58 #define sio_open psio_open
rlm@0 59 #define sio_close psio_close
rlm@0 60 #define sio_setpar psio_setpar
rlm@0 61 #define sio_getpar psio_getpar
rlm@0 62 #define sio_getcap psio_getcap
rlm@0 63 #define sio_onmove psio_onmove
rlm@0 64 #define sio_write psio_write
rlm@0 65 #define sio_read psio_read
rlm@0 66 #define sio_start psio_start
rlm@0 67 #define sio_stop psio_stop
rlm@0 68 #define sio_nfds psio_nfds
rlm@0 69 #define sio_pollfd psio_pollfd
rlm@0 70 #define sio_revents psio_revents
rlm@0 71 #define sio_eof psio_eof
rlm@0 72 #define sio_setvol psio_setvol
rlm@0 73 #define sio_onvol psio_onvol
rlm@0 74 #endif
rlm@0 75
rlm@0 76
rlm@0 77 static ALCboolean sndio_load(void)
rlm@0 78 {
rlm@0 79 if(!sndio_handle)
rlm@0 80 {
rlm@0 81 #ifdef HAVE_DYNLOAD
rlm@0 82 sndio_handle = LoadLib("libsndio.so");
rlm@0 83 if(!sndio_handle)
rlm@0 84 return ALC_FALSE;
rlm@0 85
rlm@0 86 #define LOAD_FUNC(f) do { \
rlm@0 87 p##f = GetSymbol(sndio_handle, #f); \
rlm@0 88 if(p##f == NULL) { \
rlm@0 89 CloseLib(sndio_handle); \
rlm@0 90 sndio_handle = NULL; \
rlm@0 91 return ALC_FALSE; \
rlm@0 92 } \
rlm@0 93 } while(0)
rlm@0 94 LOAD_FUNC(sio_initpar);
rlm@0 95 LOAD_FUNC(sio_open);
rlm@0 96 LOAD_FUNC(sio_close);
rlm@0 97 LOAD_FUNC(sio_setpar);
rlm@0 98 LOAD_FUNC(sio_getpar);
rlm@0 99 LOAD_FUNC(sio_getcap);
rlm@0 100 LOAD_FUNC(sio_onmove);
rlm@0 101 LOAD_FUNC(sio_write);
rlm@0 102 LOAD_FUNC(sio_read);
rlm@0 103 LOAD_FUNC(sio_start);
rlm@0 104 LOAD_FUNC(sio_stop);
rlm@0 105 LOAD_FUNC(sio_nfds);
rlm@0 106 LOAD_FUNC(sio_pollfd);
rlm@0 107 LOAD_FUNC(sio_revents);
rlm@0 108 LOAD_FUNC(sio_eof);
rlm@0 109 LOAD_FUNC(sio_setvol);
rlm@0 110 LOAD_FUNC(sio_onvol);
rlm@0 111 #undef LOAD_FUNC
rlm@0 112 #else
rlm@0 113 sndio_handle = (void*)0xDEADBEEF;
rlm@0 114 #endif
rlm@0 115 }
rlm@0 116 return ALC_TRUE;
rlm@0 117 }
rlm@0 118
rlm@0 119
rlm@0 120 typedef struct {
rlm@0 121 struct sio_hdl *sndHandle;
rlm@0 122
rlm@0 123 ALvoid *mix_data;
rlm@0 124 ALsizei data_size;
rlm@0 125
rlm@0 126 volatile int killNow;
rlm@0 127 ALvoid *thread;
rlm@0 128 } sndio_data;
rlm@0 129
rlm@0 130
rlm@0 131 static ALuint sndio_proc(ALvoid *ptr)
rlm@0 132 {
rlm@0 133 ALCdevice *device = ptr;
rlm@0 134 sndio_data *data = device->ExtraData;
rlm@0 135 ALsizei frameSize;
rlm@0 136 size_t wrote;
rlm@0 137
rlm@0 138 SetRTPriority();
rlm@0 139
rlm@0 140 frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
rlm@0 141
rlm@0 142 while(!data->killNow && device->Connected)
rlm@0 143 {
rlm@0 144 ALsizei len = data->data_size;
rlm@0 145 ALubyte *WritePtr = data->mix_data;
rlm@0 146
rlm@0 147 aluMixData(device, WritePtr, len/frameSize);
rlm@0 148 while(len > 0 && !data->killNow)
rlm@0 149 {
rlm@0 150 wrote = sio_write(data->sndHandle, WritePtr, len);
rlm@0 151 if(wrote == 0)
rlm@0 152 {
rlm@0 153 ERR("sio_write failed\n");
rlm@0 154 aluHandleDisconnect(device);
rlm@0 155 break;
rlm@0 156 }
rlm@0 157
rlm@0 158 len -= wrote;
rlm@0 159 WritePtr += wrote;
rlm@0 160 }
rlm@0 161 }
rlm@0 162
rlm@0 163 return 0;
rlm@0 164 }
rlm@0 165
rlm@0 166
rlm@0 167
rlm@0 168 static ALCboolean sndio_open_playback(ALCdevice *device, const ALCchar *deviceName)
rlm@0 169 {
rlm@0 170 sndio_data *data;
rlm@0 171
rlm@0 172 if(!deviceName)
rlm@0 173 deviceName = sndio_device;
rlm@0 174 else if(strcmp(deviceName, sndio_device) != 0)
rlm@0 175 return ALC_FALSE;
rlm@0 176
rlm@0 177 data = calloc(1, sizeof(*data));
rlm@0 178 data->killNow = 0;
rlm@0 179
rlm@0 180 data->sndHandle = sio_open(NULL, SIO_PLAY, 0);
rlm@0 181 if(data->sndHandle == NULL)
rlm@0 182 {
rlm@0 183 free(data);
rlm@0 184 ERR("Could not open device\n");
rlm@0 185 return ALC_FALSE;
rlm@0 186 }
rlm@0 187
rlm@0 188 device->szDeviceName = strdup(deviceName);
rlm@0 189 device->ExtraData = data;
rlm@0 190
rlm@0 191 return ALC_TRUE;
rlm@0 192 }
rlm@0 193
rlm@0 194 static void sndio_close_playback(ALCdevice *device)
rlm@0 195 {
rlm@0 196 sndio_data *data = device->ExtraData;
rlm@0 197
rlm@0 198 sio_close(data->sndHandle);
rlm@0 199 free(data);
rlm@0 200 device->ExtraData = NULL;
rlm@0 201 }
rlm@0 202
rlm@0 203 static ALCboolean sndio_reset_playback(ALCdevice *device)
rlm@0 204 {
rlm@0 205 sndio_data *data = device->ExtraData;
rlm@0 206 struct sio_par par;
rlm@0 207
rlm@0 208 sio_initpar(&par);
rlm@0 209
rlm@0 210 par.rate = device->Frequency;
rlm@0 211
rlm@0 212 par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1);
rlm@0 213
rlm@0 214 switch(device->FmtType)
rlm@0 215 {
rlm@0 216 case DevFmtByte:
rlm@0 217 par.bits = 8;
rlm@0 218 par.sig = 1;
rlm@0 219 break;
rlm@0 220 case DevFmtUByte:
rlm@0 221 par.bits = 8;
rlm@0 222 par.sig = 0;
rlm@0 223 break;
rlm@0 224 case DevFmtFloat:
rlm@0 225 device->FmtType = DevFmtShort;
rlm@0 226 /* fall-through */
rlm@0 227 case DevFmtShort:
rlm@0 228 par.bits = 16;
rlm@0 229 par.sig = 1;
rlm@0 230 break;
rlm@0 231 case DevFmtUShort:
rlm@0 232 par.bits = 16;
rlm@0 233 par.sig = 0;
rlm@0 234 break;
rlm@0 235 }
rlm@0 236 par.le = SIO_LE_NATIVE;
rlm@0 237
rlm@0 238 par.round = device->UpdateSize;
rlm@0 239 par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
rlm@0 240 if(!par.appbufsz) par.appbufsz = device->UpdateSize;
rlm@0 241
rlm@0 242
rlm@0 243 if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par))
rlm@0 244 {
rlm@0 245 ERR("Failed to set device parameters\n");
rlm@0 246 return ALC_FALSE;
rlm@0 247 }
rlm@0 248
rlm@0 249 if(par.rate != device->Frequency)
rlm@0 250 {
rlm@0 251 if((device->Flags&DEVICE_FREQUENCY_REQUEST))
rlm@0 252 ERR("Failed to set frequency %uhz, got %uhz instead\n", device->Frequency, par.rate);
rlm@0 253 device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
rlm@0 254 device->Frequency = par.rate;
rlm@0 255 }
rlm@0 256
rlm@0 257 if(par.pchan != ChannelsFromDevFmt(device->FmtChans))
rlm@0 258 {
rlm@0 259 if(par.pchan != 1 && par.pchan != 2)
rlm@0 260 {
rlm@0 261 ERR("Unhandled channel count: %u\n", par.pchan);
rlm@0 262 return ALC_FALSE;
rlm@0 263 }
rlm@0 264 if((device->Flags&DEVICE_CHANNELS_REQUEST))
rlm@0 265 ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), par.pchan);
rlm@0 266 device->Flags &= ~DEVICE_CHANNELS_REQUEST;
rlm@0 267 device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
rlm@0 268 }
rlm@0 269
rlm@0 270 if(par.bits != par.bps*8)
rlm@0 271 {
rlm@0 272 ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
rlm@0 273 return ALC_FALSE;
rlm@0 274 }
rlm@0 275
rlm@0 276 if(par.bits == 8 && par.sig == 1)
rlm@0 277 device->FmtType = DevFmtByte;
rlm@0 278 else if(par.bits == 8 && par.sig == 0)
rlm@0 279 device->FmtType = DevFmtUByte;
rlm@0 280 else if(par.bits == 16 && par.sig == 1)
rlm@0 281 device->FmtType = DevFmtShort;
rlm@0 282 else if(par.bits == 16 && par.sig == 0)
rlm@0 283 device->FmtType = DevFmtUShort;
rlm@0 284 else
rlm@0 285 {
rlm@0 286 ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
rlm@0 287 return ALC_FALSE;
rlm@0 288 }
rlm@0 289
rlm@0 290
rlm@0 291 device->UpdateSize = par.round;
rlm@0 292 device->NumUpdates = (par.bufsz/par.round) + 1;
rlm@0 293
rlm@0 294 SetDefaultChannelOrder(device);
rlm@0 295
rlm@0 296
rlm@0 297 if(!sio_start(data->sndHandle))
rlm@0 298 {
rlm@0 299 ERR("Error starting playback\n");
rlm@0 300 return ALC_FALSE;
rlm@0 301 }
rlm@0 302
rlm@0 303 data->data_size = device->UpdateSize * par.bps * par.pchan;
rlm@0 304 data->mix_data = calloc(1, data->data_size);
rlm@0 305
rlm@0 306 data->thread = StartThread(sndio_proc, device);
rlm@0 307 if(data->thread == NULL)
rlm@0 308 {
rlm@0 309 sio_stop(data->sndHandle);
rlm@0 310 free(data->mix_data);
rlm@0 311 data->mix_data = NULL;
rlm@0 312 return ALC_FALSE;
rlm@0 313 }
rlm@0 314
rlm@0 315 return ALC_TRUE;
rlm@0 316 }
rlm@0 317
rlm@0 318 static void sndio_stop_playback(ALCdevice *device)
rlm@0 319 {
rlm@0 320 sndio_data *data = device->ExtraData;
rlm@0 321
rlm@0 322 if(!data->thread)
rlm@0 323 return;
rlm@0 324
rlm@0 325 data->killNow = 1;
rlm@0 326 StopThread(data->thread);
rlm@0 327 data->thread = NULL;
rlm@0 328
rlm@0 329 data->killNow = 0;
rlm@0 330 if(!sio_stop(data->sndHandle))
rlm@0 331 ERR("Error stopping device\n");
rlm@0 332
rlm@0 333 free(data->mix_data);
rlm@0 334 data->mix_data = NULL;
rlm@0 335 }
rlm@0 336
rlm@0 337
rlm@0 338 static const BackendFuncs sndio_funcs = {
rlm@0 339 sndio_open_playback,
rlm@0 340 sndio_close_playback,
rlm@0 341 sndio_reset_playback,
rlm@0 342 sndio_stop_playback,
rlm@0 343 NULL,
rlm@0 344 NULL,
rlm@0 345 NULL,
rlm@0 346 NULL,
rlm@0 347 NULL,
rlm@0 348 NULL
rlm@0 349 };
rlm@0 350
rlm@0 351 ALCboolean alc_sndio_init(BackendFuncs *func_list)
rlm@0 352 {
rlm@0 353 if(!sndio_load())
rlm@0 354 return ALC_FALSE;
rlm@0 355 *func_list = sndio_funcs;
rlm@0 356 return ALC_TRUE;
rlm@0 357 }
rlm@0 358
rlm@0 359 void alc_sndio_deinit(void)
rlm@0 360 {
rlm@0 361 #ifdef HAVE_DYNLOAD
rlm@0 362 if(sndio_handle)
rlm@0 363 CloseLib(sndio_handle);
rlm@0 364 sndio_handle = NULL;
rlm@0 365 #endif
rlm@0 366 }
rlm@0 367
rlm@0 368 void alc_sndio_probe(enum DevProbe type)
rlm@0 369 {
rlm@0 370 switch(type)
rlm@0 371 {
rlm@0 372 case DEVICE_PROBE:
rlm@0 373 AppendDeviceList(sndio_device);
rlm@0 374 break;
rlm@0 375 case ALL_DEVICE_PROBE:
rlm@0 376 AppendAllDeviceList(sndio_device);
rlm@0 377 break;
rlm@0 378 case CAPTURE_DEVICE_PROBE:
rlm@0 379 break;
rlm@0 380 }
rlm@0 381 }