diff options
author | Chris Robinson <[email protected]> | 2011-08-20 00:41:47 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2011-08-20 00:41:47 -0700 |
commit | 9989f33fc24042578bf4bf2c50a06a6366d07c1d (patch) | |
tree | cdf87e14c0333069c3ba791109c753c3ebf9784e /Alc/alsa.c | |
parent | ba4456d24aa013118e70fa1158def7ad18e8d66e (diff) |
Move backend sources to a separate sub-directory
Diffstat (limited to 'Alc/alsa.c')
-rw-r--r-- | Alc/alsa.c | 1138 |
1 files changed, 0 insertions, 1138 deletions
diff --git a/Alc/alsa.c b/Alc/alsa.c deleted file mode 100644 index ffed94a8..00000000 --- a/Alc/alsa.c +++ /dev/null @@ -1,1138 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <memory.h> - -#include "alMain.h" - -#include <alsa/asoundlib.h> - - -static const ALCchar alsaDevice[] = "ALSA Default"; - - -static void *alsa_handle; -#ifdef HAVE_DYNLOAD -#define MAKE_FUNC(f) static typeof(f) * p##f -MAKE_FUNC(snd_strerror); -MAKE_FUNC(snd_pcm_open); -MAKE_FUNC(snd_pcm_close); -MAKE_FUNC(snd_pcm_nonblock); -MAKE_FUNC(snd_pcm_frames_to_bytes); -MAKE_FUNC(snd_pcm_bytes_to_frames); -MAKE_FUNC(snd_pcm_hw_params_malloc); -MAKE_FUNC(snd_pcm_hw_params_free); -MAKE_FUNC(snd_pcm_hw_params_any); -MAKE_FUNC(snd_pcm_hw_params_set_access); -MAKE_FUNC(snd_pcm_hw_params_set_format); -MAKE_FUNC(snd_pcm_hw_params_set_channels); -MAKE_FUNC(snd_pcm_hw_params_set_periods_near); -MAKE_FUNC(snd_pcm_hw_params_set_rate_near); -MAKE_FUNC(snd_pcm_hw_params_set_rate); -MAKE_FUNC(snd_pcm_hw_params_set_rate_resample); -MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near); -MAKE_FUNC(snd_pcm_hw_params_set_period_time_near); -MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near); -MAKE_FUNC(snd_pcm_hw_params_set_period_size_near); -MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min); -MAKE_FUNC(snd_pcm_hw_params_get_buffer_size); -MAKE_FUNC(snd_pcm_hw_params_get_period_size); -MAKE_FUNC(snd_pcm_hw_params_get_access); -MAKE_FUNC(snd_pcm_hw_params_get_periods); -MAKE_FUNC(snd_pcm_hw_params); -MAKE_FUNC(snd_pcm_sw_params_malloc); -MAKE_FUNC(snd_pcm_sw_params_current); -MAKE_FUNC(snd_pcm_sw_params_set_avail_min); -MAKE_FUNC(snd_pcm_sw_params); -MAKE_FUNC(snd_pcm_sw_params_free); -MAKE_FUNC(snd_pcm_prepare); -MAKE_FUNC(snd_pcm_start); -MAKE_FUNC(snd_pcm_resume); -MAKE_FUNC(snd_pcm_wait); -MAKE_FUNC(snd_pcm_state); -MAKE_FUNC(snd_pcm_avail_update); -MAKE_FUNC(snd_pcm_areas_silence); -MAKE_FUNC(snd_pcm_mmap_begin); -MAKE_FUNC(snd_pcm_mmap_commit); -MAKE_FUNC(snd_pcm_readi); -MAKE_FUNC(snd_pcm_writei); -MAKE_FUNC(snd_pcm_drain); -MAKE_FUNC(snd_pcm_recover); -MAKE_FUNC(snd_pcm_info_malloc); -MAKE_FUNC(snd_pcm_info_free); -MAKE_FUNC(snd_pcm_info_set_device); -MAKE_FUNC(snd_pcm_info_set_subdevice); -MAKE_FUNC(snd_pcm_info_set_stream); -MAKE_FUNC(snd_pcm_info_get_name); -MAKE_FUNC(snd_ctl_pcm_next_device); -MAKE_FUNC(snd_ctl_pcm_info); -MAKE_FUNC(snd_ctl_open); -MAKE_FUNC(snd_ctl_close); -MAKE_FUNC(snd_ctl_card_info_malloc); -MAKE_FUNC(snd_ctl_card_info_free); -MAKE_FUNC(snd_ctl_card_info); -MAKE_FUNC(snd_ctl_card_info_get_name); -MAKE_FUNC(snd_ctl_card_info_get_id); -MAKE_FUNC(snd_card_next); -#undef MAKE_FUNC - -#define snd_strerror psnd_strerror -#define snd_pcm_open psnd_pcm_open -#define snd_pcm_close psnd_pcm_close -#define snd_pcm_nonblock psnd_pcm_nonblock -#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes -#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames -#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc -#define snd_pcm_hw_params_free psnd_pcm_hw_params_free -#define snd_pcm_hw_params_any psnd_pcm_hw_params_any -#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access -#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format -#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels -#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near -#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near -#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate -#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample -#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near -#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near -#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near -#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near -#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min -#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size -#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size -#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access -#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods -#define snd_pcm_hw_params psnd_pcm_hw_params -#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc -#define snd_pcm_sw_params_current psnd_pcm_sw_params_current -#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min -#define snd_pcm_sw_params psnd_pcm_sw_params -#define snd_pcm_sw_params_free psnd_pcm_sw_params_free -#define snd_pcm_prepare psnd_pcm_prepare -#define snd_pcm_start psnd_pcm_start -#define snd_pcm_resume psnd_pcm_resume -#define snd_pcm_wait psnd_pcm_wait -#define snd_pcm_state psnd_pcm_state -#define snd_pcm_avail_update psnd_pcm_avail_update -#define snd_pcm_areas_silence psnd_pcm_areas_silence -#define snd_pcm_mmap_begin psnd_pcm_mmap_begin -#define snd_pcm_mmap_commit psnd_pcm_mmap_commit -#define snd_pcm_readi psnd_pcm_readi -#define snd_pcm_writei psnd_pcm_writei -#define snd_pcm_drain psnd_pcm_drain -#define snd_pcm_recover psnd_pcm_recover -#define snd_pcm_info_malloc psnd_pcm_info_malloc -#define snd_pcm_info_free psnd_pcm_info_free -#define snd_pcm_info_set_device psnd_pcm_info_set_device -#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice -#define snd_pcm_info_set_stream psnd_pcm_info_set_stream -#define snd_pcm_info_get_name psnd_pcm_info_get_name -#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device -#define snd_ctl_pcm_info psnd_ctl_pcm_info -#define snd_ctl_open psnd_ctl_open -#define snd_ctl_close psnd_ctl_close -#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc -#define snd_ctl_card_info_free psnd_ctl_card_info_free -#define snd_ctl_card_info psnd_ctl_card_info -#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name -#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id -#define snd_card_next psnd_card_next -#endif - - -static ALCboolean alsa_load(void) -{ - if(!alsa_handle) - { -#ifdef HAVE_DYNLOAD - alsa_handle = LoadLib("libasound.so.2"); - if(!alsa_handle) - return ALC_FALSE; - -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(alsa_handle, #f); \ - if(p##f == NULL) { \ - CloseLib(alsa_handle); \ - alsa_handle = NULL; \ - return ALC_FALSE; \ - } \ -} while(0) - LOAD_FUNC(snd_strerror); - LOAD_FUNC(snd_pcm_open); - LOAD_FUNC(snd_pcm_close); - LOAD_FUNC(snd_pcm_nonblock); - LOAD_FUNC(snd_pcm_frames_to_bytes); - LOAD_FUNC(snd_pcm_bytes_to_frames); - LOAD_FUNC(snd_pcm_hw_params_malloc); - LOAD_FUNC(snd_pcm_hw_params_free); - LOAD_FUNC(snd_pcm_hw_params_any); - LOAD_FUNC(snd_pcm_hw_params_set_access); - LOAD_FUNC(snd_pcm_hw_params_set_format); - LOAD_FUNC(snd_pcm_hw_params_set_channels); - LOAD_FUNC(snd_pcm_hw_params_set_periods_near); - LOAD_FUNC(snd_pcm_hw_params_set_rate_near); - LOAD_FUNC(snd_pcm_hw_params_set_rate); - LOAD_FUNC(snd_pcm_hw_params_set_rate_resample); - LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near); - LOAD_FUNC(snd_pcm_hw_params_set_period_time_near); - LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); - LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); - LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); - LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); - LOAD_FUNC(snd_pcm_hw_params_get_period_size); - LOAD_FUNC(snd_pcm_hw_params_get_access); - LOAD_FUNC(snd_pcm_hw_params_get_periods); - LOAD_FUNC(snd_pcm_hw_params); - LOAD_FUNC(snd_pcm_sw_params_malloc); - LOAD_FUNC(snd_pcm_sw_params_current); - LOAD_FUNC(snd_pcm_sw_params_set_avail_min); - LOAD_FUNC(snd_pcm_sw_params); - LOAD_FUNC(snd_pcm_sw_params_free); - LOAD_FUNC(snd_pcm_prepare); - LOAD_FUNC(snd_pcm_start); - LOAD_FUNC(snd_pcm_resume); - LOAD_FUNC(snd_pcm_wait); - LOAD_FUNC(snd_pcm_state); - LOAD_FUNC(snd_pcm_avail_update); - LOAD_FUNC(snd_pcm_areas_silence); - LOAD_FUNC(snd_pcm_mmap_begin); - LOAD_FUNC(snd_pcm_mmap_commit); - LOAD_FUNC(snd_pcm_readi); - LOAD_FUNC(snd_pcm_writei); - LOAD_FUNC(snd_pcm_drain); - LOAD_FUNC(snd_pcm_recover); - LOAD_FUNC(snd_pcm_info_malloc); - LOAD_FUNC(snd_pcm_info_free); - LOAD_FUNC(snd_pcm_info_set_device); - LOAD_FUNC(snd_pcm_info_set_subdevice); - LOAD_FUNC(snd_pcm_info_set_stream); - LOAD_FUNC(snd_pcm_info_get_name); - LOAD_FUNC(snd_ctl_pcm_next_device); - LOAD_FUNC(snd_ctl_pcm_info); - LOAD_FUNC(snd_ctl_open); - LOAD_FUNC(snd_ctl_close); - LOAD_FUNC(snd_ctl_card_info_malloc); - LOAD_FUNC(snd_ctl_card_info_free); - LOAD_FUNC(snd_ctl_card_info); - LOAD_FUNC(snd_ctl_card_info_get_name); - LOAD_FUNC(snd_ctl_card_info_get_id); - LOAD_FUNC(snd_card_next); -#undef LOAD_FUNC -#else - alsa_handle = (void*)0xDEADBEEF; -#endif - } - return ALC_TRUE; -} - - -typedef struct { - snd_pcm_t *pcmHandle; - - ALvoid *buffer; - ALsizei size; - - ALboolean doCapture; - RingBuffer *ring; - - volatile int killNow; - ALvoid *thread; -} alsa_data; - -typedef struct { - ALCchar *name; - char *card; - int dev; -} DevMap; - -static DevMap *allDevNameMap; -static ALuint numDevNames; -static DevMap *allCaptureDevNameMap; -static ALuint numCaptureDevNames; - -static const char *device_prefix; -static const char *capture_prefix; - - -static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count) -{ - snd_ctl_t *handle; - int card, err, dev, idx; - snd_ctl_card_info_t *info; - snd_pcm_info_t *pcminfo; - DevMap *DevList; - char name[1024]; - - snd_ctl_card_info_malloc(&info); - snd_pcm_info_malloc(&pcminfo); - - card = -1; - if((err=snd_card_next(&card)) < 0) - ERR("Failed to find a card: %s\n", snd_strerror(err)); - - DevList = malloc(sizeof(DevMap) * 1); - DevList[0].name = strdup("ALSA Default"); - DevList[0].card = NULL; - DevList[0].dev = 0; - idx = 1; - while(card >= 0) - { - sprintf(name, "hw:%d", card); - if((err = snd_ctl_open(&handle, name, 0)) < 0) - { - ERR("control open (%i): %s\n", card, snd_strerror(err)); - goto next_card; - } - if((err = snd_ctl_card_info(handle, info)) < 0) - { - ERR("control hardware info (%i): %s\n", card, snd_strerror(err)); - snd_ctl_close(handle); - goto next_card; - } - - dev = -1; - while(1) - { - const char *cname, *dname, *cid; - void *temp; - - if(snd_ctl_pcm_next_device(handle, &dev) < 0) - ERR("snd_ctl_pcm_next_device failed\n"); - if(dev < 0) - break; - - snd_pcm_info_set_device(pcminfo, dev); - snd_pcm_info_set_subdevice(pcminfo, 0); - snd_pcm_info_set_stream(pcminfo, stream); - if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) { - if(err != -ENOENT) - ERR("control digital audio info (%i): %s\n", card, snd_strerror(err)); - continue; - } - - temp = realloc(DevList, sizeof(DevMap) * (idx+1)); - if(temp) - { - DevList = temp; - cname = snd_ctl_card_info_get_name(info); - dname = snd_pcm_info_get_name(pcminfo); - cid = snd_ctl_card_info_get_id(info); - snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", - cname, dname, cid, dev); - DevList[idx].name = strdup(name); - DevList[idx].card = strdup(cid); - DevList[idx].dev = dev; - idx++; - } - } - snd_ctl_close(handle); - next_card: - if(snd_card_next(&card) < 0) { - ERR("snd_card_next failed\n"); - break; - } - } - - snd_pcm_info_free(pcminfo); - snd_ctl_card_info_free(info); - - *count = idx; - return DevList; -} - - -static int xrun_recovery(snd_pcm_t *handle, int err) -{ - err = snd_pcm_recover(handle, err, 1); - if(err < 0) - ERR("recover failed: %s\n", snd_strerror(err)); - return err; -} - -static int verify_state(snd_pcm_t *handle) -{ - snd_pcm_state_t state = snd_pcm_state(handle); - if(state == SND_PCM_STATE_DISCONNECTED) - return -ENODEV; - if(state == SND_PCM_STATE_XRUN) - { - int err = xrun_recovery(handle, -EPIPE); - if(err < 0) return err; - } - else if(state == SND_PCM_STATE_SUSPENDED) - { - int err = xrun_recovery(handle, -ESTRPIPE); - if(err < 0) return err; - } - - return state; -} - - -static ALuint ALSAProc(ALvoid *ptr) -{ - ALCdevice *pDevice = (ALCdevice*)ptr; - alsa_data *data = (alsa_data*)pDevice->ExtraData; - const snd_pcm_channel_area_t *areas = NULL; - snd_pcm_sframes_t avail, commitres; - snd_pcm_uframes_t offset, frames; - char *WritePtr; - int err; - - SetRTPriority(); - - while(!data->killNow) - { - int state = verify_state(data->pcmHandle); - if(state < 0) - { - ERR("Invalid state detected: %s\n", snd_strerror(state)); - aluHandleDisconnect(pDevice); - break; - } - - avail = snd_pcm_avail_update(data->pcmHandle); - if(avail < 0) - { - ERR("available update failed: %s\n", snd_strerror(avail)); - continue; - } - - // make sure there's frames to process - if((snd_pcm_uframes_t)avail < pDevice->UpdateSize) - { - if(state != SND_PCM_STATE_RUNNING) - { - err = snd_pcm_start(data->pcmHandle); - if(err < 0) - { - ERR("start failed: %s\n", snd_strerror(err)); - continue; - } - } - if(snd_pcm_wait(data->pcmHandle, 1000) == 0) - ERR("Wait timeout... buffer size too low?\n"); - continue; - } - avail -= avail%pDevice->UpdateSize; - - // it is possible that contiguous areas are smaller, thus we use a loop - while(avail > 0) - { - frames = avail; - - err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames); - if(err < 0) - { - ERR("mmap begin error: %s\n", snd_strerror(err)); - break; - } - - WritePtr = (char*)areas->addr + (offset * areas->step / 8); - aluMixData(pDevice, WritePtr, frames); - - commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames); - if(commitres < 0 || (commitres-frames) != 0) - { - ERR("mmap commit error: %s\n", - snd_strerror(commitres >= 0 ? -EPIPE : commitres)); - break; - } - - avail -= frames; - } - } - - return 0; -} - -static ALuint ALSANoMMapProc(ALvoid *ptr) -{ - ALCdevice *pDevice = (ALCdevice*)ptr; - alsa_data *data = (alsa_data*)pDevice->ExtraData; - snd_pcm_sframes_t avail; - char *WritePtr; - - SetRTPriority(); - - while(!data->killNow) - { - int state = verify_state(data->pcmHandle); - if(state < 0) - { - ERR("Invalid state detected: %s\n", snd_strerror(state)); - aluHandleDisconnect(pDevice); - break; - } - - WritePtr = data->buffer; - avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1); - aluMixData(pDevice, WritePtr, avail); - - while(avail > 0) - { - int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail); - switch (ret) - { - case -EAGAIN: - continue; - case -ESTRPIPE: - case -EPIPE: - case -EINTR: - ret = snd_pcm_recover(data->pcmHandle, ret, 1); - if(ret < 0) - avail = 0; - break; - default: - if (ret >= 0) - { - WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret); - avail -= ret; - } - break; - } - if (ret < 0) - { - ret = snd_pcm_prepare(data->pcmHandle); - if(ret < 0) - break; - } - } - } - - return 0; -} - -static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName) -{ - alsa_data *data; - char driver[128]; - int i; - - strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1); - driver[sizeof(driver)-1] = 0; - - if(!deviceName) - deviceName = alsaDevice; - else if(strcmp(deviceName, alsaDevice) != 0) - { - size_t idx; - - if(!allDevNameMap) - allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames); - - for(idx = 0;idx < numDevNames;idx++) - { - if(allDevNameMap[idx].name && - strcmp(deviceName, allDevNameMap[idx].name) == 0) - { - if(idx > 0) - snprintf(driver, sizeof(driver), "%sCARD=%s,DEV=%d", device_prefix, - allDevNameMap[idx].card, allDevNameMap[idx].dev); - break; - } - } - if(idx == numDevNames) - return ALC_FALSE; - } - - data = (alsa_data*)calloc(1, sizeof(alsa_data)); - - i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - if(i >= 0) - { - i = snd_pcm_nonblock(data->pcmHandle, 0); - if(i < 0) - snd_pcm_close(data->pcmHandle); - } - if(i < 0) - { - free(data); - ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(i)); - return ALC_FALSE; - } - - device->szDeviceName = strdup(deviceName); - device->ExtraData = data; - return ALC_TRUE; -} - -static void alsa_close_playback(ALCdevice *device) -{ - alsa_data *data = (alsa_data*)device->ExtraData; - - snd_pcm_close(data->pcmHandle); - free(data); - device->ExtraData = NULL; -} - -static ALCboolean alsa_reset_playback(ALCdevice *device) -{ - alsa_data *data = (alsa_data*)device->ExtraData; - snd_pcm_uframes_t periodSizeInFrames; - unsigned int periodLen, bufferLen; - snd_pcm_sw_params_t *sp = NULL; - snd_pcm_hw_params_t *p = NULL; - snd_pcm_access_t access; - snd_pcm_format_t format; - unsigned int periods; - unsigned int rate; - int allowmmap; - char *err; - int i; - - - format = -1; - switch(device->FmtType) - { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; - } - - allowmmap = GetConfigValueBool("alsa", "mmap", 1); - periods = device->NumUpdates; - periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; - bufferLen = periodLen * periods; - rate = device->Frequency; - - err = NULL; - snd_pcm_hw_params_malloc(&p); - - if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0) - err = "any"; - /* set interleaved access */ - if(i >= 0 && (!allowmmap || (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)) - { - if(periods > 2) - { - periods--; - bufferLen = periodLen * periods; - } - if((i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) - err = "set access"; - } - /* set format (implicitly sets sample bits) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) - { - device->FmtType = DevFmtFloat; - if(format == SND_PCM_FORMAT_FLOAT || - (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0) - { - device->FmtType = DevFmtShort; - if(format == SND_PCM_FORMAT_S16 || - (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0) - { - device->FmtType = DevFmtUByte; - if(format == SND_PCM_FORMAT_U8 || - (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0) - err = "set format"; - } - } - } - /* set channels (implicitly sets frame bits) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0) - { - if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0) - { - if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0) - err = "set channels"; - else - { - if((device->Flags&DEVICE_CHANNELS_REQUEST)) - ERR("Failed to set %s, got Mono instead\n", DevFmtChannelsString(device->FmtChans)); - device->FmtChans = DevFmtMono; - } - } - else - { - if((device->Flags&DEVICE_CHANNELS_REQUEST)) - ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(device->FmtChans)); - device->FmtChans = DevFmtStereo; - } - device->Flags &= ~DEVICE_CHANNELS_REQUEST; - } - if(i >= 0 && (i=snd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0) - { - ERR("Failed to disable ALSA resampler\n"); - i = 0; - } - /* set rate (implicitly constrains period/buffer parameters) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0) - err = "set rate near"; - /* set buffer time (implicitly constrains period/buffer parameters) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0) - err = "set buffer time near"; - /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0) - err = "set period time near"; - /* install and prepare hardware configuration */ - if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0) - err = "set params"; - if(i >= 0 && (i=snd_pcm_hw_params_get_access(p, &access)) < 0) - err = "get access"; - if(i >= 0 && (i=snd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0) - err = "get period size"; - if(i >= 0 && (i=snd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0) - err = "get periods"; - if(i < 0) - { - ERR("%s failed: %s\n", err, snd_strerror(i)); - snd_pcm_hw_params_free(p); - return ALC_FALSE; - } - - snd_pcm_hw_params_free(p); - - err = NULL; - snd_pcm_sw_params_malloc(&sp); - - if((i=snd_pcm_sw_params_current(data->pcmHandle, sp)) != 0) - err = "sw current"; - if(i == 0 && (i=snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0) - err = "sw set avail min"; - if(i == 0 && (i=snd_pcm_sw_params(data->pcmHandle, sp)) != 0) - err = "sw set params"; - if(i != 0) - { - ERR("%s failed: %s\n", err, snd_strerror(i)); - snd_pcm_sw_params_free(sp); - return ALC_FALSE; - } - - snd_pcm_sw_params_free(sp); - - if(device->Frequency != rate) - { - if((device->Flags&DEVICE_FREQUENCY_REQUEST)) - ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, rate); - device->Flags &= ~DEVICE_FREQUENCY_REQUEST; - device->Frequency = rate; - } - - SetDefaultChannelOrder(device); - - data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); - if(access == SND_PCM_ACCESS_RW_INTERLEAVED) - { - /* Increase periods by one, since the temp buffer counts as an extra - * period */ - periods++; - data->buffer = malloc(data->size); - if(!data->buffer) - { - ERR("buffer malloc failed\n"); - return ALC_FALSE; - } - device->UpdateSize = periodSizeInFrames; - device->NumUpdates = periods; - data->thread = StartThread(ALSANoMMapProc, device); - } - else - { - i = snd_pcm_prepare(data->pcmHandle); - if(i < 0) - { - ERR("prepare error: %s\n", snd_strerror(i)); - return ALC_FALSE; - } - device->UpdateSize = periodSizeInFrames; - device->NumUpdates = periods; - data->thread = StartThread(ALSAProc, device); - } - if(data->thread == NULL) - { - ERR("Could not create playback thread\n"); - free(data->buffer); - data->buffer = NULL; - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void alsa_stop_playback(ALCdevice *device) -{ - alsa_data *data = (alsa_data*)device->ExtraData; - - if(data->thread) - { - data->killNow = 1; - StopThread(data->thread); - data->thread = NULL; - } - data->killNow = 0; - free(data->buffer); - data->buffer = NULL; -} - - -static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName) -{ - snd_pcm_hw_params_t *p; - snd_pcm_uframes_t bufferSizeInFrames; - snd_pcm_format_t format; - ALuint frameSize; - alsa_data *data; - char driver[128]; - char *err; - int i; - - strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); - driver[sizeof(driver)-1] = 0; - - if(!allCaptureDevNameMap) - allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); - - if(!deviceName) - deviceName = allCaptureDevNameMap[0].name; - else - { - size_t idx; - - for(idx = 0;idx < numCaptureDevNames;idx++) - { - if(allCaptureDevNameMap[idx].name && - strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) - { - if(idx > 0) - snprintf(driver, sizeof(driver), "%sCARD=%s,DEV=%d", capture_prefix, - allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev); - break; - } - } - if(idx == numCaptureDevNames) - return ALC_FALSE; - } - - data = (alsa_data*)calloc(1, sizeof(alsa_data)); - - i = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - if(i < 0) - { - ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(i)); - free(data); - return ALC_FALSE; - } - - format = -1; - switch(pDevice->FmtType) - { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; - } - - err = NULL; - bufferSizeInFrames = pDevice->UpdateSize * pDevice->NumUpdates; - snd_pcm_hw_params_malloc(&p); - - if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0) - err = "any"; - /* set interleaved access */ - if(i >= 0 && (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) - err = "set access"; - /* set format (implicitly sets sample bits) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0) - err = "set format"; - /* set channels (implicitly sets frame bits) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0) - err = "set channels"; - /* set rate (implicitly constrains period/buffer parameters) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0) - err = "set rate near"; - /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0) - err = "set buffer size near"; - /* install and prepare hardware configuration */ - if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0) - err = "set params"; - if(i < 0) - { - ERR("%s failed: %s\n", err, snd_strerror(i)); - snd_pcm_hw_params_free(p); - goto error; - } - - if((i=snd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0) - { - ERR("get size failed: %s\n", snd_strerror(i)); - snd_pcm_hw_params_free(p); - goto error; - } - - snd_pcm_hw_params_free(p); - - frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); - - data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates); - if(!data->ring) - { - ERR("ring buffer create failed\n"); - goto error; - } - - data->size = snd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames); - data->buffer = malloc(data->size); - if(!data->buffer) - { - ERR("buffer malloc failed\n"); - goto error; - } - - pDevice->szDeviceName = strdup(deviceName); - - pDevice->ExtraData = data; - return ALC_TRUE; - -error: - free(data->buffer); - DestroyRingBuffer(data->ring); - snd_pcm_close(data->pcmHandle); - free(data); - - pDevice->ExtraData = NULL; - return ALC_FALSE; -} - -static void alsa_close_capture(ALCdevice *pDevice) -{ - alsa_data *data = (alsa_data*)pDevice->ExtraData; - - snd_pcm_close(data->pcmHandle); - DestroyRingBuffer(data->ring); - - free(data->buffer); - free(data); - pDevice->ExtraData = NULL; -} - -static void alsa_start_capture(ALCdevice *Device) -{ - alsa_data *data = (alsa_data*)Device->ExtraData; - int err; - - err = snd_pcm_start(data->pcmHandle); - if(err < 0) - { - ERR("start failed: %s\n", snd_strerror(err)); - aluHandleDisconnect(Device); - } - else - data->doCapture = AL_TRUE; -} - -static void alsa_stop_capture(ALCdevice *Device) -{ - alsa_data *data = (alsa_data*)Device->ExtraData; - snd_pcm_drain(data->pcmHandle); - data->doCapture = AL_FALSE; -} - -static ALCuint alsa_available_samples(ALCdevice *Device) -{ - alsa_data *data = (alsa_data*)Device->ExtraData; - snd_pcm_sframes_t avail; - - avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0); - if(avail < 0) - { - ERR("avail update failed: %s\n", snd_strerror(avail)); - - if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0) - { - if(data->doCapture) - avail = snd_pcm_start(data->pcmHandle); - if(avail >= 0) - avail = snd_pcm_avail_update(data->pcmHandle); - } - if(avail < 0) - { - ERR("restore error: %s\n", snd_strerror(avail)); - aluHandleDisconnect(Device); - } - } - while(avail > 0) - { - snd_pcm_sframes_t amt; - - amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); - if(avail < amt) amt = avail; - - amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt); - if(amt < 0) - { - ERR("read error: %s\n", snd_strerror(amt)); - - if(amt == -EAGAIN) - continue; - if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) - { - if(data->doCapture) - amt = snd_pcm_start(data->pcmHandle); - if(amt >= 0) - amt = snd_pcm_avail_update(data->pcmHandle); - } - if(amt < 0) - { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(Device); - break; - } - avail = amt; - continue; - } - - WriteRingBuffer(data->ring, data->buffer, amt); - avail -= amt; - } - - return RingBufferSize(data->ring); -} - -static void alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) -{ - alsa_data *data = (alsa_data*)Device->ExtraData; - - if(Samples <= alsa_available_samples(Device)) - ReadRingBuffer(data->ring, Buffer, Samples); - else - alcSetError(Device, ALC_INVALID_VALUE); -} - - -static const BackendFuncs alsa_funcs = { - alsa_open_playback, - alsa_close_playback, - alsa_reset_playback, - alsa_stop_playback, - alsa_open_capture, - alsa_close_capture, - alsa_start_capture, - alsa_stop_capture, - alsa_capture_samples, - alsa_available_samples -}; - -ALCboolean alc_alsa_init(BackendFuncs *func_list) -{ - if(!alsa_load()) - return ALC_FALSE; - device_prefix = GetConfigValue("alsa", "device-prefix", "plughw:"); - capture_prefix = GetConfigValue("alsa", "capture-prefix", "plughw:"); - *func_list = alsa_funcs; - return ALC_TRUE; -} - -void alc_alsa_deinit(void) -{ - ALuint i; - - for(i = 0;i < numDevNames;++i) - { - free(allDevNameMap[i].name); - free(allDevNameMap[i].card); - } - free(allDevNameMap); - allDevNameMap = NULL; - numDevNames = 0; - - for(i = 0;i < numCaptureDevNames;++i) - { - free(allCaptureDevNameMap[i].name); - free(allCaptureDevNameMap[i].card); - } - free(allCaptureDevNameMap); - allCaptureDevNameMap = NULL; - numCaptureDevNames = 0; - -#ifdef HAVE_DYNLOAD - if(alsa_handle) - CloseLib(alsa_handle); - alsa_handle = NULL; -#endif -} - -void alc_alsa_probe(enum DevProbe type) -{ - ALuint i; - - switch(type) - { - case DEVICE_PROBE: - AppendDeviceList(alsaDevice); - break; - - case ALL_DEVICE_PROBE: - for(i = 0;i < numDevNames;++i) - { - free(allDevNameMap[i].name); - free(allDevNameMap[i].card); - } - - free(allDevNameMap); - allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames); - - for(i = 0;i < numDevNames;++i) - AppendAllDeviceList(allDevNameMap[i].name); - break; - - case CAPTURE_DEVICE_PROBE: - for(i = 0;i < numCaptureDevNames;++i) - { - free(allCaptureDevNameMap[i].name); - free(allCaptureDevNameMap[i].card); - } - - free(allCaptureDevNameMap); - allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); - - for(i = 0;i < numCaptureDevNames;++i) - AppendCaptureDeviceList(allCaptureDevNameMap[i].name); - break; - } -} |