aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends/alsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/backends/alsa.c')
-rw-r--r--Alc/backends/alsa.c306
1 files changed, 195 insertions, 111 deletions
diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c
index 9a443c09..a967fff0 100644
--- a/Alc/backends/alsa.c
+++ b/Alc/backends/alsa.c
@@ -26,6 +26,8 @@
#include "alMain.h"
#include "alu.h"
+#include "alconfig.h"
+#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
@@ -199,15 +201,21 @@ static ALCboolean alsa_load(void)
#ifdef HAVE_DYNLOAD
if(!alsa_handle)
{
+ al_string missing_funcs = AL_STRING_INIT_STATIC();
+
alsa_handle = LoadLib("libasound.so.2");
if(!alsa_handle)
+ {
+ WARN("Failed to load %s\n", "libasound.so.2");
return ALC_FALSE;
+ }
error = ALC_FALSE;
#define LOAD_FUNC(f) do { \
p##f = GetSymbol(alsa_handle, #f); \
if(p##f == NULL) { \
error = ALC_TRUE; \
+ alstr_append_cstr(&missing_funcs, "\n" #f); \
} \
} while(0)
ALSA_FUNCS(LOAD_FUNC);
@@ -215,10 +223,11 @@ static ALCboolean alsa_load(void)
if(error)
{
+ WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs));
CloseLib(alsa_handle);
alsa_handle = NULL;
- return ALC_FALSE;
}
+ alstr_reset(&missing_funcs);
}
#endif
@@ -237,16 +246,13 @@ static vector_DevMap CaptureDevices;
static void clear_devlist(vector_DevMap *devlist)
{
- DevMap *iter, *end;
-
- iter = VECTOR_ITER_BEGIN(*devlist);
- end = VECTOR_ITER_END(*devlist);
- for(;iter != end;iter++)
- {
- AL_STRING_DEINIT(iter->name);
- AL_STRING_DEINIT(iter->device_name);
- }
- VECTOR_RESIZE(*devlist, 0);
+#define FREE_DEV(i) do { \
+ AL_STRING_DEINIT((i)->name); \
+ AL_STRING_DEINIT((i)->device_name); \
+} while(0)
+ VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV);
+ VECTOR_RESIZE(*devlist, 0, 0);
+#undef FREE_DEV
}
@@ -272,11 +278,45 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
- al_string_copy_cstr(&entry.name, alsaDevice);
- al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
- "device" : "capture", "default"));
+ alstr_copy_cstr(&entry.name, alsaDevice);
+ alstr_copy_cstr(&entry.device_name, GetConfigValue(
+ NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default"
+ ));
VECTOR_PUSH_BACK(*DeviceList, entry);
+ if(stream == SND_PCM_STREAM_PLAYBACK)
+ {
+ const char *customdevs, *sep, *next;
+ next = GetConfigValue(NULL, "alsa", "custom-devices", "");
+ while((customdevs=next) != NULL && customdevs[0])
+ {
+ next = strchr(customdevs, ';');
+ sep = strchr(customdevs, '=');
+ if(!sep)
+ {
+ al_string spec = AL_STRING_INIT_STATIC();
+ if(next)
+ alstr_copy_range(&spec, customdevs, next++);
+ else
+ alstr_copy_cstr(&spec, customdevs);
+ ERR("Invalid ALSA device specification \"%s\"\n", alstr_get_cstr(spec));
+ alstr_reset(&spec);
+ continue;
+ }
+
+ AL_STRING_INIT(entry.name);
+ AL_STRING_INIT(entry.device_name);
+ alstr_copy_range(&entry.name, customdevs, sep++);
+ if(next)
+ alstr_copy_range(&entry.device_name, sep, next++);
+ else
+ alstr_copy_cstr(&entry.device_name, sep);
+ TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name),
+ alstr_get_cstr(entry.device_name));
+ VECTOR_PUSH_BACK(*DeviceList, entry);
+ }
+ }
+
card = -1;
if((err=snd_card_next(&card)) < 0)
ERR("Failed to find a card: %s\n", snd_strerror(err));
@@ -321,7 +361,8 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
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 = snd_ctl_pcm_info(handle, pcminfo)) < 0)
+ {
if(err != -ENOENT)
ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
continue;
@@ -333,15 +374,15 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
ConfigValueStr(NULL, "alsa", name, &device_prefix);
snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
- cardname, devname, cardid, dev);
+ cardname, devname, cardid, dev);
snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
- device_prefix, cardid, dev);
+ device_prefix, cardid, dev);
TRACE("Got device \"%s\", \"%s\"\n", name, device);
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
- al_string_copy_cstr(&entry.name, name);
- al_string_copy_cstr(&entry.device_name, device);
+ alstr_copy_cstr(&entry.name, name);
+ alstr_copy_cstr(&entry.device_name, device);
VECTOR_PUSH_BACK(*DeviceList, entry);
}
snd_ctl_close(handle);
@@ -397,7 +438,7 @@ typedef struct ALCplaybackAlsa {
ALvoid *buffer;
ALsizei size;
- volatile int killNow;
+ ATOMIC(ALenum) killNow;
althrd_t thread;
} ALCplaybackAlsa;
@@ -405,15 +446,14 @@ static int ALCplaybackAlsa_mixerProc(void *ptr);
static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
+static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self);
static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
-static void ALCplaybackAlsa_close(ALCplaybackAlsa *self);
static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
static DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples)
-static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self);
+static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self);
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa)
@@ -425,6 +465,19 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self);
+
+ self->pcmHandle = NULL;
+ self->buffer = NULL;
+
+ ATOMIC_INIT(&self->killNow, AL_TRUE);
+}
+
+void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self)
+{
+ if(self->pcmHandle)
+ snd_pcm_close(self->pcmHandle);
+ self->pcmHandle = NULL;
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -444,14 +497,14 @@ static int ALCplaybackAlsa_mixerProc(void *ptr)
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
- while(!self->killNow)
+ while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
{
int state = verify_state(self->pcmHandle);
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
ALCplaybackAlsa_lock(self);
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state));
ALCplaybackAlsa_unlock(self);
break;
}
@@ -534,14 +587,14 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
- while(!self->killNow)
+ while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
{
int state = verify_state(self->pcmHandle);
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
ALCplaybackAlsa_lock(self);
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state));
ALCplaybackAlsa_unlock(self);
break;
}
@@ -588,7 +641,9 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
{
case -EAGAIN:
continue;
+#if ESTRPIPE != EPIPE
case -ESTRPIPE:
+#endif
case -EPIPE:
case -EINTR:
ret = snd_pcm_recover(self->pcmHandle, ret, 1);
@@ -630,12 +685,12 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
if(VECTOR_SIZE(PlaybackDevices) == 0)
probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
-#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0)
+#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
#undef MATCH_NAME
- if(iter == VECTOR_ITER_END(PlaybackDevices))
+ if(iter == VECTOR_END(PlaybackDevices))
return ALC_INVALID_VALUE;
- driver = al_string_get_cstr(iter->device_name);
+ driver = alstr_get_cstr(iter->device_name);
}
else
{
@@ -654,16 +709,11 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
- al_string_copy_cstr(&device->DeviceName, name);
+ alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
-static void ALCplaybackAlsa_close(ALCplaybackAlsa *self)
-{
- snd_pcm_close(self->pcmHandle);
-}
-
static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -677,6 +727,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
unsigned int rate;
const char *funcerr;
int allowmmap;
+ int dir;
int err;
switch(device->FmtType)
@@ -704,7 +755,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
break;
}
- allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1);
+ allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1);
periods = device->NumUpdates;
periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
bufferLen = periodLen * periods;
@@ -748,7 +799,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
}
CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
/* test and set channels (implicitly sets frame bits) */
- if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
+ if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0)
{
static const enum DevFmtChannels channellist[] = {
DevFmtStereo,
@@ -761,20 +812,24 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
for(k = 0;k < COUNTOF(channellist);k++)
{
- if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
+ if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0)
{
device->FmtChans = channellist[k];
+ device->AmbiOrder = 0;
break;
}
}
}
- CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
+ CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)));
/* set rate (implicitly constrains period/buffer parameters) */
- if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0))
+ if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) ||
+ !(device->Flags&DEVICE_FREQUENCY_REQUEST))
{
if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
ERR("Failed to disable ALSA resampler\n");
}
+ else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0)
+ ERR("Failed to enable ALSA resampler\n");
CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL));
/* set buffer time (implicitly constrains period/buffer parameters) */
if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0)
@@ -787,7 +842,9 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_access(hp, &access));
CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
- CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));
+ CHECK(snd_pcm_hw_params_get_periods(hp, &periods, &dir));
+ if(dir != 0)
+ WARN("Inexact period count: %u (%d)\n", periods, dir);
snd_pcm_hw_params_free(hp);
hp = NULL;
@@ -837,7 +894,7 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
- self->buffer = malloc(self->size);
+ self->buffer = al_malloc(16, self->size);
if(!self->buffer)
{
ERR("buffer malloc failed\n");
@@ -855,11 +912,11 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
}
thread_func = ALCplaybackAlsa_mixerProc;
}
- self->killNow = 0;
+ ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
if(althrd_create(&self->thread, thread_func, self) != althrd_success)
{
ERR("Could not create playback thread\n");
- free(self->buffer);
+ al_free(self->buffer);
self->buffer = NULL;
return ALC_FALSE;
}
@@ -876,28 +933,33 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
{
int res;
- if(self->killNow)
+ if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
return;
-
- self->killNow = 1;
althrd_join(self->thread, &res);
- free(self->buffer);
+ al_free(self->buffer);
self->buffer = NULL;
}
-static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self)
+static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_sframes_t delay = 0;
+ ClockLatency ret;
int err;
+ ALCplaybackAlsa_lock(self);
+ ret.ClockTime = GetDeviceClockTime(device);
if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0)
{
ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
- return 0;
+ delay = 0;
}
- return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
+ if(delay < 0) delay = 0;
+ ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency;
+ ALCplaybackAlsa_unlock(self);
+
+ return ret;
}
@@ -910,21 +972,20 @@ typedef struct ALCcaptureAlsa {
ALsizei size;
ALboolean doCapture;
- RingBuffer *ring;
+ ll_ringbuffer_t *ring;
snd_pcm_sframes_t last_avail;
} ALCcaptureAlsa;
static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
+static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self);
static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
-static void ALCcaptureAlsa_close(ALCcaptureAlsa *self);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self);
-static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self);
+static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa)
@@ -936,6 +997,25 @@ static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self);
+
+ self->pcmHandle = NULL;
+ self->buffer = NULL;
+ self->ring = NULL;
+}
+
+void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self)
+{
+ if(self->pcmHandle)
+ snd_pcm_close(self->pcmHandle);
+ self->pcmHandle = NULL;
+
+ al_free(self->buffer);
+ self->buffer = NULL;
+
+ ll_ringbuffer_free(self->ring);
+ self->ring = NULL;
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -958,12 +1038,12 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
if(VECTOR_SIZE(CaptureDevices) == 0)
probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
-#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0)
+#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
#undef MATCH_NAME
- if(iter == VECTOR_ITER_END(CaptureDevices))
+ if(iter == VECTOR_END(CaptureDevices))
return ALC_INVALID_VALUE;
- driver = al_string_get_cstr(iter->device_name);
+ driver = alstr_get_cstr(iter->device_name);
}
else
{
@@ -1020,7 +1100,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
/* set format (implicitly sets sample bits) */
CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
/* set channels (implicitly sets frame bits) */
- CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
+ CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)));
/* set rate (implicitly constrains period/buffer parameters) */
CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0));
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
@@ -1042,24 +1122,19 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
if(needring)
{
- self->ring = CreateRingBuffer(FrameSizeFromDevFmt(device->FmtChans, device->FmtType),
- device->UpdateSize*device->NumUpdates);
+ self->ring = ll_ringbuffer_create(
+ device->UpdateSize*device->NumUpdates,
+ FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder),
+ false
+ );
if(!self->ring)
{
ERR("ring buffer create failed\n");
goto error2;
}
-
- self->size = snd_pcm_frames_to_bytes(self->pcmHandle, periodSizeInFrames);
- self->buffer = malloc(self->size);
- if(!self->buffer)
- {
- ERR("buffer malloc failed\n");
- goto error2;
- }
}
- al_string_copy_cstr(&device->DeviceName, name);
+ alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
@@ -1068,31 +1143,29 @@ error:
if(hp) snd_pcm_hw_params_free(hp);
error2:
- free(self->buffer);
- self->buffer = NULL;
- DestroyRingBuffer(self->ring);
+ ll_ringbuffer_free(self->ring);
self->ring = NULL;
snd_pcm_close(self->pcmHandle);
+ self->pcmHandle = NULL;
return ALC_INVALID_VALUE;
}
-static void ALCcaptureAlsa_close(ALCcaptureAlsa *self)
-{
- snd_pcm_close(self->pcmHandle);
- DestroyRingBuffer(self->ring);
-
- free(self->buffer);
- self->buffer = NULL;
-}
-
static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
{
- int err = snd_pcm_start(self->pcmHandle);
+ int err = snd_pcm_prepare(self->pcmHandle);
+ if(err < 0)
+ ERR("prepare failed: %s\n", snd_strerror(err));
+ else
+ {
+ err = snd_pcm_start(self->pcmHandle);
+ if(err < 0)
+ ERR("start failed: %s\n", snd_strerror(err));
+ }
if(err < 0)
{
- ERR("start failed: %s\n", snd_strerror(err));
- aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
+ aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s",
+ snd_strerror(err));
return ALC_FALSE;
}
@@ -1117,11 +1190,11 @@ static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self)
void *ptr;
size = snd_pcm_frames_to_bytes(self->pcmHandle, avail);
- ptr = malloc(size);
+ ptr = al_malloc(16, size);
if(ptr)
{
ALCcaptureAlsa_captureSamples(self, ptr, avail);
- free(self->buffer);
+ al_free(self->buffer);
self->buffer = ptr;
self->size = size;
}
@@ -1138,12 +1211,12 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
if(self->ring)
{
- ReadRingBuffer(self->ring, buffer, samples);
+ ll_ringbuffer_read(self->ring, buffer, samples);
return ALC_NO_ERROR;
}
self->last_avail -= samples;
- while(device->Connected && samples > 0)
+ while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0)
{
snd_pcm_sframes_t amt = 0;
@@ -1163,7 +1236,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
}
else
{
- free(self->buffer);
+ al_free(self->buffer);
self->buffer = NULL;
self->size = 0;
}
@@ -1186,7 +1259,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
break;
}
/* If the amount available is less than what's asked, we lost it
@@ -1211,7 +1284,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_sframes_t avail = 0;
- if(device->Connected && self->doCapture)
+ if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture)
avail = snd_pcm_avail_update(self->pcmHandle);
if(avail < 0)
{
@@ -1227,7 +1300,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
if(avail < 0)
{
ERR("restore error: %s\n", snd_strerror(avail));
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail));
}
}
@@ -1241,12 +1314,15 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
while(avail > 0)
{
+ ll_ringbuffer_data_t vec[2];
snd_pcm_sframes_t amt;
- amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size);
- if(avail < amt) amt = avail;
+ ll_ringbuffer_get_write_vector(self->ring, vec);
+ if(vec[0].len == 0) break;
- amt = snd_pcm_readi(self->pcmHandle, self->buffer, amt);
+ amt = (vec[0].len < (snd_pcm_uframes_t)avail) ?
+ vec[0].len : (snd_pcm_uframes_t)avail;
+ amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt);
if(amt < 0)
{
ERR("read error: %s\n", snd_strerror(amt));
@@ -1263,39 +1339,41 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
- aluHandleDisconnect(device);
+ aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
break;
}
avail = amt;
continue;
}
- WriteRingBuffer(self->ring, self->buffer, amt);
+ ll_ringbuffer_write_advance(self->ring, amt);
avail -= amt;
}
- return RingBufferSize(self->ring);
+ return ll_ringbuffer_read_space(self->ring);
}
-static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self)
+static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_sframes_t delay = 0;
+ ClockLatency ret;
int err;
+ ALCcaptureAlsa_lock(self);
+ ret.ClockTime = GetDeviceClockTime(device);
if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0)
{
ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
- return 0;
+ delay = 0;
}
- return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
-}
+ if(delay < 0) delay = 0;
+ ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency;
+ ALCcaptureAlsa_unlock(self);
+ return ret;
+}
-static inline void AppendAllDevicesList2(const DevMap *entry)
-{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
-static inline void AppendCaptureDeviceList2(const DevMap *entry)
-{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
typedef struct ALCalsaBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
@@ -1334,19 +1412,25 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS
return ALC_FALSE;
}
-static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type)
+static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
{
switch(type)
{
+#define APPEND_OUTNAME(i) do { \
+ if(!alstr_empty((i)->name)) \
+ alstr_append_range(outnames, VECTOR_BEGIN((i)->name), \
+ VECTOR_END((i)->name)+1); \
+} while(0)
case ALL_DEVICE_PROBE:
probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
- VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME);
break;
case CAPTURE_DEVICE_PROBE:
probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
- VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME);
break;
+#undef APPEND_OUTNAME
}
}