#include <sys/poll.h>
+#include <pthread.h>
+
#include <alsa/asoundlib.h>
#include <alsa/control_external.h>
int subscribed;
int updated;
+
+ pthread_mutex_t mutex;
} snd_ctl_polyp_t;
#define SOURCE_VOL_NAME "Capture Volume"
assert(ctl);
+ pthread_mutex_lock(&ctl->mutex);
+
if (ctl->source)
count += 2;
if (ctl->sink)
count += 2;
+ pthread_mutex_unlock(&ctl->mutex);
+
return count;
}
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ pthread_mutex_lock(&ctl->mutex);
+
if (ctl->source) {
if (offset == 0)
snd_ctl_elem_id_set_name(id, SOURCE_VOL_NAME);
} else
offset += 2;
+ pthread_mutex_unlock(&ctl->mutex);
+
if (offset == 2)
snd_ctl_elem_id_set_name(id, SINK_VOL_NAME);
else if (offset == 3)
int *type, unsigned int *acc, unsigned int *count)
{
snd_ctl_polyp_t *ctl = ext->private_data;
- int err;
+ int err = 0;
- assert(ctl && ctl->p);
+ assert(ctl);
if (key > 3)
return -EINVAL;
+ pthread_mutex_lock(&ctl->mutex);
+
+ assert(ctl->p);
+
err = polyp_finish_poll(ctl->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(ctl->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_update_volume(ctl);
if (err < 0)
- return err;
+ goto finish;
if (key & 1)
*type = SND_CTL_ELEM_TYPE_BOOLEAN;
else
*count = 1;
- return 0;
+finish:
+ pthread_mutex_unlock(&ctl->mutex);
+
+ return err;
}
static int polyp_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
long *value)
{
snd_ctl_polyp_t *ctl = ext->private_data;
- int err, i;
+ int err = 0, i;
pa_cvolume *vol = NULL;
- assert(ctl && ctl->p);
+ assert(ctl);
+
+ pthread_mutex_lock(&ctl->mutex);
+
+ assert(ctl->p);
err = polyp_finish_poll(ctl->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(ctl->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_update_volume(ctl);
if (err < 0)
- return err;
+ goto finish;
switch (key) {
case 0:
*value = !ctl->sink_muted;
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto finish;
}
if (vol) {
value[i] = vol->values[i];
}
- return 0;
+finish:
+ pthread_mutex_unlock(&ctl->mutex);
+
+ return err;
}
static int polyp_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
long *value)
{
snd_ctl_polyp_t *ctl = ext->private_data;
- int err, i;
+ int err = 0, i;
pa_operation *o;
pa_cvolume *vol = NULL;
- assert(ctl && ctl->p && ctl->p->context);
+ assert(ctl);
+
+ pthread_mutex_lock(&ctl->mutex);
+
+ assert(ctl->p && ctl->p->context);
err = polyp_finish_poll(ctl->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(ctl->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_update_volume(ctl);
if (err < 0)
- return err;
+ goto finish;
switch (key) {
case 0:
break;
case 1:
if (!!ctl->source_muted == !*value)
- return 0;
+ goto finish;
ctl->source_muted = !*value;
break;
case 2:
break;
case 3:
if (!!ctl->sink_muted == !*value)
- return 0;
+ goto finish;
ctl->sink_muted = !*value;
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto finish;
}
if (vol) {
break;
if (i == vol->channels)
- return 0;
+ goto finish;
for (i = 0;i < vol->channels;i++)
vol->values[i] = value[i];
err = polyp_wait_operation(ctl->p, o);
pa_operation_unref(o);
if (err < 0)
- return err;
+ goto finish;
+
+ err = 1;
- return 1;
+finish:
+ pthread_mutex_unlock(&ctl->mutex);
+
+ return err;
}
static void polyp_subscribe_events(snd_ctl_ext_t *ext, int subscribe)
assert(ctl);
+ pthread_mutex_lock(&ctl->mutex);
+
ctl->subscribed = !!(subscribe & SND_CTL_EVENT_MASK_VALUE);
+
+ pthread_mutex_unlock(&ctl->mutex);
}
static int polyp_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
{
snd_ctl_polyp_t *ctl = ext->private_data;
int offset;
+ int err = -EAGAIN;
assert(ctl);
+ pthread_mutex_lock(&ctl->mutex);
+
if (!ctl->updated || !ctl->subscribed)
- return -EAGAIN;
+ goto finish;
if (ctl->source)
offset = 2;
*event_mask = SND_CTL_EVENT_MASK_VALUE;
- return 1;
+ err = 0;
+
+finish:
+ pthread_mutex_unlock(&ctl->mutex);
+
+ return err;
}
static int polyp_ctl_poll_descriptors_count(snd_ctl_ext_t *ext)
{
snd_ctl_polyp_t *ctl = ext->private_data;
+ int count;
+
+ assert(ctl);
+
+ pthread_mutex_lock(&ctl->mutex);
+
+ assert(ctl->p);
+
+ count = polyp_poll_descriptors_count(ctl->p);
- assert(ctl && ctl->p);
+ pthread_mutex_unlock(&ctl->mutex);
- return polyp_poll_descriptors_count(ctl->p);
+ return count;
}
static int polyp_ctl_poll_descriptors(snd_ctl_ext_t *ext, struct pollfd *pfd, unsigned int space)
snd_ctl_polyp_t *ctl = ext->private_data;
- assert(ctl && ctl->p);
+ assert(ctl);
+
+ pthread_mutex_lock(&ctl->mutex);
+
+ assert(ctl->p);
num = polyp_poll_descriptors(ctl->p, pfd, space);
if (num < 0)
- return num;
+ goto finish;
if (ctl->updated)
pa_mainloop_wakeup(ctl->p->mainloop);
+finish:
+ pthread_mutex_unlock(&ctl->mutex);
+
return num;
}
static int polyp_ctl_poll_revents(snd_ctl_ext_t *ext, struct pollfd *pfd, unsigned int nfds, unsigned short *revents)
{
snd_ctl_polyp_t *ctl = ext->private_data;
- int err;
+ int err = 0;
+
+ assert(ctl);
+
+ pthread_mutex_lock(&ctl->mutex);
- assert(ctl && ctl->p);
+ assert(ctl->p);
err = polyp_poll_revents(ctl->p, pfd, nfds, revents);
if (err < 0)
- return err;
+ goto finish;
*revents = 0;
if (ctl->updated)
*revents |= POLLIN;
- return 0;
+finish:
+ pthread_mutex_unlock(&ctl->mutex);
+
+ return err;
}
static void polyp_close(snd_ctl_ext_t *ext)
if (ctl->sink)
free(ctl->sink);
+ pthread_mutex_destroy(&ctl->mutex);
+
free(ctl);
}
int err;
snd_ctl_polyp_t *ctl;
pa_operation *o;
+ pthread_mutexattr_t mutexattr;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
if (err < 0)
goto error;
+ pthread_mutexattr_init(&mutexattr);
+ pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&ctl->mutex, &mutexattr);
+ pthread_mutexattr_destroy(&mutexattr);
+
if (source)
ctl->source = strdup(source);
else if (device)
#include <stdio.h>
#include <sys/poll.h>
+#include <pthread.h>
+
#include <alsa/asoundlib.h>
#include <alsa/pcm_external.h>
pa_sample_spec ss;
unsigned int frame_size;
pa_buffer_attr buffer_attr;
+
+ pthread_mutex_t mutex;
} snd_pcm_polyp_t;
static void update_ptr(snd_pcm_polyp_t *pcm)
{
snd_pcm_polyp_t *pcm = io->private_data;
pa_operation *o;
- int err;
+ int err = 0;
- assert(pcm && pcm->p && pcm->stream);
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p && pcm->stream);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
o = pa_stream_cork(pcm->stream, 0, NULL, NULL);
assert(o);
pa_operation_unref(o);
- if (err < 0)
- return -EIO;
+ if (err < 0) {
+ err = -EIO;
+ goto finish;
+ }
- return 0;
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static int polyp_stop(snd_pcm_ioplug_t *io)
{
snd_pcm_polyp_t *pcm = io->private_data;
pa_operation *o;
- int err;
+ int err = 0;
+
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
- assert(pcm && pcm->p && pcm->stream);
+ assert(pcm->p && pcm->stream);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
o = pa_stream_flush(pcm->stream, NULL, NULL);
assert(o);
pa_operation_unref(o);
- if (err < 0)
- return -EIO;
+ if (err < 0) {
+ err = -EIO;
+ goto finish;
+ }
o = pa_stream_cork(pcm->stream, 1, NULL, NULL);
assert(o);
pa_operation_unref(o);
- if (err < 0)
- return -EIO;
+ if (err < 0) {
+ err = -EIO;
+ goto finish;
+ }
- return 0;
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
int polyp_drain(snd_pcm_ioplug_t *io)
{
snd_pcm_polyp_t *pcm = io->private_data;
pa_operation *o;
- int err;
+ int err = 0;
+
+ assert(pcm);
- assert(pcm && pcm->p && pcm->stream);
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p && pcm->stream);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
o = pa_stream_drain(pcm->stream, NULL, NULL);
assert(o);
pa_operation_unref(o);
- if (err < 0)
- return -EIO;
+ if (err < 0) {
+ err = -EIO;
+ goto finish;
+ }
- return 0;
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static snd_pcm_sframes_t polyp_pointer(snd_pcm_ioplug_t *io)
{
snd_pcm_polyp_t *pcm = io->private_data;
- int err;
+ int err = 0;
- assert(pcm && pcm->p && pcm->stream);
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p && pcm->stream);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
update_ptr(pcm);
err = polyp_start_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
+
+ err = snd_pcm_bytes_to_frames(io->pcm, pcm->ptr);
- return snd_pcm_bytes_to_frames(io->pcm, pcm->ptr);
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static snd_pcm_sframes_t polyp_write(snd_pcm_ioplug_t *io,
{
snd_pcm_polyp_t *pcm = io->private_data;
const char *buf;
- int err;
+ int err = 0;
- assert(pcm && pcm->p && pcm->stream);
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p && pcm->stream);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
/* Make sure the buffer pointer is in sync */
update_ptr(pcm);
/* Make sure the buffer pointer is in sync */
update_ptr(pcm);
- return size;
+ err = size;
+
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static snd_pcm_sframes_t polyp_read(snd_pcm_ioplug_t *io,
snd_pcm_polyp_t *pcm = io->private_data;
void *dst_buf, *src_buf;
size_t remain_size, frag_length;
- int err;
+ int err = 0;
+
+ assert(pcm);
- assert(pcm && pcm->p && pcm->stream);
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p && pcm->stream);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
/* Make sure the buffer pointer is in sync */
update_ptr(pcm);
/* Make sure the buffer pointer is in sync */
update_ptr(pcm);
- return size - (remain_size / pcm->frame_size);
+ err = size - (remain_size / pcm->frame_size);
+
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static int polyp_pcm_poll_descriptors_count(snd_pcm_ioplug_t *io)
{
snd_pcm_polyp_t *pcm = io->private_data;
+ int count;
+
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p);
- assert(pcm && pcm->p);
+ count = polyp_poll_descriptors_count(pcm->p);
- return polyp_poll_descriptors_count(pcm->p);
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return count;
}
static int polyp_pcm_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space)
{
snd_pcm_polyp_t *pcm = io->private_data;
+ int err;
+
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p);
- assert(pcm && pcm->p);
+ err = polyp_poll_descriptors(pcm->p, pfd, space);
- return polyp_poll_descriptors(pcm->p, pfd, space);
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static int polyp_pcm_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int nfds, unsigned short *revents)
{
snd_pcm_polyp_t *pcm = io->private_data;
- int err;
+ int err = 0;
- assert(pcm && pcm->p);
+ assert(pcm);
+
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p);
err = polyp_poll_revents(pcm->p, pfd, nfds, revents);
if (err < 0)
- return err;
+ goto finish;
*revents = 0;
*revents |= POLLIN;
}
- return 0;
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static int polyp_prepare(snd_pcm_ioplug_t *io)
{
snd_pcm_polyp_t *pcm = io->private_data;
- int err;
- pa_stream_state_t state;
+ int err = 0;
+
+ assert(pcm);
- assert(pcm && pcm->p);
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p);
err = polyp_finish_poll(pcm->p);
if (err < 0)
- return err;
+ goto finish;
if (pcm->stream) {
pa_stream_disconnect(pcm->stream);
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
assert(pcm->stream == NULL);
fprintf(stderr, "*** POLYPAUDIO: Unable to create stream.\n");
pa_stream_unref(pcm->stream);
pcm->stream = NULL;
- return err;
+ goto finish;
}
pcm->last_size = 0;
pcm->ptr = 0;
pcm->offset = 0;
- return 0;
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static int polyp_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
{
snd_pcm_polyp_t *pcm = io->private_data;
+ int err = 0;
+
+ assert(pcm);
- assert(pcm && pcm->p && !pcm->stream);
+ pthread_mutex_lock(&pcm->mutex);
+
+ assert(pcm->p && !pcm->stream);
pcm->frame_size = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
default:
fprintf(stderr, "*** POLYPAUDIO: unsupported format %s\n",
snd_pcm_format_name(io->format));
- return -EINVAL;
+ err = -EINVAL;
+ goto finish;
}
pcm->ss.rate = io->rate;
pcm->buffer_attr.minreq = io->period_size * pcm->frame_size;
pcm->buffer_attr.fragsize = io->period_size * pcm->frame_size;
- return 0;
+finish:
+ pthread_mutex_unlock(&pcm->mutex);
+
+ return err;
}
static int polyp_close(snd_pcm_ioplug_t *io)
if (pcm->device)
free(pcm->device);
+ pthread_mutex_destroy(&pcm->mutex);
+
free(pcm);
return 0;
const char *device = NULL;
int err;
snd_pcm_polyp_t *pcm;
+ pthread_mutexattr_t mutexattr;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
if (err < 0)
goto error;
+ pthread_mutexattr_init(&mutexattr);
+ pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&pcm->mutex, &mutexattr);
+ pthread_mutexattr_destroy(&mutexattr);
+
pcm->io.version = SND_PCM_IOPLUG_VERSION;
pcm->io.name = "ALSA <-> Polypaudio PCM I/O Plugin";
pcm->io.poll_fd = -1;