aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/alsa.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2011-08-20 00:41:47 -0700
committerChris Robinson <[email protected]>2011-08-20 00:41:47 -0700
commit9989f33fc24042578bf4bf2c50a06a6366d07c1d (patch)
treecdf87e14c0333069c3ba791109c753c3ebf9784e /Alc/alsa.c
parentba4456d24aa013118e70fa1158def7ad18e8d66e (diff)
Move backend sources to a separate sub-directory
Diffstat (limited to 'Alc/alsa.c')
-rw-r--r--Alc/alsa.c1138
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;
- }
-}