Mercurial > audio-send
diff Alc/backends/alsa.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/alsa.c Tue Oct 25 13:02:31 2011 -0700 1.3 @@ -0,0 +1,1138 @@ 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 <stdlib.h> 1.27 +#include <stdio.h> 1.28 +#include <memory.h> 1.29 + 1.30 +#include "alMain.h" 1.31 + 1.32 +#include <alsa/asoundlib.h> 1.33 + 1.34 + 1.35 +static const ALCchar alsaDevice[] = "ALSA Default"; 1.36 + 1.37 + 1.38 +static void *alsa_handle; 1.39 +#ifdef HAVE_DYNLOAD 1.40 +#define MAKE_FUNC(f) static typeof(f) * p##f 1.41 +MAKE_FUNC(snd_strerror); 1.42 +MAKE_FUNC(snd_pcm_open); 1.43 +MAKE_FUNC(snd_pcm_close); 1.44 +MAKE_FUNC(snd_pcm_nonblock); 1.45 +MAKE_FUNC(snd_pcm_frames_to_bytes); 1.46 +MAKE_FUNC(snd_pcm_bytes_to_frames); 1.47 +MAKE_FUNC(snd_pcm_hw_params_malloc); 1.48 +MAKE_FUNC(snd_pcm_hw_params_free); 1.49 +MAKE_FUNC(snd_pcm_hw_params_any); 1.50 +MAKE_FUNC(snd_pcm_hw_params_set_access); 1.51 +MAKE_FUNC(snd_pcm_hw_params_set_format); 1.52 +MAKE_FUNC(snd_pcm_hw_params_set_channels); 1.53 +MAKE_FUNC(snd_pcm_hw_params_set_periods_near); 1.54 +MAKE_FUNC(snd_pcm_hw_params_set_rate_near); 1.55 +MAKE_FUNC(snd_pcm_hw_params_set_rate); 1.56 +MAKE_FUNC(snd_pcm_hw_params_set_rate_resample); 1.57 +MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near); 1.58 +MAKE_FUNC(snd_pcm_hw_params_set_period_time_near); 1.59 +MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near); 1.60 +MAKE_FUNC(snd_pcm_hw_params_set_period_size_near); 1.61 +MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min); 1.62 +MAKE_FUNC(snd_pcm_hw_params_get_buffer_size); 1.63 +MAKE_FUNC(snd_pcm_hw_params_get_period_size); 1.64 +MAKE_FUNC(snd_pcm_hw_params_get_access); 1.65 +MAKE_FUNC(snd_pcm_hw_params_get_periods); 1.66 +MAKE_FUNC(snd_pcm_hw_params); 1.67 +MAKE_FUNC(snd_pcm_sw_params_malloc); 1.68 +MAKE_FUNC(snd_pcm_sw_params_current); 1.69 +MAKE_FUNC(snd_pcm_sw_params_set_avail_min); 1.70 +MAKE_FUNC(snd_pcm_sw_params); 1.71 +MAKE_FUNC(snd_pcm_sw_params_free); 1.72 +MAKE_FUNC(snd_pcm_prepare); 1.73 +MAKE_FUNC(snd_pcm_start); 1.74 +MAKE_FUNC(snd_pcm_resume); 1.75 +MAKE_FUNC(snd_pcm_wait); 1.76 +MAKE_FUNC(snd_pcm_state); 1.77 +MAKE_FUNC(snd_pcm_avail_update); 1.78 +MAKE_FUNC(snd_pcm_areas_silence); 1.79 +MAKE_FUNC(snd_pcm_mmap_begin); 1.80 +MAKE_FUNC(snd_pcm_mmap_commit); 1.81 +MAKE_FUNC(snd_pcm_readi); 1.82 +MAKE_FUNC(snd_pcm_writei); 1.83 +MAKE_FUNC(snd_pcm_drain); 1.84 +MAKE_FUNC(snd_pcm_recover); 1.85 +MAKE_FUNC(snd_pcm_info_malloc); 1.86 +MAKE_FUNC(snd_pcm_info_free); 1.87 +MAKE_FUNC(snd_pcm_info_set_device); 1.88 +MAKE_FUNC(snd_pcm_info_set_subdevice); 1.89 +MAKE_FUNC(snd_pcm_info_set_stream); 1.90 +MAKE_FUNC(snd_pcm_info_get_name); 1.91 +MAKE_FUNC(snd_ctl_pcm_next_device); 1.92 +MAKE_FUNC(snd_ctl_pcm_info); 1.93 +MAKE_FUNC(snd_ctl_open); 1.94 +MAKE_FUNC(snd_ctl_close); 1.95 +MAKE_FUNC(snd_ctl_card_info_malloc); 1.96 +MAKE_FUNC(snd_ctl_card_info_free); 1.97 +MAKE_FUNC(snd_ctl_card_info); 1.98 +MAKE_FUNC(snd_ctl_card_info_get_name); 1.99 +MAKE_FUNC(snd_ctl_card_info_get_id); 1.100 +MAKE_FUNC(snd_card_next); 1.101 +#undef MAKE_FUNC 1.102 + 1.103 +#define snd_strerror psnd_strerror 1.104 +#define snd_pcm_open psnd_pcm_open 1.105 +#define snd_pcm_close psnd_pcm_close 1.106 +#define snd_pcm_nonblock psnd_pcm_nonblock 1.107 +#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes 1.108 +#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames 1.109 +#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc 1.110 +#define snd_pcm_hw_params_free psnd_pcm_hw_params_free 1.111 +#define snd_pcm_hw_params_any psnd_pcm_hw_params_any 1.112 +#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access 1.113 +#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format 1.114 +#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels 1.115 +#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near 1.116 +#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near 1.117 +#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate 1.118 +#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample 1.119 +#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near 1.120 +#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near 1.121 +#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near 1.122 +#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near 1.123 +#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min 1.124 +#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size 1.125 +#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size 1.126 +#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access 1.127 +#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods 1.128 +#define snd_pcm_hw_params psnd_pcm_hw_params 1.129 +#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc 1.130 +#define snd_pcm_sw_params_current psnd_pcm_sw_params_current 1.131 +#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min 1.132 +#define snd_pcm_sw_params psnd_pcm_sw_params 1.133 +#define snd_pcm_sw_params_free psnd_pcm_sw_params_free 1.134 +#define snd_pcm_prepare psnd_pcm_prepare 1.135 +#define snd_pcm_start psnd_pcm_start 1.136 +#define snd_pcm_resume psnd_pcm_resume 1.137 +#define snd_pcm_wait psnd_pcm_wait 1.138 +#define snd_pcm_state psnd_pcm_state 1.139 +#define snd_pcm_avail_update psnd_pcm_avail_update 1.140 +#define snd_pcm_areas_silence psnd_pcm_areas_silence 1.141 +#define snd_pcm_mmap_begin psnd_pcm_mmap_begin 1.142 +#define snd_pcm_mmap_commit psnd_pcm_mmap_commit 1.143 +#define snd_pcm_readi psnd_pcm_readi 1.144 +#define snd_pcm_writei psnd_pcm_writei 1.145 +#define snd_pcm_drain psnd_pcm_drain 1.146 +#define snd_pcm_recover psnd_pcm_recover 1.147 +#define snd_pcm_info_malloc psnd_pcm_info_malloc 1.148 +#define snd_pcm_info_free psnd_pcm_info_free 1.149 +#define snd_pcm_info_set_device psnd_pcm_info_set_device 1.150 +#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice 1.151 +#define snd_pcm_info_set_stream psnd_pcm_info_set_stream 1.152 +#define snd_pcm_info_get_name psnd_pcm_info_get_name 1.153 +#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device 1.154 +#define snd_ctl_pcm_info psnd_ctl_pcm_info 1.155 +#define snd_ctl_open psnd_ctl_open 1.156 +#define snd_ctl_close psnd_ctl_close 1.157 +#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc 1.158 +#define snd_ctl_card_info_free psnd_ctl_card_info_free 1.159 +#define snd_ctl_card_info psnd_ctl_card_info 1.160 +#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name 1.161 +#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id 1.162 +#define snd_card_next psnd_card_next 1.163 +#endif 1.164 + 1.165 + 1.166 +static ALCboolean alsa_load(void) 1.167 +{ 1.168 + if(!alsa_handle) 1.169 + { 1.170 +#ifdef HAVE_DYNLOAD 1.171 + alsa_handle = LoadLib("libasound.so.2"); 1.172 + if(!alsa_handle) 1.173 + return ALC_FALSE; 1.174 + 1.175 +#define LOAD_FUNC(f) do { \ 1.176 + p##f = GetSymbol(alsa_handle, #f); \ 1.177 + if(p##f == NULL) { \ 1.178 + CloseLib(alsa_handle); \ 1.179 + alsa_handle = NULL; \ 1.180 + return ALC_FALSE; \ 1.181 + } \ 1.182 +} while(0) 1.183 + LOAD_FUNC(snd_strerror); 1.184 + LOAD_FUNC(snd_pcm_open); 1.185 + LOAD_FUNC(snd_pcm_close); 1.186 + LOAD_FUNC(snd_pcm_nonblock); 1.187 + LOAD_FUNC(snd_pcm_frames_to_bytes); 1.188 + LOAD_FUNC(snd_pcm_bytes_to_frames); 1.189 + LOAD_FUNC(snd_pcm_hw_params_malloc); 1.190 + LOAD_FUNC(snd_pcm_hw_params_free); 1.191 + LOAD_FUNC(snd_pcm_hw_params_any); 1.192 + LOAD_FUNC(snd_pcm_hw_params_set_access); 1.193 + LOAD_FUNC(snd_pcm_hw_params_set_format); 1.194 + LOAD_FUNC(snd_pcm_hw_params_set_channels); 1.195 + LOAD_FUNC(snd_pcm_hw_params_set_periods_near); 1.196 + LOAD_FUNC(snd_pcm_hw_params_set_rate_near); 1.197 + LOAD_FUNC(snd_pcm_hw_params_set_rate); 1.198 + LOAD_FUNC(snd_pcm_hw_params_set_rate_resample); 1.199 + LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near); 1.200 + LOAD_FUNC(snd_pcm_hw_params_set_period_time_near); 1.201 + LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); 1.202 + LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); 1.203 + LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); 1.204 + LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); 1.205 + LOAD_FUNC(snd_pcm_hw_params_get_period_size); 1.206 + LOAD_FUNC(snd_pcm_hw_params_get_access); 1.207 + LOAD_FUNC(snd_pcm_hw_params_get_periods); 1.208 + LOAD_FUNC(snd_pcm_hw_params); 1.209 + LOAD_FUNC(snd_pcm_sw_params_malloc); 1.210 + LOAD_FUNC(snd_pcm_sw_params_current); 1.211 + LOAD_FUNC(snd_pcm_sw_params_set_avail_min); 1.212 + LOAD_FUNC(snd_pcm_sw_params); 1.213 + LOAD_FUNC(snd_pcm_sw_params_free); 1.214 + LOAD_FUNC(snd_pcm_prepare); 1.215 + LOAD_FUNC(snd_pcm_start); 1.216 + LOAD_FUNC(snd_pcm_resume); 1.217 + LOAD_FUNC(snd_pcm_wait); 1.218 + LOAD_FUNC(snd_pcm_state); 1.219 + LOAD_FUNC(snd_pcm_avail_update); 1.220 + LOAD_FUNC(snd_pcm_areas_silence); 1.221 + LOAD_FUNC(snd_pcm_mmap_begin); 1.222 + LOAD_FUNC(snd_pcm_mmap_commit); 1.223 + LOAD_FUNC(snd_pcm_readi); 1.224 + LOAD_FUNC(snd_pcm_writei); 1.225 + LOAD_FUNC(snd_pcm_drain); 1.226 + LOAD_FUNC(snd_pcm_recover); 1.227 + LOAD_FUNC(snd_pcm_info_malloc); 1.228 + LOAD_FUNC(snd_pcm_info_free); 1.229 + LOAD_FUNC(snd_pcm_info_set_device); 1.230 + LOAD_FUNC(snd_pcm_info_set_subdevice); 1.231 + LOAD_FUNC(snd_pcm_info_set_stream); 1.232 + LOAD_FUNC(snd_pcm_info_get_name); 1.233 + LOAD_FUNC(snd_ctl_pcm_next_device); 1.234 + LOAD_FUNC(snd_ctl_pcm_info); 1.235 + LOAD_FUNC(snd_ctl_open); 1.236 + LOAD_FUNC(snd_ctl_close); 1.237 + LOAD_FUNC(snd_ctl_card_info_malloc); 1.238 + LOAD_FUNC(snd_ctl_card_info_free); 1.239 + LOAD_FUNC(snd_ctl_card_info); 1.240 + LOAD_FUNC(snd_ctl_card_info_get_name); 1.241 + LOAD_FUNC(snd_ctl_card_info_get_id); 1.242 + LOAD_FUNC(snd_card_next); 1.243 +#undef LOAD_FUNC 1.244 +#else 1.245 + alsa_handle = (void*)0xDEADBEEF; 1.246 +#endif 1.247 + } 1.248 + return ALC_TRUE; 1.249 +} 1.250 + 1.251 + 1.252 +typedef struct { 1.253 + snd_pcm_t *pcmHandle; 1.254 + 1.255 + ALvoid *buffer; 1.256 + ALsizei size; 1.257 + 1.258 + ALboolean doCapture; 1.259 + RingBuffer *ring; 1.260 + 1.261 + volatile int killNow; 1.262 + ALvoid *thread; 1.263 +} alsa_data; 1.264 + 1.265 +typedef struct { 1.266 + ALCchar *name; 1.267 + char *card; 1.268 + int dev; 1.269 +} DevMap; 1.270 + 1.271 +static DevMap *allDevNameMap; 1.272 +static ALuint numDevNames; 1.273 +static DevMap *allCaptureDevNameMap; 1.274 +static ALuint numCaptureDevNames; 1.275 + 1.276 +static const char *device_prefix; 1.277 +static const char *capture_prefix; 1.278 + 1.279 + 1.280 +static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count) 1.281 +{ 1.282 + snd_ctl_t *handle; 1.283 + int card, err, dev, idx; 1.284 + snd_ctl_card_info_t *info; 1.285 + snd_pcm_info_t *pcminfo; 1.286 + DevMap *DevList; 1.287 + char name[1024]; 1.288 + 1.289 + snd_ctl_card_info_malloc(&info); 1.290 + snd_pcm_info_malloc(&pcminfo); 1.291 + 1.292 + card = -1; 1.293 + if((err=snd_card_next(&card)) < 0) 1.294 + ERR("Failed to find a card: %s\n", snd_strerror(err)); 1.295 + 1.296 + DevList = malloc(sizeof(DevMap) * 1); 1.297 + DevList[0].name = strdup("ALSA Default"); 1.298 + DevList[0].card = NULL; 1.299 + DevList[0].dev = 0; 1.300 + idx = 1; 1.301 + while(card >= 0) 1.302 + { 1.303 + sprintf(name, "hw:%d", card); 1.304 + if((err = snd_ctl_open(&handle, name, 0)) < 0) 1.305 + { 1.306 + ERR("control open (%i): %s\n", card, snd_strerror(err)); 1.307 + goto next_card; 1.308 + } 1.309 + if((err = snd_ctl_card_info(handle, info)) < 0) 1.310 + { 1.311 + ERR("control hardware info (%i): %s\n", card, snd_strerror(err)); 1.312 + snd_ctl_close(handle); 1.313 + goto next_card; 1.314 + } 1.315 + 1.316 + dev = -1; 1.317 + while(1) 1.318 + { 1.319 + const char *cname, *dname, *cid; 1.320 + void *temp; 1.321 + 1.322 + if(snd_ctl_pcm_next_device(handle, &dev) < 0) 1.323 + ERR("snd_ctl_pcm_next_device failed\n"); 1.324 + if(dev < 0) 1.325 + break; 1.326 + 1.327 + snd_pcm_info_set_device(pcminfo, dev); 1.328 + snd_pcm_info_set_subdevice(pcminfo, 0); 1.329 + snd_pcm_info_set_stream(pcminfo, stream); 1.330 + if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) { 1.331 + if(err != -ENOENT) 1.332 + ERR("control digital audio info (%i): %s\n", card, snd_strerror(err)); 1.333 + continue; 1.334 + } 1.335 + 1.336 + temp = realloc(DevList, sizeof(DevMap) * (idx+1)); 1.337 + if(temp) 1.338 + { 1.339 + DevList = temp; 1.340 + cname = snd_ctl_card_info_get_name(info); 1.341 + dname = snd_pcm_info_get_name(pcminfo); 1.342 + cid = snd_ctl_card_info_get_id(info); 1.343 + snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", 1.344 + cname, dname, cid, dev); 1.345 + DevList[idx].name = strdup(name); 1.346 + DevList[idx].card = strdup(cid); 1.347 + DevList[idx].dev = dev; 1.348 + idx++; 1.349 + } 1.350 + } 1.351 + snd_ctl_close(handle); 1.352 + next_card: 1.353 + if(snd_card_next(&card) < 0) { 1.354 + ERR("snd_card_next failed\n"); 1.355 + break; 1.356 + } 1.357 + } 1.358 + 1.359 + snd_pcm_info_free(pcminfo); 1.360 + snd_ctl_card_info_free(info); 1.361 + 1.362 + *count = idx; 1.363 + return DevList; 1.364 +} 1.365 + 1.366 + 1.367 +static int xrun_recovery(snd_pcm_t *handle, int err) 1.368 +{ 1.369 + err = snd_pcm_recover(handle, err, 1); 1.370 + if(err < 0) 1.371 + ERR("recover failed: %s\n", snd_strerror(err)); 1.372 + return err; 1.373 +} 1.374 + 1.375 +static int verify_state(snd_pcm_t *handle) 1.376 +{ 1.377 + snd_pcm_state_t state = snd_pcm_state(handle); 1.378 + if(state == SND_PCM_STATE_DISCONNECTED) 1.379 + return -ENODEV; 1.380 + if(state == SND_PCM_STATE_XRUN) 1.381 + { 1.382 + int err = xrun_recovery(handle, -EPIPE); 1.383 + if(err < 0) return err; 1.384 + } 1.385 + else if(state == SND_PCM_STATE_SUSPENDED) 1.386 + { 1.387 + int err = xrun_recovery(handle, -ESTRPIPE); 1.388 + if(err < 0) return err; 1.389 + } 1.390 + 1.391 + return state; 1.392 +} 1.393 + 1.394 + 1.395 +static ALuint ALSAProc(ALvoid *ptr) 1.396 +{ 1.397 + ALCdevice *pDevice = (ALCdevice*)ptr; 1.398 + alsa_data *data = (alsa_data*)pDevice->ExtraData; 1.399 + const snd_pcm_channel_area_t *areas = NULL; 1.400 + snd_pcm_sframes_t avail, commitres; 1.401 + snd_pcm_uframes_t offset, frames; 1.402 + char *WritePtr; 1.403 + int err; 1.404 + 1.405 + SetRTPriority(); 1.406 + 1.407 + while(!data->killNow) 1.408 + { 1.409 + int state = verify_state(data->pcmHandle); 1.410 + if(state < 0) 1.411 + { 1.412 + ERR("Invalid state detected: %s\n", snd_strerror(state)); 1.413 + aluHandleDisconnect(pDevice); 1.414 + break; 1.415 + } 1.416 + 1.417 + avail = snd_pcm_avail_update(data->pcmHandle); 1.418 + if(avail < 0) 1.419 + { 1.420 + ERR("available update failed: %s\n", snd_strerror(avail)); 1.421 + continue; 1.422 + } 1.423 + 1.424 + // make sure there's frames to process 1.425 + if((snd_pcm_uframes_t)avail < pDevice->UpdateSize) 1.426 + { 1.427 + if(state != SND_PCM_STATE_RUNNING) 1.428 + { 1.429 + err = snd_pcm_start(data->pcmHandle); 1.430 + if(err < 0) 1.431 + { 1.432 + ERR("start failed: %s\n", snd_strerror(err)); 1.433 + continue; 1.434 + } 1.435 + } 1.436 + if(snd_pcm_wait(data->pcmHandle, 1000) == 0) 1.437 + ERR("Wait timeout... buffer size too low?\n"); 1.438 + continue; 1.439 + } 1.440 + avail -= avail%pDevice->UpdateSize; 1.441 + 1.442 + // it is possible that contiguous areas are smaller, thus we use a loop 1.443 + while(avail > 0) 1.444 + { 1.445 + frames = avail; 1.446 + 1.447 + err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames); 1.448 + if(err < 0) 1.449 + { 1.450 + ERR("mmap begin error: %s\n", snd_strerror(err)); 1.451 + break; 1.452 + } 1.453 + 1.454 + WritePtr = (char*)areas->addr + (offset * areas->step / 8); 1.455 + aluMixData(pDevice, WritePtr, frames); 1.456 + 1.457 + commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames); 1.458 + if(commitres < 0 || (commitres-frames) != 0) 1.459 + { 1.460 + ERR("mmap commit error: %s\n", 1.461 + snd_strerror(commitres >= 0 ? -EPIPE : commitres)); 1.462 + break; 1.463 + } 1.464 + 1.465 + avail -= frames; 1.466 + } 1.467 + } 1.468 + 1.469 + return 0; 1.470 +} 1.471 + 1.472 +static ALuint ALSANoMMapProc(ALvoid *ptr) 1.473 +{ 1.474 + ALCdevice *pDevice = (ALCdevice*)ptr; 1.475 + alsa_data *data = (alsa_data*)pDevice->ExtraData; 1.476 + snd_pcm_sframes_t avail; 1.477 + char *WritePtr; 1.478 + 1.479 + SetRTPriority(); 1.480 + 1.481 + while(!data->killNow) 1.482 + { 1.483 + int state = verify_state(data->pcmHandle); 1.484 + if(state < 0) 1.485 + { 1.486 + ERR("Invalid state detected: %s\n", snd_strerror(state)); 1.487 + aluHandleDisconnect(pDevice); 1.488 + break; 1.489 + } 1.490 + 1.491 + WritePtr = data->buffer; 1.492 + avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1); 1.493 + aluMixData(pDevice, WritePtr, avail); 1.494 + 1.495 + while(avail > 0) 1.496 + { 1.497 + int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail); 1.498 + switch (ret) 1.499 + { 1.500 + case -EAGAIN: 1.501 + continue; 1.502 + case -ESTRPIPE: 1.503 + case -EPIPE: 1.504 + case -EINTR: 1.505 + ret = snd_pcm_recover(data->pcmHandle, ret, 1); 1.506 + if(ret < 0) 1.507 + avail = 0; 1.508 + break; 1.509 + default: 1.510 + if (ret >= 0) 1.511 + { 1.512 + WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret); 1.513 + avail -= ret; 1.514 + } 1.515 + break; 1.516 + } 1.517 + if (ret < 0) 1.518 + { 1.519 + ret = snd_pcm_prepare(data->pcmHandle); 1.520 + if(ret < 0) 1.521 + break; 1.522 + } 1.523 + } 1.524 + } 1.525 + 1.526 + return 0; 1.527 +} 1.528 + 1.529 +static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName) 1.530 +{ 1.531 + alsa_data *data; 1.532 + char driver[128]; 1.533 + int i; 1.534 + 1.535 + strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1); 1.536 + driver[sizeof(driver)-1] = 0; 1.537 + 1.538 + if(!deviceName) 1.539 + deviceName = alsaDevice; 1.540 + else if(strcmp(deviceName, alsaDevice) != 0) 1.541 + { 1.542 + size_t idx; 1.543 + 1.544 + if(!allDevNameMap) 1.545 + allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames); 1.546 + 1.547 + for(idx = 0;idx < numDevNames;idx++) 1.548 + { 1.549 + if(allDevNameMap[idx].name && 1.550 + strcmp(deviceName, allDevNameMap[idx].name) == 0) 1.551 + { 1.552 + if(idx > 0) 1.553 + snprintf(driver, sizeof(driver), "%sCARD=%s,DEV=%d", device_prefix, 1.554 + allDevNameMap[idx].card, allDevNameMap[idx].dev); 1.555 + break; 1.556 + } 1.557 + } 1.558 + if(idx == numDevNames) 1.559 + return ALC_FALSE; 1.560 + } 1.561 + 1.562 + data = (alsa_data*)calloc(1, sizeof(alsa_data)); 1.563 + 1.564 + i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 1.565 + if(i >= 0) 1.566 + { 1.567 + i = snd_pcm_nonblock(data->pcmHandle, 0); 1.568 + if(i < 0) 1.569 + snd_pcm_close(data->pcmHandle); 1.570 + } 1.571 + if(i < 0) 1.572 + { 1.573 + free(data); 1.574 + ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(i)); 1.575 + return ALC_FALSE; 1.576 + } 1.577 + 1.578 + device->szDeviceName = strdup(deviceName); 1.579 + device->ExtraData = data; 1.580 + return ALC_TRUE; 1.581 +} 1.582 + 1.583 +static void alsa_close_playback(ALCdevice *device) 1.584 +{ 1.585 + alsa_data *data = (alsa_data*)device->ExtraData; 1.586 + 1.587 + snd_pcm_close(data->pcmHandle); 1.588 + free(data); 1.589 + device->ExtraData = NULL; 1.590 +} 1.591 + 1.592 +static ALCboolean alsa_reset_playback(ALCdevice *device) 1.593 +{ 1.594 + alsa_data *data = (alsa_data*)device->ExtraData; 1.595 + snd_pcm_uframes_t periodSizeInFrames; 1.596 + unsigned int periodLen, bufferLen; 1.597 + snd_pcm_sw_params_t *sp = NULL; 1.598 + snd_pcm_hw_params_t *p = NULL; 1.599 + snd_pcm_access_t access; 1.600 + snd_pcm_format_t format; 1.601 + unsigned int periods; 1.602 + unsigned int rate; 1.603 + int allowmmap; 1.604 + char *err; 1.605 + int i; 1.606 + 1.607 + 1.608 + format = -1; 1.609 + switch(device->FmtType) 1.610 + { 1.611 + case DevFmtByte: 1.612 + format = SND_PCM_FORMAT_S8; 1.613 + break; 1.614 + case DevFmtUByte: 1.615 + format = SND_PCM_FORMAT_U8; 1.616 + break; 1.617 + case DevFmtShort: 1.618 + format = SND_PCM_FORMAT_S16; 1.619 + break; 1.620 + case DevFmtUShort: 1.621 + format = SND_PCM_FORMAT_U16; 1.622 + break; 1.623 + case DevFmtFloat: 1.624 + format = SND_PCM_FORMAT_FLOAT; 1.625 + break; 1.626 + } 1.627 + 1.628 + allowmmap = GetConfigValueBool("alsa", "mmap", 1); 1.629 + periods = device->NumUpdates; 1.630 + periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; 1.631 + bufferLen = periodLen * periods; 1.632 + rate = device->Frequency; 1.633 + 1.634 + err = NULL; 1.635 + snd_pcm_hw_params_malloc(&p); 1.636 + 1.637 + if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0) 1.638 + err = "any"; 1.639 + /* set interleaved access */ 1.640 + if(i >= 0 && (!allowmmap || (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)) 1.641 + { 1.642 + if(periods > 2) 1.643 + { 1.644 + periods--; 1.645 + bufferLen = periodLen * periods; 1.646 + } 1.647 + if((i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 1.648 + err = "set access"; 1.649 + } 1.650 + /* set format (implicitly sets sample bits) */ 1.651 + if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) 1.652 + { 1.653 + device->FmtType = DevFmtFloat; 1.654 + if(format == SND_PCM_FORMAT_FLOAT || 1.655 + (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0) 1.656 + { 1.657 + device->FmtType = DevFmtShort; 1.658 + if(format == SND_PCM_FORMAT_S16 || 1.659 + (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0) 1.660 + { 1.661 + device->FmtType = DevFmtUByte; 1.662 + if(format == SND_PCM_FORMAT_U8 || 1.663 + (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0) 1.664 + err = "set format"; 1.665 + } 1.666 + } 1.667 + } 1.668 + /* set channels (implicitly sets frame bits) */ 1.669 + if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0) 1.670 + { 1.671 + if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0) 1.672 + { 1.673 + if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0) 1.674 + err = "set channels"; 1.675 + else 1.676 + { 1.677 + if((device->Flags&DEVICE_CHANNELS_REQUEST)) 1.678 + ERR("Failed to set %s, got Mono instead\n", DevFmtChannelsString(device->FmtChans)); 1.679 + device->FmtChans = DevFmtMono; 1.680 + } 1.681 + } 1.682 + else 1.683 + { 1.684 + if((device->Flags&DEVICE_CHANNELS_REQUEST)) 1.685 + ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(device->FmtChans)); 1.686 + device->FmtChans = DevFmtStereo; 1.687 + } 1.688 + device->Flags &= ~DEVICE_CHANNELS_REQUEST; 1.689 + } 1.690 + if(i >= 0 && (i=snd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0) 1.691 + { 1.692 + ERR("Failed to disable ALSA resampler\n"); 1.693 + i = 0; 1.694 + } 1.695 + /* set rate (implicitly constrains period/buffer parameters) */ 1.696 + if(i >= 0 && (i=snd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0) 1.697 + err = "set rate near"; 1.698 + /* set buffer time (implicitly constrains period/buffer parameters) */ 1.699 + if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0) 1.700 + err = "set buffer time near"; 1.701 + /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */ 1.702 + if(i >= 0 && (i=snd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0) 1.703 + err = "set period time near"; 1.704 + /* install and prepare hardware configuration */ 1.705 + if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0) 1.706 + err = "set params"; 1.707 + if(i >= 0 && (i=snd_pcm_hw_params_get_access(p, &access)) < 0) 1.708 + err = "get access"; 1.709 + if(i >= 0 && (i=snd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0) 1.710 + err = "get period size"; 1.711 + if(i >= 0 && (i=snd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0) 1.712 + err = "get periods"; 1.713 + if(i < 0) 1.714 + { 1.715 + ERR("%s failed: %s\n", err, snd_strerror(i)); 1.716 + snd_pcm_hw_params_free(p); 1.717 + return ALC_FALSE; 1.718 + } 1.719 + 1.720 + snd_pcm_hw_params_free(p); 1.721 + 1.722 + err = NULL; 1.723 + snd_pcm_sw_params_malloc(&sp); 1.724 + 1.725 + if((i=snd_pcm_sw_params_current(data->pcmHandle, sp)) != 0) 1.726 + err = "sw current"; 1.727 + if(i == 0 && (i=snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0) 1.728 + err = "sw set avail min"; 1.729 + if(i == 0 && (i=snd_pcm_sw_params(data->pcmHandle, sp)) != 0) 1.730 + err = "sw set params"; 1.731 + if(i != 0) 1.732 + { 1.733 + ERR("%s failed: %s\n", err, snd_strerror(i)); 1.734 + snd_pcm_sw_params_free(sp); 1.735 + return ALC_FALSE; 1.736 + } 1.737 + 1.738 + snd_pcm_sw_params_free(sp); 1.739 + 1.740 + if(device->Frequency != rate) 1.741 + { 1.742 + if((device->Flags&DEVICE_FREQUENCY_REQUEST)) 1.743 + ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, rate); 1.744 + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; 1.745 + device->Frequency = rate; 1.746 + } 1.747 + 1.748 + SetDefaultChannelOrder(device); 1.749 + 1.750 + data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); 1.751 + if(access == SND_PCM_ACCESS_RW_INTERLEAVED) 1.752 + { 1.753 + /* Increase periods by one, since the temp buffer counts as an extra 1.754 + * period */ 1.755 + periods++; 1.756 + data->buffer = malloc(data->size); 1.757 + if(!data->buffer) 1.758 + { 1.759 + ERR("buffer malloc failed\n"); 1.760 + return ALC_FALSE; 1.761 + } 1.762 + device->UpdateSize = periodSizeInFrames; 1.763 + device->NumUpdates = periods; 1.764 + data->thread = StartThread(ALSANoMMapProc, device); 1.765 + } 1.766 + else 1.767 + { 1.768 + i = snd_pcm_prepare(data->pcmHandle); 1.769 + if(i < 0) 1.770 + { 1.771 + ERR("prepare error: %s\n", snd_strerror(i)); 1.772 + return ALC_FALSE; 1.773 + } 1.774 + device->UpdateSize = periodSizeInFrames; 1.775 + device->NumUpdates = periods; 1.776 + data->thread = StartThread(ALSAProc, device); 1.777 + } 1.778 + if(data->thread == NULL) 1.779 + { 1.780 + ERR("Could not create playback thread\n"); 1.781 + free(data->buffer); 1.782 + data->buffer = NULL; 1.783 + return ALC_FALSE; 1.784 + } 1.785 + 1.786 + return ALC_TRUE; 1.787 +} 1.788 + 1.789 +static void alsa_stop_playback(ALCdevice *device) 1.790 +{ 1.791 + alsa_data *data = (alsa_data*)device->ExtraData; 1.792 + 1.793 + if(data->thread) 1.794 + { 1.795 + data->killNow = 1; 1.796 + StopThread(data->thread); 1.797 + data->thread = NULL; 1.798 + } 1.799 + data->killNow = 0; 1.800 + free(data->buffer); 1.801 + data->buffer = NULL; 1.802 +} 1.803 + 1.804 + 1.805 +static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName) 1.806 +{ 1.807 + snd_pcm_hw_params_t *p; 1.808 + snd_pcm_uframes_t bufferSizeInFrames; 1.809 + snd_pcm_format_t format; 1.810 + ALuint frameSize; 1.811 + alsa_data *data; 1.812 + char driver[128]; 1.813 + char *err; 1.814 + int i; 1.815 + 1.816 + strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); 1.817 + driver[sizeof(driver)-1] = 0; 1.818 + 1.819 + if(!allCaptureDevNameMap) 1.820 + allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); 1.821 + 1.822 + if(!deviceName) 1.823 + deviceName = allCaptureDevNameMap[0].name; 1.824 + else 1.825 + { 1.826 + size_t idx; 1.827 + 1.828 + for(idx = 0;idx < numCaptureDevNames;idx++) 1.829 + { 1.830 + if(allCaptureDevNameMap[idx].name && 1.831 + strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) 1.832 + { 1.833 + if(idx > 0) 1.834 + snprintf(driver, sizeof(driver), "%sCARD=%s,DEV=%d", capture_prefix, 1.835 + allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev); 1.836 + break; 1.837 + } 1.838 + } 1.839 + if(idx == numCaptureDevNames) 1.840 + return ALC_FALSE; 1.841 + } 1.842 + 1.843 + data = (alsa_data*)calloc(1, sizeof(alsa_data)); 1.844 + 1.845 + i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); 1.846 + if(i < 0) 1.847 + { 1.848 + ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(i)); 1.849 + free(data); 1.850 + return ALC_FALSE; 1.851 + } 1.852 + 1.853 + format = -1; 1.854 + switch(pDevice->FmtType) 1.855 + { 1.856 + case DevFmtByte: 1.857 + format = SND_PCM_FORMAT_S8; 1.858 + break; 1.859 + case DevFmtUByte: 1.860 + format = SND_PCM_FORMAT_U8; 1.861 + break; 1.862 + case DevFmtShort: 1.863 + format = SND_PCM_FORMAT_S16; 1.864 + break; 1.865 + case DevFmtUShort: 1.866 + format = SND_PCM_FORMAT_U16; 1.867 + break; 1.868 + case DevFmtFloat: 1.869 + format = SND_PCM_FORMAT_FLOAT; 1.870 + break; 1.871 + } 1.872 + 1.873 + err = NULL; 1.874 + bufferSizeInFrames = pDevice->UpdateSize * pDevice->NumUpdates; 1.875 + snd_pcm_hw_params_malloc(&p); 1.876 + 1.877 + if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0) 1.878 + err = "any"; 1.879 + /* set interleaved access */ 1.880 + if(i >= 0 && (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 1.881 + err = "set access"; 1.882 + /* set format (implicitly sets sample bits) */ 1.883 + if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) 1.884 + err = "set format"; 1.885 + /* set channels (implicitly sets frame bits) */ 1.886 + if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0) 1.887 + err = "set channels"; 1.888 + /* set rate (implicitly constrains period/buffer parameters) */ 1.889 + if(i >= 0 && (i=snd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0) 1.890 + err = "set rate near"; 1.891 + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ 1.892 + if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0) 1.893 + err = "set buffer size near"; 1.894 + /* install and prepare hardware configuration */ 1.895 + if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0) 1.896 + err = "set params"; 1.897 + if(i < 0) 1.898 + { 1.899 + ERR("%s failed: %s\n", err, snd_strerror(i)); 1.900 + snd_pcm_hw_params_free(p); 1.901 + goto error; 1.902 + } 1.903 + 1.904 + if((i=snd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0) 1.905 + { 1.906 + ERR("get size failed: %s\n", snd_strerror(i)); 1.907 + snd_pcm_hw_params_free(p); 1.908 + goto error; 1.909 + } 1.910 + 1.911 + snd_pcm_hw_params_free(p); 1.912 + 1.913 + frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); 1.914 + 1.915 + data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates); 1.916 + if(!data->ring) 1.917 + { 1.918 + ERR("ring buffer create failed\n"); 1.919 + goto error; 1.920 + } 1.921 + 1.922 + data->size = snd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames); 1.923 + data->buffer = malloc(data->size); 1.924 + if(!data->buffer) 1.925 + { 1.926 + ERR("buffer malloc failed\n"); 1.927 + goto error; 1.928 + } 1.929 + 1.930 + pDevice->szDeviceName = strdup(deviceName); 1.931 + 1.932 + pDevice->ExtraData = data; 1.933 + return ALC_TRUE; 1.934 + 1.935 +error: 1.936 + free(data->buffer); 1.937 + DestroyRingBuffer(data->ring); 1.938 + snd_pcm_close(data->pcmHandle); 1.939 + free(data); 1.940 + 1.941 + pDevice->ExtraData = NULL; 1.942 + return ALC_FALSE; 1.943 +} 1.944 + 1.945 +static void alsa_close_capture(ALCdevice *pDevice) 1.946 +{ 1.947 + alsa_data *data = (alsa_data*)pDevice->ExtraData; 1.948 + 1.949 + snd_pcm_close(data->pcmHandle); 1.950 + DestroyRingBuffer(data->ring); 1.951 + 1.952 + free(data->buffer); 1.953 + free(data); 1.954 + pDevice->ExtraData = NULL; 1.955 +} 1.956 + 1.957 +static void alsa_start_capture(ALCdevice *Device) 1.958 +{ 1.959 + alsa_data *data = (alsa_data*)Device->ExtraData; 1.960 + int err; 1.961 + 1.962 + err = snd_pcm_start(data->pcmHandle); 1.963 + if(err < 0) 1.964 + { 1.965 + ERR("start failed: %s\n", snd_strerror(err)); 1.966 + aluHandleDisconnect(Device); 1.967 + } 1.968 + else 1.969 + data->doCapture = AL_TRUE; 1.970 +} 1.971 + 1.972 +static void alsa_stop_capture(ALCdevice *Device) 1.973 +{ 1.974 + alsa_data *data = (alsa_data*)Device->ExtraData; 1.975 + snd_pcm_drain(data->pcmHandle); 1.976 + data->doCapture = AL_FALSE; 1.977 +} 1.978 + 1.979 +static ALCuint alsa_available_samples(ALCdevice *Device) 1.980 +{ 1.981 + alsa_data *data = (alsa_data*)Device->ExtraData; 1.982 + snd_pcm_sframes_t avail; 1.983 + 1.984 + avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0); 1.985 + if(avail < 0) 1.986 + { 1.987 + ERR("avail update failed: %s\n", snd_strerror(avail)); 1.988 + 1.989 + if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0) 1.990 + { 1.991 + if(data->doCapture) 1.992 + avail = snd_pcm_start(data->pcmHandle); 1.993 + if(avail >= 0) 1.994 + avail = snd_pcm_avail_update(data->pcmHandle); 1.995 + } 1.996 + if(avail < 0) 1.997 + { 1.998 + ERR("restore error: %s\n", snd_strerror(avail)); 1.999 + aluHandleDisconnect(Device); 1.1000 + } 1.1001 + } 1.1002 + while(avail > 0) 1.1003 + { 1.1004 + snd_pcm_sframes_t amt; 1.1005 + 1.1006 + amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); 1.1007 + if(avail < amt) amt = avail; 1.1008 + 1.1009 + amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt); 1.1010 + if(amt < 0) 1.1011 + { 1.1012 + ERR("read error: %s\n", snd_strerror(amt)); 1.1013 + 1.1014 + if(amt == -EAGAIN) 1.1015 + continue; 1.1016 + if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) 1.1017 + { 1.1018 + if(data->doCapture) 1.1019 + amt = snd_pcm_start(data->pcmHandle); 1.1020 + if(amt >= 0) 1.1021 + amt = snd_pcm_avail_update(data->pcmHandle); 1.1022 + } 1.1023 + if(amt < 0) 1.1024 + { 1.1025 + ERR("restore error: %s\n", snd_strerror(amt)); 1.1026 + aluHandleDisconnect(Device); 1.1027 + break; 1.1028 + } 1.1029 + avail = amt; 1.1030 + continue; 1.1031 + } 1.1032 + 1.1033 + WriteRingBuffer(data->ring, data->buffer, amt); 1.1034 + avail -= amt; 1.1035 + } 1.1036 + 1.1037 + return RingBufferSize(data->ring); 1.1038 +} 1.1039 + 1.1040 +static void alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) 1.1041 +{ 1.1042 + alsa_data *data = (alsa_data*)Device->ExtraData; 1.1043 + 1.1044 + if(Samples <= alsa_available_samples(Device)) 1.1045 + ReadRingBuffer(data->ring, Buffer, Samples); 1.1046 + else 1.1047 + alcSetError(Device, ALC_INVALID_VALUE); 1.1048 +} 1.1049 + 1.1050 + 1.1051 +static const BackendFuncs alsa_funcs = { 1.1052 + alsa_open_playback, 1.1053 + alsa_close_playback, 1.1054 + alsa_reset_playback, 1.1055 + alsa_stop_playback, 1.1056 + alsa_open_capture, 1.1057 + alsa_close_capture, 1.1058 + alsa_start_capture, 1.1059 + alsa_stop_capture, 1.1060 + alsa_capture_samples, 1.1061 + alsa_available_samples 1.1062 +}; 1.1063 + 1.1064 +ALCboolean alc_alsa_init(BackendFuncs *func_list) 1.1065 +{ 1.1066 + if(!alsa_load()) 1.1067 + return ALC_FALSE; 1.1068 + device_prefix = GetConfigValue("alsa", "device-prefix", "plughw:"); 1.1069 + capture_prefix = GetConfigValue("alsa", "capture-prefix", "plughw:"); 1.1070 + *func_list = alsa_funcs; 1.1071 + return ALC_TRUE; 1.1072 +} 1.1073 + 1.1074 +void alc_alsa_deinit(void) 1.1075 +{ 1.1076 + ALuint i; 1.1077 + 1.1078 + for(i = 0;i < numDevNames;++i) 1.1079 + { 1.1080 + free(allDevNameMap[i].name); 1.1081 + free(allDevNameMap[i].card); 1.1082 + } 1.1083 + free(allDevNameMap); 1.1084 + allDevNameMap = NULL; 1.1085 + numDevNames = 0; 1.1086 + 1.1087 + for(i = 0;i < numCaptureDevNames;++i) 1.1088 + { 1.1089 + free(allCaptureDevNameMap[i].name); 1.1090 + free(allCaptureDevNameMap[i].card); 1.1091 + } 1.1092 + free(allCaptureDevNameMap); 1.1093 + allCaptureDevNameMap = NULL; 1.1094 + numCaptureDevNames = 0; 1.1095 + 1.1096 +#ifdef HAVE_DYNLOAD 1.1097 + if(alsa_handle) 1.1098 + CloseLib(alsa_handle); 1.1099 + alsa_handle = NULL; 1.1100 +#endif 1.1101 +} 1.1102 + 1.1103 +void alc_alsa_probe(enum DevProbe type) 1.1104 +{ 1.1105 + ALuint i; 1.1106 + 1.1107 + switch(type) 1.1108 + { 1.1109 + case DEVICE_PROBE: 1.1110 + AppendDeviceList(alsaDevice); 1.1111 + break; 1.1112 + 1.1113 + case ALL_DEVICE_PROBE: 1.1114 + for(i = 0;i < numDevNames;++i) 1.1115 + { 1.1116 + free(allDevNameMap[i].name); 1.1117 + free(allDevNameMap[i].card); 1.1118 + } 1.1119 + 1.1120 + free(allDevNameMap); 1.1121 + allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames); 1.1122 + 1.1123 + for(i = 0;i < numDevNames;++i) 1.1124 + AppendAllDeviceList(allDevNameMap[i].name); 1.1125 + break; 1.1126 + 1.1127 + case CAPTURE_DEVICE_PROBE: 1.1128 + for(i = 0;i < numCaptureDevNames;++i) 1.1129 + { 1.1130 + free(allCaptureDevNameMap[i].name); 1.1131 + free(allCaptureDevNameMap[i].card); 1.1132 + } 1.1133 + 1.1134 + free(allCaptureDevNameMap); 1.1135 + allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); 1.1136 + 1.1137 + for(i = 0;i < numCaptureDevNames;++i) 1.1138 + AppendCaptureDeviceList(allCaptureDevNameMap[i].name); 1.1139 + break; 1.1140 + } 1.1141 +}