Mercurial > audio-send
diff Alc/backends/oss.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/oss.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,536 @@ 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 <sys/ioctl.h> 1.27 +#include <sys/types.h> 1.28 +#include <sys/stat.h> 1.29 +#include <fcntl.h> 1.30 +#include <stdlib.h> 1.31 +#include <stdio.h> 1.32 +#include <memory.h> 1.33 +#include <unistd.h> 1.34 +#include <errno.h> 1.35 +#include <math.h> 1.36 +#include "alMain.h" 1.37 +#include "AL/al.h" 1.38 +#include "AL/alc.h" 1.39 + 1.40 +#include <sys/soundcard.h> 1.41 + 1.42 +/* 1.43 + * The OSS documentation talks about SOUND_MIXER_READ, but the header 1.44 + * only contains MIXER_READ. Play safe. Same for WRITE. 1.45 + */ 1.46 +#ifndef SOUND_MIXER_READ 1.47 +#define SOUND_MIXER_READ MIXER_READ 1.48 +#endif 1.49 +#ifndef SOUND_MIXER_WRITE 1.50 +#define SOUND_MIXER_WRITE MIXER_WRITE 1.51 +#endif 1.52 + 1.53 +static const ALCchar oss_device[] = "OSS Default"; 1.54 + 1.55 +typedef struct { 1.56 + int fd; 1.57 + volatile int killNow; 1.58 + ALvoid *thread; 1.59 + 1.60 + ALubyte *mix_data; 1.61 + int data_size; 1.62 + 1.63 + RingBuffer *ring; 1.64 + int doCapture; 1.65 +} oss_data; 1.66 + 1.67 + 1.68 +static int log2i(ALCuint x) 1.69 +{ 1.70 + int y = 0; 1.71 + while (x > 1) 1.72 + { 1.73 + x >>= 1; 1.74 + y++; 1.75 + } 1.76 + return y; 1.77 +} 1.78 + 1.79 + 1.80 +static ALuint OSSProc(ALvoid *ptr) 1.81 +{ 1.82 + ALCdevice *pDevice = (ALCdevice*)ptr; 1.83 + oss_data *data = (oss_data*)pDevice->ExtraData; 1.84 + ALint frameSize; 1.85 + ssize_t wrote; 1.86 + 1.87 + SetRTPriority(); 1.88 + 1.89 + frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); 1.90 + 1.91 + while(!data->killNow && pDevice->Connected) 1.92 + { 1.93 + ALint len = data->data_size; 1.94 + ALubyte *WritePtr = data->mix_data; 1.95 + 1.96 + aluMixData(pDevice, WritePtr, len/frameSize); 1.97 + while(len > 0 && !data->killNow) 1.98 + { 1.99 + wrote = write(data->fd, WritePtr, len); 1.100 + if(wrote < 0) 1.101 + { 1.102 + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) 1.103 + { 1.104 + ERR("write failed: %s\n", strerror(errno)); 1.105 + aluHandleDisconnect(pDevice); 1.106 + break; 1.107 + } 1.108 + 1.109 + Sleep(1); 1.110 + continue; 1.111 + } 1.112 + 1.113 + len -= wrote; 1.114 + WritePtr += wrote; 1.115 + } 1.116 + } 1.117 + 1.118 + return 0; 1.119 +} 1.120 + 1.121 +static ALuint OSSCaptureProc(ALvoid *ptr) 1.122 +{ 1.123 + ALCdevice *pDevice = (ALCdevice*)ptr; 1.124 + oss_data *data = (oss_data*)pDevice->ExtraData; 1.125 + int frameSize; 1.126 + int amt; 1.127 + 1.128 + SetRTPriority(); 1.129 + 1.130 + frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); 1.131 + 1.132 + while(!data->killNow) 1.133 + { 1.134 + amt = read(data->fd, data->mix_data, data->data_size); 1.135 + if(amt < 0) 1.136 + { 1.137 + ERR("read failed: %s\n", strerror(errno)); 1.138 + aluHandleDisconnect(pDevice); 1.139 + break; 1.140 + } 1.141 + if(amt == 0) 1.142 + { 1.143 + Sleep(1); 1.144 + continue; 1.145 + } 1.146 + if(data->doCapture) 1.147 + WriteRingBuffer(data->ring, data->mix_data, amt/frameSize); 1.148 + } 1.149 + 1.150 + return 0; 1.151 +} 1.152 + 1.153 +static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName) 1.154 +{ 1.155 + char driver[64]; 1.156 + oss_data *data; 1.157 + 1.158 + strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1); 1.159 + driver[sizeof(driver)-1] = 0; 1.160 + if(!deviceName) 1.161 + deviceName = oss_device; 1.162 + else if(strcmp(deviceName, oss_device) != 0) 1.163 + return ALC_FALSE; 1.164 + 1.165 + data = (oss_data*)calloc(1, sizeof(oss_data)); 1.166 + data->killNow = 0; 1.167 + 1.168 + data->fd = open(driver, O_WRONLY); 1.169 + if(data->fd == -1) 1.170 + { 1.171 + free(data); 1.172 + ERR("Could not open %s: %s\n", driver, strerror(errno)); 1.173 + return ALC_FALSE; 1.174 + } 1.175 + 1.176 + device->szDeviceName = strdup(deviceName); 1.177 + device->ExtraData = data; 1.178 + return ALC_TRUE; 1.179 +} 1.180 + 1.181 +static void oss_close_playback(ALCdevice *device) 1.182 +{ 1.183 + oss_data *data = (oss_data*)device->ExtraData; 1.184 + 1.185 + close(data->fd); 1.186 + free(data); 1.187 + device->ExtraData = NULL; 1.188 +} 1.189 + 1.190 +static ALCboolean oss_reset_playback(ALCdevice *device) 1.191 +{ 1.192 + oss_data *data = (oss_data*)device->ExtraData; 1.193 + int numFragmentsLogSize; 1.194 + int log2FragmentSize; 1.195 + unsigned int periods; 1.196 + audio_buf_info info; 1.197 + ALuint frameSize; 1.198 + int numChannels; 1.199 + int ossFormat; 1.200 + int ossSpeed; 1.201 + char *err; 1.202 + 1.203 + switch(device->FmtType) 1.204 + { 1.205 + case DevFmtByte: 1.206 + ossFormat = AFMT_S8; 1.207 + break; 1.208 + case DevFmtUByte: 1.209 + ossFormat = AFMT_U8; 1.210 + break; 1.211 + case DevFmtUShort: 1.212 + case DevFmtFloat: 1.213 + device->FmtType = DevFmtShort; 1.214 + /* fall-through */ 1.215 + case DevFmtShort: 1.216 + ossFormat = AFMT_S16_NE; 1.217 + break; 1.218 + } 1.219 + 1.220 + periods = device->NumUpdates; 1.221 + numChannels = ChannelsFromDevFmt(device->FmtChans); 1.222 + frameSize = numChannels * BytesFromDevFmt(device->FmtType); 1.223 + 1.224 + ossSpeed = device->Frequency; 1.225 + log2FragmentSize = log2i(device->UpdateSize * frameSize); 1.226 + 1.227 + /* according to the OSS spec, 16 bytes are the minimum */ 1.228 + if (log2FragmentSize < 4) 1.229 + log2FragmentSize = 4; 1.230 + /* Subtract one period since the temp mixing buffer counts as one. Still 1.231 + * need at least two on the card, though. */ 1.232 + if(periods > 2) periods--; 1.233 + numFragmentsLogSize = (periods << 16) | log2FragmentSize; 1.234 + 1.235 +#define CHECKERR(func) if((func) < 0) { \ 1.236 + err = #func; \ 1.237 + goto err; \ 1.238 +} 1.239 + /* Don't fail if SETFRAGMENT fails. We can handle just about anything 1.240 + * that's reported back via GETOSPACE */ 1.241 + ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); 1.242 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat)); 1.243 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels)); 1.244 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed)); 1.245 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info)); 1.246 + if(0) 1.247 + { 1.248 + err: 1.249 + ERR("%s failed: %s\n", err, strerror(errno)); 1.250 + return ALC_FALSE; 1.251 + } 1.252 +#undef CHECKERR 1.253 + 1.254 + if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) 1.255 + { 1.256 + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); 1.257 + return ALC_FALSE; 1.258 + } 1.259 + 1.260 + if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || 1.261 + (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || 1.262 + (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) 1.263 + { 1.264 + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); 1.265 + return ALC_FALSE; 1.266 + } 1.267 + 1.268 + if(device->Frequency != (ALuint)ossSpeed) 1.269 + { 1.270 + if((device->Flags&DEVICE_FREQUENCY_REQUEST)) 1.271 + ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, ossSpeed); 1.272 + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; 1.273 + device->Frequency = ossSpeed; 1.274 + } 1.275 + device->UpdateSize = info.fragsize / frameSize; 1.276 + device->NumUpdates = info.fragments + 1; 1.277 + 1.278 + data->data_size = device->UpdateSize * frameSize; 1.279 + data->mix_data = calloc(1, data->data_size); 1.280 + 1.281 + SetDefaultChannelOrder(device); 1.282 + 1.283 + data->thread = StartThread(OSSProc, device); 1.284 + if(data->thread == NULL) 1.285 + { 1.286 + free(data->mix_data); 1.287 + data->mix_data = NULL; 1.288 + return ALC_FALSE; 1.289 + } 1.290 + 1.291 + return ALC_TRUE; 1.292 +} 1.293 + 1.294 +static void oss_stop_playback(ALCdevice *device) 1.295 +{ 1.296 + oss_data *data = (oss_data*)device->ExtraData; 1.297 + 1.298 + if(!data->thread) 1.299 + return; 1.300 + 1.301 + data->killNow = 1; 1.302 + StopThread(data->thread); 1.303 + data->thread = NULL; 1.304 + 1.305 + data->killNow = 0; 1.306 + if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0) 1.307 + ERR("Error resetting device: %s\n", strerror(errno)); 1.308 + 1.309 + free(data->mix_data); 1.310 + data->mix_data = NULL; 1.311 +} 1.312 + 1.313 + 1.314 +static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName) 1.315 +{ 1.316 + int numFragmentsLogSize; 1.317 + int log2FragmentSize; 1.318 + unsigned int periods; 1.319 + audio_buf_info info; 1.320 + ALuint frameSize; 1.321 + int numChannels; 1.322 + char driver[64]; 1.323 + oss_data *data; 1.324 + int ossFormat; 1.325 + int ossSpeed; 1.326 + char *err; 1.327 + 1.328 + strncpy(driver, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver)-1); 1.329 + driver[sizeof(driver)-1] = 0; 1.330 + if(!deviceName) 1.331 + deviceName = oss_device; 1.332 + else if(strcmp(deviceName, oss_device) != 0) 1.333 + return ALC_FALSE; 1.334 + 1.335 + data = (oss_data*)calloc(1, sizeof(oss_data)); 1.336 + data->killNow = 0; 1.337 + 1.338 + data->fd = open(driver, O_RDONLY); 1.339 + if(data->fd == -1) 1.340 + { 1.341 + free(data); 1.342 + ERR("Could not open %s: %s\n", driver, strerror(errno)); 1.343 + return ALC_FALSE; 1.344 + } 1.345 + 1.346 + switch(device->FmtType) 1.347 + { 1.348 + case DevFmtByte: 1.349 + ossFormat = AFMT_S8; 1.350 + break; 1.351 + case DevFmtUByte: 1.352 + ossFormat = AFMT_U8; 1.353 + break; 1.354 + case DevFmtShort: 1.355 + ossFormat = AFMT_S16_NE; 1.356 + break; 1.357 + case DevFmtUShort: 1.358 + case DevFmtFloat: 1.359 + free(data); 1.360 + ERR("%s capture samples not supported on OSS\n", DevFmtTypeString(device->FmtType)); 1.361 + return ALC_FALSE; 1.362 + } 1.363 + 1.364 + periods = 4; 1.365 + numChannels = ChannelsFromDevFmt(device->FmtChans); 1.366 + frameSize = numChannels * BytesFromDevFmt(device->FmtType); 1.367 + ossSpeed = device->Frequency; 1.368 + log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * 1.369 + frameSize / periods); 1.370 + 1.371 + /* according to the OSS spec, 16 bytes are the minimum */ 1.372 + if (log2FragmentSize < 4) 1.373 + log2FragmentSize = 4; 1.374 + numFragmentsLogSize = (periods << 16) | log2FragmentSize; 1.375 + 1.376 +#define CHECKERR(func) if((func) < 0) { \ 1.377 + err = #func; \ 1.378 + goto err; \ 1.379 +} 1.380 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); 1.381 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat)); 1.382 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels)); 1.383 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed)); 1.384 + CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info)); 1.385 + if(0) 1.386 + { 1.387 + err: 1.388 + ERR("%s failed: %s\n", err, strerror(errno)); 1.389 + close(data->fd); 1.390 + free(data); 1.391 + return ALC_FALSE; 1.392 + } 1.393 +#undef CHECKERR 1.394 + 1.395 + if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) 1.396 + { 1.397 + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); 1.398 + close(data->fd); 1.399 + free(data); 1.400 + return ALC_FALSE; 1.401 + } 1.402 + 1.403 + if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || 1.404 + (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || 1.405 + (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) 1.406 + { 1.407 + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); 1.408 + close(data->fd); 1.409 + free(data); 1.410 + return ALC_FALSE; 1.411 + } 1.412 + 1.413 + data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates); 1.414 + if(!data->ring) 1.415 + { 1.416 + ERR("Ring buffer create failed\n"); 1.417 + close(data->fd); 1.418 + free(data); 1.419 + return ALC_FALSE; 1.420 + } 1.421 + 1.422 + data->data_size = info.fragsize; 1.423 + data->mix_data = calloc(1, data->data_size); 1.424 + 1.425 + device->ExtraData = data; 1.426 + data->thread = StartThread(OSSCaptureProc, device); 1.427 + if(data->thread == NULL) 1.428 + { 1.429 + device->ExtraData = NULL; 1.430 + free(data->mix_data); 1.431 + free(data); 1.432 + return ALC_FALSE; 1.433 + } 1.434 + 1.435 + device->szDeviceName = strdup(deviceName); 1.436 + return ALC_TRUE; 1.437 +} 1.438 + 1.439 +static void oss_close_capture(ALCdevice *device) 1.440 +{ 1.441 + oss_data *data = (oss_data*)device->ExtraData; 1.442 + data->killNow = 1; 1.443 + StopThread(data->thread); 1.444 + 1.445 + close(data->fd); 1.446 + 1.447 + DestroyRingBuffer(data->ring); 1.448 + 1.449 + free(data->mix_data); 1.450 + free(data); 1.451 + device->ExtraData = NULL; 1.452 +} 1.453 + 1.454 +static void oss_start_capture(ALCdevice *pDevice) 1.455 +{ 1.456 + oss_data *data = (oss_data*)pDevice->ExtraData; 1.457 + data->doCapture = 1; 1.458 +} 1.459 + 1.460 +static void oss_stop_capture(ALCdevice *pDevice) 1.461 +{ 1.462 + oss_data *data = (oss_data*)pDevice->ExtraData; 1.463 + data->doCapture = 0; 1.464 +} 1.465 + 1.466 +static void oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) 1.467 +{ 1.468 + oss_data *data = (oss_data*)pDevice->ExtraData; 1.469 + if(lSamples <= (ALCuint)RingBufferSize(data->ring)) 1.470 + ReadRingBuffer(data->ring, pBuffer, lSamples); 1.471 + else 1.472 + alcSetError(pDevice, ALC_INVALID_VALUE); 1.473 +} 1.474 + 1.475 +static ALCuint oss_available_samples(ALCdevice *pDevice) 1.476 +{ 1.477 + oss_data *data = (oss_data*)pDevice->ExtraData; 1.478 + return RingBufferSize(data->ring); 1.479 +} 1.480 + 1.481 + 1.482 +static const BackendFuncs oss_funcs = { 1.483 + oss_open_playback, 1.484 + oss_close_playback, 1.485 + oss_reset_playback, 1.486 + oss_stop_playback, 1.487 + oss_open_capture, 1.488 + oss_close_capture, 1.489 + oss_start_capture, 1.490 + oss_stop_capture, 1.491 + oss_capture_samples, 1.492 + oss_available_samples 1.493 +}; 1.494 + 1.495 +ALCboolean alc_oss_init(BackendFuncs *func_list) 1.496 +{ 1.497 + *func_list = oss_funcs; 1.498 + return ALC_TRUE; 1.499 +} 1.500 + 1.501 +void alc_oss_deinit(void) 1.502 +{ 1.503 +} 1.504 + 1.505 +void alc_oss_probe(enum DevProbe type) 1.506 +{ 1.507 + switch(type) 1.508 + { 1.509 + case DEVICE_PROBE: 1.510 + { 1.511 +#ifdef HAVE_STAT 1.512 + struct stat buf; 1.513 + if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0) 1.514 +#endif 1.515 + AppendDeviceList(oss_device); 1.516 + } 1.517 + break; 1.518 + 1.519 + case ALL_DEVICE_PROBE: 1.520 + { 1.521 +#ifdef HAVE_STAT 1.522 + struct stat buf; 1.523 + if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0) 1.524 +#endif 1.525 + AppendAllDeviceList(oss_device); 1.526 + } 1.527 + break; 1.528 + 1.529 + case CAPTURE_DEVICE_PROBE: 1.530 + { 1.531 +#ifdef HAVE_STAT 1.532 + struct stat buf; 1.533 + if(stat(GetConfigValue("oss", "capture", "/dev/dsp"), &buf) == 0) 1.534 +#endif 1.535 + AppendCaptureDeviceList(oss_device); 1.536 + } 1.537 + break; 1.538 + } 1.539 +}