summaryrefslogtreecommitdiffstats
path: root/polyp/pcm_polyp.c
diff options
context:
space:
mode:
Diffstat (limited to 'polyp/pcm_polyp.c')
-rw-r--r--polyp/pcm_polyp.c222
1 files changed, 165 insertions, 57 deletions
diff --git a/polyp/pcm_polyp.c b/polyp/pcm_polyp.c
index 80c943b..032ccbb 100644
--- a/polyp/pcm_polyp.c
+++ b/polyp/pcm_polyp.c
@@ -21,6 +21,8 @@
#include <stdio.h>
#include <sys/poll.h>
+#include <pthread.h>
+
#include <alsa/asoundlib.h>
#include <alsa/pcm_external.h>
@@ -44,6 +46,8 @@ typedef struct snd_pcm_polyp {
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)
@@ -67,17 +71,21 @@ static int polyp_start(snd_pcm_ioplug_t *io)
{
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);
@@ -86,27 +94,36 @@ static int polyp_start(snd_pcm_ioplug_t *io)
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);
@@ -115,8 +132,10 @@ static int polyp_stop(snd_pcm_ioplug_t *io)
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);
@@ -125,27 +144,36 @@ static int polyp_stop(snd_pcm_ioplug_t *io)
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);
@@ -154,34 +182,48 @@ int polyp_drain(snd_pcm_ioplug_t *io)
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,
@@ -191,17 +233,21 @@ 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);
@@ -215,7 +261,12 @@ static snd_pcm_sframes_t polyp_write(snd_pcm_ioplug_t *io,
/* 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,
@@ -226,17 +277,21 @@ 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);
@@ -270,37 +325,64 @@ static snd_pcm_sframes_t polyp_read(snd_pcm_ioplug_t *io,
/* 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;
@@ -319,20 +401,26 @@ static int polyp_pcm_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsi
*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);
@@ -343,7 +431,7 @@ static int polyp_prepare(snd_pcm_ioplug_t *io)
err = polyp_check_connection(pcm->p);
if (err < 0)
- return err;
+ goto finish;
assert(pcm->stream == NULL);
@@ -363,21 +451,29 @@ static int polyp_prepare(snd_pcm_ioplug_t *io)
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;
@@ -406,7 +502,8 @@ static int polyp_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
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;
@@ -418,7 +515,10 @@ static int polyp_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
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)
@@ -439,6 +539,8 @@ static int polyp_close(snd_pcm_ioplug_t *io)
if (pcm->device)
free(pcm->device);
+ pthread_mutex_destroy(&pcm->mutex);
+
free(pcm);
return 0;
@@ -543,6 +645,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(polyp)
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);
@@ -585,6 +688,11 @@ SND_PCM_PLUGIN_DEFINE_FUNC(polyp)
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;