From bef6322859a5dc01e35d884de7afd2eabb1d9e4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 May 2007 22:22:53 +0000 Subject: at basic locking/threading support git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@26 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- Makefile | 4 +- common.c | 585 +++++++++++++++++++++++++++++++++++++++++++++++---------------- common.h | 3 + macro.h | 23 +++ mutex.c | 86 ++++++++++ mutex.h | 19 +++ once.c | 58 +++++++ once.h | 17 ++ sydney.h | 19 ++- thread.c | 200 ++++++++++++++++++++++ thread.h | 27 +++ 11 files changed, 881 insertions(+), 160 deletions(-) create mode 100644 mutex.c create mode 100644 mutex.h create mode 100644 once.c create mode 100644 once.h create mode 100644 thread.c create mode 100644 thread.h diff --git a/Makefile b/Makefile index 2064a0b..cd6deb4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -CFLAGS=-Wall -O0 -g -W -Wno-unused-parameter `pkg-config --cflags liboil-0.3` -DRANDOM_PREFIX=sa -DOUTSIDE_SPEEX -D_GNU_SOURCE +CFLAGS=-Wall -O0 -g -W -Wno-unused-parameter `pkg-config --cflags liboil-0.3` -DRANDOM_PREFIX=sa -DOUTSIDE_SPEEX -D_GNU_SOURCE -pthread LIBS=-lm `pkg-config --libs liboil-0.3` -SOURCES=common.c malloc.c test-sine.c oss.c bbuffer.c format.c volscale.c byteswap.c continued-fraction.c zero.c add.c speex/resample.c resample.c interleave.c converter.c g711.c +SOURCES=common.c malloc.c test-sine.c oss.c bbuffer.c format.c volscale.c byteswap.c continued-fraction.c zero.c add.c speex/resample.c resample.c interleave.c converter.c g711.c mutex.c once.c thread.c OBJS=$(SOURCES:.c=.o) all: test-bufferq test-llist test-sine diff --git a/common.c b/common.c index dfdde95..a08316c 100644 --- a/common.c +++ b/common.c @@ -7,6 +7,7 @@ #include "malloc.h" #include "common.h" #include "driver.h" +#include "mutex.h" /* contains code */ #include "meta-name-table.h" @@ -19,6 +20,11 @@ static sa_stream_t *stream_alloc(void) { /* All fields a carefully chosen in a way that initializing them * NUL bytes is sufficient */ + + if (!(d->mutex = sa_mutex_new(0))) { + sa_free(d); + return NULL; + } return d; } @@ -48,7 +54,7 @@ int sa_stream_create_opaque( oil_init(); if (client_name) - if ((error = sa_stream_change_meta_data(*s, SA_META_CLIENT_NAME, client_name, strlen(client_name))) < 0) + if ((error = sa_stream_change_meta_data(*s, SA_META_CLIENT_NAME, client_name, strlen(client_name)+1)) < 0) goto fail; return SA_SUCCESS; @@ -136,16 +142,19 @@ int sa_stream_open(sa_stream_t *s) { int ret; sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); - sa_return_val_if_fail(s->codec || s->pcm_attrs.channel_map, SA_ERROR_NO_INIT); - sa_return_val_if_fail(!(s->mode & SA_MODE_RDONLY) || (s->read_lower_watermark <= s->read_upper_watermark), SA_ERROR_INVALID); - sa_return_val_if_fail(!(s->mode & SA_MODE_WRONLY) || (s->write_lower_watermark <= s->write_upper_watermark), SA_ERROR_INVALID); - sa_return_val_if_fail(!(s->mode & SA_MODE_RDONLY) || !s->codec || (s->read_lower_watermark > 0 && s->read_upper_watermark > 0), SA_ERROR_NO_INIT); - sa_return_val_if_fail(!(s->mode & SA_MODE_WRONLY) || !s->codec || (s->write_lower_watermark > 0 && s->write_upper_watermark > 0), SA_ERROR_NO_INIT); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->codec || s->pcm_attrs.channel_map, SA_ERROR_NO_INIT); + sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_RDONLY) || (s->read_lower_watermark <= s->read_upper_watermark), SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_WRONLY) || (s->write_lower_watermark <= s->write_upper_watermark), SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_RDONLY) || !s->codec || (s->read_lower_watermark > 0 && s->read_upper_watermark > 0), SA_ERROR_NO_INIT); + sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_WRONLY) || !s->codec || (s->write_lower_watermark > 0 && s->write_upper_watermark > 0), SA_ERROR_NO_INIT); if ((ret = driver_open(s)) == 0) s->state = SA_STATE_STOPPED; + sa_mutex_unlock(s->mutex); + return ret; } @@ -153,7 +162,7 @@ int sa_stream_destroy(sa_stream_t *s) { int ret; unsigned u; - sa_return_val_if_fail(s, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s, SA_ERROR_INVALID); ret = driver_destroy(s); @@ -167,6 +176,7 @@ int sa_stream_destroy(sa_stream_t *s) { for (u = 0; u < _META_NAMES_MAX; u++) sa_free(s->meta_data[u]); + sa_mutex_free(s->mutex); sa_free(s); return ret; } @@ -175,10 +185,14 @@ int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); s->write_lower_watermark = size; + + sa_mutex_unlock(s->mutex); + return SA_SUCCESS; } @@ -186,10 +200,13 @@ int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); s->read_lower_watermark = size; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } @@ -197,10 +214,13 @@ int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); s->write_upper_watermark = size; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } @@ -208,10 +228,13 @@ int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); s->read_upper_watermark = size; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } @@ -221,47 +244,62 @@ int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t *map, unsigned sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(map, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); - sa_return_val_if_fail(n == s->pcm_attrs.nchannels, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, n == s->pcm_attrs.nchannels, SA_ERROR_INVALID); for (c = map; n > 0; c++, n--) - if (*c >= _SA_CHANNEL_MAX) + if (*c >= _SA_CHANNEL_MAX) { + sa_mutex_unlock(s->mutex); return SA_ERROR_INVALID; + } - if (!(m = sa_memdup(map, sizeof(sa_channel_t) * s->pcm_attrs.nchannels))) + if (!(m = sa_memdup(map, sizeof(sa_channel_t) * s->pcm_attrs.nchannels))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } sa_free(s->pcm_attrs.channel_map); s->pcm_attrs.channel_map = m; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(mode == SA_XRUN_MODE_STOP || mode == SA_XRUN_MODE_SPIN, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); s->xrun_mode = mode; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_non_interleaved(sa_stream_t *s, int enable) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); s->ni_enabled = !!enable; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); s->dynamic_rate_enabled = !!enable; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } @@ -270,23 +308,33 @@ int sa_stream_set_driver(sa_stream_t *s, const char *driver) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(driver, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); - if (!(d = sa_strdup(driver))) + if (!(d = sa_strdup(driver))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } sa_free(s->driver); s->driver = d; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t *callback) { + int r; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(callback, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); - return driver_start_thread(s, callback); + r = driver_start_thread(s, callback); + + sa_mutex_unlock(s->mutex); + return r; } int sa_stream_change_device(sa_stream_t *s, const char *device_name) { @@ -299,6 +347,8 @@ int sa_stream_change_device(sa_stream_t *s, const char *device_name) { if (!(d = sa_strdup(device_name))) return SA_ERROR_OOM; + sa_mutex_lock(s->mutex); + ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_device(s, device_name); if (ret == SA_SUCCESS) { @@ -307,6 +357,8 @@ int sa_stream_change_device(sa_stream_t *s, const char *device_name) { } else sa_free(d); + sa_mutex_unlock(s->mutex); + return ret; } @@ -315,17 +367,22 @@ int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(vol, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); - sa_return_val_if_fail((!s->codec && n == s->pcm_attrs.nchannels) || s->pcm_attrs.nchannels == 1, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, (!s->codec && n == s->pcm_attrs.nchannels) || s->pcm_attrs.nchannels == 1, SA_ERROR_INVALID); if (s->codec || s->pcm_attrs.nchannels == n) { - if (!(v = sa_newdup(int32_t, vol, n))) + if (!(v = sa_newdup(int32_t, vol, n))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } } else { unsigned i; - if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) + if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } for (i = 0; i < s->pcm_attrs.nchannels; i++) v[i] = vol[0]; @@ -339,6 +396,7 @@ int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n } else sa_free(v); + sa_mutex_unlock(s->mutex); return ret; } @@ -347,17 +405,22 @@ int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(vol, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); - sa_return_val_if_fail((!s->codec && n == s->pcm_attrs.nchannels) || s->pcm_attrs.nchannels == 1, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, (!s->codec && n == s->pcm_attrs.nchannels) || s->pcm_attrs.nchannels == 1, SA_ERROR_INVALID); if (s->codec || s->pcm_attrs.nchannels == n) { - if (!(v = sa_newdup(int32_t, vol, n))) + if (!(v = sa_newdup(int32_t, vol, n))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } } else { unsigned i; - if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) + if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } for (i = 0; i < s->pcm_attrs.nchannels; i++) v[i] = vol[0]; @@ -371,6 +434,7 @@ int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned } else sa_free(v); + sa_mutex_unlock(s->mutex); return ret; } @@ -379,285 +443,434 @@ int sa_stream_change_rate(sa_stream_t *s, unsigned rate) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(rate > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); - sa_return_val_if_fail(s->dynamic_rate_enabled || s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->dynamic_rate_enabled || s->state == SA_STATE_INIT, SA_ERROR_STATE); ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_rate(s, rate); if (ret == SA_SUCCESS) s->pcm_attrs.rate = rate; + sa_mutex_unlock(s->mutex); return ret; } -int sa_stream_change_user_data(sa_stream_t *s, void *value) { - sa_return_val_if_fail(s, SA_ERROR_INVALID); - - s->user_data = value; +int sa_stream_change_user_data(sa_stream_t *s, const void *value) { + sa_return_val_if_fail(s->mutex, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + + s->user_data = (void*) value; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); s->adjust_rate = direction; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); s->adjust_rate = direction; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); s->adjust_pcm_format = direction; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_INIT, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); s->adjust_watermarks = direction; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_state(sa_stream_t *s, sa_state_t *state) { + int ret; sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(state, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, state, SA_ERROR_INVALID); + + ret = driver_get_state(s, state); - return driver_get_state(s, state); + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_get_rate(sa_stream_t *s, unsigned *rate) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(rate, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); *rate = s->pcm_attrs.rate; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(nchannels, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); *nchannels = s->pcm_attrs.nchannels; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *pcm_format) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(pcm_format, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); *pcm_format = s->pcm_attrs.format; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(access_mode, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); *access_mode = s->mode; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } -int sa_stream_get_codec(sa_stream_t *s, const char **codec) { +int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size) { + size_t n; + sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(codec, SA_ERROR_INVALID); - sa_return_val_if_fail(s->codec, SA_ERROR_STATE); + sa_return_val_if_fail(size && (*size == 0 || codec), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->codec, SA_ERROR_STATE); + + n = strlen(s->codec)+1; + if (*size < n) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } - *codec = s->codec; + if (codec) + strcpy(codec, s->codec); + *size = n; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); *size = s->write_lower_watermark; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); *size = s->read_lower_watermark; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); *size = s->write_upper_watermark; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); *size = s->read_upper_watermark; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } -int sa_stream_get_channel_map(sa_stream_t *s, const sa_channel_t *map[]) { +int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t *map, unsigned *n) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(map, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_return_val_if_fail(n && (*n == 0 || map), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + + if (*n < s->pcm_attrs.nchannels) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } - *map = s->pcm_attrs.channel_map; + if (map) + memcpy(map, s->pcm_attrs.channel_map, s->pcm_attrs.nchannels * sizeof(sa_channel_t)); + *n = s->pcm_attrs.nchannels; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(mode, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); *mode = s->xrun_mode; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(enabled, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); *enabled = s->ni_enabled; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(enabled, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); - *enabled = s->ni_enabled; + *enabled = s->dynamic_rate_enabled; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } -int sa_stream_get_driver(sa_stream_t *s, const char **driver) { +int sa_stream_get_driver(sa_stream_t *s, char *driver, size_t *size) { + size_t n; + sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(driver, SA_ERROR_INVALID); - sa_return_val_if_fail(s->driver, SA_ERROR_STATE); + sa_return_val_if_fail(size && (*size == 0 || driver), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->driver, SA_ERROR_STATE); + + n = strlen(s->driver)+1; + if (*size < n) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } - *driver = s->driver; + if (driver) + strcpy(driver, s->driver); + *size = n; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } -int sa_stream_get_device(sa_stream_t *s, const char **device_name) { +int sa_stream_get_device(sa_stream_t *s, char *device, size_t *size) { + size_t n; + sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(device_name, SA_ERROR_INVALID); - sa_return_val_if_fail(s->device, SA_ERROR_STATE); + sa_return_val_if_fail(size && (*size == 0 || device), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->device, SA_ERROR_STATE); + + n = strlen(s->device)+1; + if (*size < n) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } - *device_name = s->device; + if (device) + strcpy(device, s->device); + *size = n; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } -int sa_stream_get_read_volume(sa_stream_t *s, const int32_t *vol[]) { +int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(vol, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->read_volume, SA_ERROR_STATE); + sa_return_val_if_fail(n && (*n == 0 || vol), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->read_volume, SA_ERROR_STATE); + + if (*n < s->pcm_attrs.nchannels) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } + + if (vol) + memcpy(vol, s->read_volume, s->pcm_attrs.nchannels * sizeof(int32_t)); + *n = s->pcm_attrs.nchannels; - *vol = s->read_volume; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } -int sa_stream_get_write_volume(sa_stream_t *s, const int32_t *vol[]) { +int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n) { sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(vol, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->write_volume, SA_ERROR_STATE); + sa_return_val_if_fail(n && (*n == 0 || vol), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->write_volume, SA_ERROR_STATE); + + if (*n < s->pcm_attrs.nchannels) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } + + if (vol) + memcpy(vol, s->write_volume, s->pcm_attrs.nchannels * sizeof(int32_t)); + *n = s->pcm_attrs.nchannels; - *vol = s->write_volume; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(direction, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); *direction = s->adjust_rate; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(direction, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); *direction = s->adjust_nchannels; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(direction, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); *direction = s->adjust_pcm_format; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction) { - sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(direction, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, direction, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); *direction = s->adjust_watermarks; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_user_data(sa_stream_t *s, void **value) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(value, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); *value = s->user_data; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(error, SA_ERROR_INVALID); - sa_return_val_if_fail(s->event == SA_EVENT_ERROR, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->event == SA_EVENT_ERROR, SA_ERROR_STATE); *error = s->error; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify) { sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(notify, SA_ERROR_INVALID); - sa_return_val_if_fail(s->event == SA_EVENT_NOTIFY, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->event == SA_EVENT_NOTIFY, SA_ERROR_STATE); *notify = s->notify; + + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } int sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(pos, SA_ERROR_INVALID); sa_return_val_if_fail(position < _SA_POSITION_MAX, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + + ret = driver_get_position(s, position, pos); - return driver_get_position(s, position, pos); + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes) { @@ -677,103 +890,157 @@ int sa_stream_write_ni(sa_stream_t *s, unsigned channel, const void *data, size_ } int sa_stream_pread(sa_stream_t *s, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(data, SA_ERROR_INVALID); sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID); sa_return_val_if_fail(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->ni_enabled, SA_ERROR_STATE); - sa_return_val_if_fail(s->codec || (nbytes % s->pcm_frame_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->codec || (offset % s->pcm_frame_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->ni_enabled, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->codec || (nbytes % s->pcm_frame_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->codec || (offset % s->pcm_frame_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - return driver_pread(s, data, nbytes, offset, whence); + ret = driver_pread(s, data, nbytes, offset, whence); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(data, SA_ERROR_INVALID); sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID); sa_return_val_if_fail(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->ni_enabled, SA_ERROR_STATE); - sa_return_val_if_fail(s->codec || (nbytes % s->pcm_frame_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->codec || (offset % s->pcm_frame_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->ni_enabled, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->codec || (nbytes % s->pcm_frame_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->codec || (offset % s->pcm_frame_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - return driver_pwrite(s, data, nbytes, offset, whence); + ret = driver_pwrite(s, data, nbytes, offset, whence); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_pread_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(data, SA_ERROR_INVALID); sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); sa_return_val_if_fail(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID); - sa_return_val_if_fail(channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID); - sa_return_val_if_fail(s->ni_enabled, SA_ERROR_STATE); - sa_return_val_if_fail((nbytes % s->pcm_sample_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail((offset % s->pcm_sample_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - - return driver_pread_ni(s, channel, data, nbytes, offset, whence); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->ni_enabled, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, (nbytes % s->pcm_sample_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, (offset % s->pcm_sample_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + + ret = driver_pread_ni(s, channel, data, nbytes, offset, whence); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(data, SA_ERROR_INVALID); sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID); - sa_return_val_if_fail(!s->codec, SA_ERROR_STATE); sa_return_val_if_fail(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID); - sa_return_val_if_fail(channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID); - sa_return_val_if_fail(s->ni_enabled, SA_ERROR_STATE); - sa_return_val_if_fail((nbytes % s->pcm_sample_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail((offset % s->pcm_sample_size) == 0, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - - return driver_pwrite_ni(s, channel, data, nbytes, offset, whence); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->ni_enabled, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, (nbytes % s->pcm_sample_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, (offset % s->pcm_sample_size) == 0, SA_ERROR_INVALID); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + + ret = driver_pwrite_ni(s, channel, data, nbytes, offset, whence); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_get_read_size(sa_stream_t *s, size_t *size) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - return driver_get_read_size(s, size); + ret = driver_get_read_size(s, size); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_get_write_size(sa_stream_t *s, size_t *size) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(size, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - return driver_get_write_size(s, size); + ret = driver_get_write_size(s, size); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_resume(sa_stream_t *s) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); - return driver_resume(s); + ret = driver_resume(s); + + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_pause(sa_stream_t *s) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + + ret = driver_pause(s); - return driver_pause(s); + sa_mutex_unlock(s->mutex); + return ret; } int sa_stream_drain(sa_stream_t *s) { + int ret; + sa_return_val_if_fail(s, SA_ERROR_INVALID); - sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); - sa_return_val_if_fail(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); + sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE); + + ret = driver_drain(s); - return driver_drain(s); + sa_mutex_unlock(s->mutex); + return ret; } size_t get_pcm_sample_size(sa_pcm_format_t f) { @@ -899,17 +1166,24 @@ int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *dat sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(name, SA_ERROR_INVALID); - sa_return_val_if_fail(data || size == 0, SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); + sa_return_val_if_fail_mutex(s->mutex, data || size == 0, SA_ERROR_INVALID); - if (!(m = lookup_meta_name(name, strlen(name)))) + if (!(m = lookup_meta_name(name, strlen(name)))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_NO_META; + } - if (!check_table[m->idx](data, size)) + if (!check_table[m->idx](data, size)) { + sa_mutex_unlock(s->mutex); return SA_ERROR_INVALID; + } if (data) - if (!(d = sa_memdup(data, size))) + if (!(d = sa_memdup(data, size))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_OOM; + } ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_meta_data(s, name, data, size); @@ -920,26 +1194,39 @@ int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *dat } else sa_free(d); + sa_mutex_unlock(s->mutex); return ret; } -int sa_stream_get_meta_data(sa_stream_t *s, const char *name, const void **data, size_t *size) { +int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void *data, size_t *size) { const struct meta_name *m; sa_return_val_if_fail(s, SA_ERROR_INVALID); sa_return_val_if_fail(name, SA_ERROR_INVALID); - sa_return_val_if_fail(data, SA_ERROR_INVALID); - sa_return_val_if_fail(size, SA_ERROR_INVALID); + sa_return_val_if_fail(size && (*size == 0 || data), SA_ERROR_INVALID); + sa_mutex_lock(s->mutex); - if (!(m = lookup_meta_name(name, strlen(name)))) + if (!(m = lookup_meta_name(name, strlen(name)))) { + sa_mutex_unlock(s->mutex); return SA_ERROR_NO_META; + } - if (!s->meta_data[m->idx]) + if (!s->meta_data[m->idx]) { + sa_mutex_unlock(s->mutex); return SA_ERROR_NO_DATA; + } + + if (*size < s->meta_data_size[m->idx]) { + sa_mutex_unlock(s->mutex); + return SA_ERROR_NO_SPACE; + } + + if (data) + memcpy(data, s->meta_data[m->idx], s->meta_data_size[m->idx]); - *data = s->meta_data[m->idx]; *size = s->meta_data_size[m->idx]; + sa_mutex_unlock(s->mutex); return SA_SUCCESS; } diff --git a/common.h b/common.h index 41c43b1..58a9a3e 100644 --- a/common.h +++ b/common.h @@ -2,6 +2,7 @@ #define foocommonh #include "sydney.h" +#include "mutex.h" #define _META_NAMES_MAX 9 @@ -55,6 +56,8 @@ struct sa_stream { void *meta_data[_META_NAMES_MAX]; size_t meta_data_size[_META_NAMES_MAX]; + + sa_mutex_t *mutex; }; size_t get_pcm_sample_size(sa_pcm_format_t f); diff --git a/macro.h b/macro.h index 847bf97..ed80654 100644 --- a/macro.h +++ b/macro.h @@ -26,10 +26,33 @@ } \ } while(0) +#define sa_return_if_fail_mutex(m, expr) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, "%s: Assertion <%s> failed.\n", PRETTY_FUNCTION, #expr ); \ + sa_mutex_unlock(m); \ + return; \ + } \ + } while(0) + +#define sa_return_val_if_fail_mutex(m, expr, val) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, "%s: Assertion <%s> failed.\n", PRETTY_FUNCTION, #expr ); \ + sa_mutex_unlock(m); \ + return (val); \ + } \ + } while(0) + #define sa_assert assert #define sa_assert_not_reached() sa_assert(!"Should not be reached.") +#define sa_assert_success(x) do { \ + int _r = (x); \ + sa_assert(_r == 0); \ + } while(0) + #define elementsof(x) (sizeof(x)/sizeof((x)[0])) #ifndef MAX diff --git a/mutex.c b/mutex.c new file mode 100644 index 0000000..8674fff --- /dev/null +++ b/mutex.c @@ -0,0 +1,86 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "macro.h" +#include "malloc.h" +#include "mutex.h" + +struct sa_mutex { + pthread_mutex_t mutex; +}; + +struct sa_cond { + pthread_cond_t cond; +}; + +sa_mutex_t* sa_mutex_new(int recursive) { + sa_mutex_t *m; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if (recursive) + sa_assert_success(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); + + if (!(m = sa_new(sa_mutex_t, 1))) + return NULL; + + sa_assert_success(pthread_mutex_init(&m->mutex, &attr)); + return m; +} + +void sa_mutex_free(sa_mutex_t *m) { + assert(m); + + sa_assert_success(pthread_mutex_destroy(&m->mutex)); + sa_free(m); +} + +void sa_mutex_lock(sa_mutex_t *m) { + assert(m); + + sa_assert_success(pthread_mutex_lock(&m->mutex)); +} + +void sa_mutex_unlock(sa_mutex_t *m) { + assert(m); + + sa_assert_success(pthread_mutex_unlock(&m->mutex)); +} + +sa_cond_t *sa_cond_new(void) { + sa_cond_t *c; + + if (!(c = sa_new(sa_cond_t, 1))) + return NULL; + + sa_assert_success(pthread_cond_init(&c->cond, NULL)); + return c; +} + +void sa_cond_free(sa_cond_t *c) { + assert(c); + + sa_assert_success(pthread_cond_destroy(&c->cond)); + sa_free(c); +} + +void sa_cond_signal(sa_cond_t *c, int broadcast) { + assert(c); + + if (broadcast) + sa_assert_success(pthread_cond_broadcast(&c->cond)); + else + sa_assert_success(pthread_cond_signal(&c->cond)); +} + +int sa_cond_wait(sa_cond_t *c, sa_mutex_t *m) { + assert(c); + assert(m); + + return pthread_cond_wait(&c->cond, &m->mutex); +} diff --git a/mutex.h b/mutex.h new file mode 100644 index 0000000..e83feb8 --- /dev/null +++ b/mutex.h @@ -0,0 +1,19 @@ +#ifndef foosydneymutexhfoo +#define foosydneymutexhfoo + +typedef struct sa_mutex sa_mutex_t; + +sa_mutex_t* sa_mutex_new(int recursive); +void sa_mutex_free(sa_mutex_t *m); +void sa_mutex_lock(sa_mutex_t *m); +void sa_mutex_unlock(sa_mutex_t *m); +int sa_mutex_try_lock(sa_mutex_t *m); + +typedef struct sa_cond sa_cond_t; + +sa_cond_t *sa_cond_new(void); +void sa_cond_free(sa_cond_t *c); +void sa_cond_signal(sa_cond_t *c, int broadcast); +int sa_cond_wait(sa_cond_t *c, sa_mutex_t *m); + +#endif diff --git a/once.c b/once.c new file mode 100644 index 0000000..de41be3 --- /dev/null +++ b/once.c @@ -0,0 +1,58 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "once.h" +#include "mutex.h" +#include "malloc.h" +#include "macro.h" + +static sa_mutex_t *global_mutex; +static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT; + +static void global_mutex_once_func(void) { + global_mutex = sa_mutex_new(0); +} + +int sa_once(sa_once_t *control, sa_once_func_t func) { + int r; + + assert(control); + assert(func); + + /* Create the global mutex */ + sa_assert_success(pthread_once(&global_mutex_once, global_mutex_once_func)); + + if (!global_mutex) + return -1; + + r = 0; + + /* Create the local mutex */ + sa_mutex_lock(global_mutex); + if (!control->mutex) { + if (!(control->mutex = sa_mutex_new(1))) + r = -1; + } + sa_mutex_unlock(global_mutex); + + if (!r) + return -1; + + /* Execute function */ + sa_mutex_lock(control->mutex); + if (!control->once_value) { + control->once_value = 1; + func(); + } + sa_mutex_unlock(control->mutex); + + /* Caveat: We have to make sure that the once func has completed + * before returning, even if the once func is not actually + * executed by us. Hence the awkward locking. */ + + return 0; +} diff --git a/once.h b/once.h new file mode 100644 index 0000000..a374529 --- /dev/null +++ b/once.h @@ -0,0 +1,17 @@ +#ifndef foosydneyoncehfoo +#define foosydneyoncehfoo + +#include "mutex.h" + +typedef struct sa_once { + unsigned int once_value; + sa_mutex_t *mutex; +} sa_once_t; + +#define SA_ONCE_INIT { .once_value = 0, .mutex = NULL } + +typedef void (*sa_once_func_t) (void); + +int sa_once(sa_once_t *o, sa_once_func_t f); + +#endif diff --git a/sydney.h b/sydney.h index 30afc03..e9ba724 100644 --- a/sydney.h +++ b/sydney.h @@ -106,7 +106,8 @@ typedef enum { SA_ERROR_NO_INIT = -9, SA_ERROR_NO_META = -10, SA_ERROR_NO_DATA = -11, - _SA_ERROR_MAX = -12 + SA_ERROR_NO_SPACE = -12, + _SA_ERROR_MAX = -13 } sa_error_t; /** Possible events for notifications */ @@ -287,7 +288,7 @@ int sa_stream_change_rate(sa_stream_t *s, unsigned rate); int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size); /** Associate opaque user data */ -int sa_stream_change_user_data(sa_stream_t *s, void *value); +int sa_stream_change_user_data(sa_stream_t *s, const void *value); /* Hardware-related. This is implementation-specific and hardware specific. */ int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction); @@ -298,7 +299,7 @@ int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction); /* Query functions */ int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode); -int sa_stream_get_codec(sa_stream_t *s, const char **codec); +int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size); int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format); int sa_stream_get_rate(sa_stream_t *s, unsigned *rate); int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels); @@ -307,15 +308,15 @@ int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size); -int sa_stream_get_channel_map(sa_stream_t *s, const sa_channel_t *map[]); +int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned *n); int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode); int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled); int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled); -int sa_stream_get_driver(sa_stream_t *s, const char **driver); -int sa_stream_get_device(sa_stream_t *s, const char **device_name); -int sa_stream_get_read_volume(sa_stream_t *s, const int32_t *vol[]); -int sa_stream_get_write_volume(sa_stream_t *s, const int32_t *vol[]); -int sa_stream_get_meta_data(sa_stream_t *s, const char *name, const void **data, size_t *size); +int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size); +int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size); +int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n); +int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n); +int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void *data, size_t *size); int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction); int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction); int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction); diff --git a/thread.c b/thread.c new file mode 100644 index 0000000..806e210 --- /dev/null +++ b/thread.c @@ -0,0 +1,200 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "thread.h" +#include "malloc.h" +#include "once.h" +#include "macro.h" + +struct sa_thread { + pthread_t id; + sa_thread_func_t thread_func; + void *userdata; + int running; + pthread_mutex_t running_mutex; +}; + +struct sa_tls { + pthread_key_t key; +}; + +static sa_tls_t *thread_tls; +static sa_once_t thread_tls_once = SA_ONCE_INIT; + +static void tls_free_cb(void *p) { + sa_thread_t *t = p; + + sa_assert(t); + + if (!t->thread_func) + /* This is a foreign thread, we need to free the struct */ + sa_free(t); +} + +static void thread_tls_once_func(void) { + thread_tls = sa_tls_new(tls_free_cb); +} + +static void* internal_thread_func(void *userdata) { + sa_thread_t *t = userdata; + sa_assert(t); + + t->id = pthread_self(); + sa_tls_set(thread_tls, t); + + t->thread_func(t->userdata); + + sa_assert_success(pthread_mutex_lock(&t->running_mutex)); + t->running = 0; + sa_assert_success(pthread_mutex_unlock(&t->running_mutex)); + + return NULL; +} + +sa_thread_t* sa_thread_new(sa_thread_func_t thread_func, void *userdata) { + sa_thread_t *t; + + sa_assert(thread_func); + + if (sa_once(&thread_tls_once, thread_tls_once_func) < 0 || !thread_tls) + return NULL; + + if (!(t = sa_new(sa_thread_t, 1))) + return NULL; + + t->thread_func = thread_func; + t->userdata = userdata; + + sa_assert_success(pthread_mutex_init(&t->running_mutex, NULL)); + t->running = 1; + + if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { + sa_assert_success(pthread_mutex_destroy(&t->running_mutex)); + sa_free(t); + return NULL; + } + + return t; +} + +int sa_thread_is_running(sa_thread_t *t) { + int b; + sa_assert(t); + + if (!t->thread_func) { + /* Mhmm, this is a foreign thread, t->running is not + * necessarily valid. We misuse pthread_getschedparam() to + * check if the thread is valid. This might not be portable. */ + + int policy; + struct sched_param param; + + return pthread_getschedparam(t->id, &policy, ¶m) >= 0 || errno != ESRCH; + } + + sa_assert_success(pthread_mutex_lock(&t->running_mutex)); + b = t->running; + sa_assert_success(pthread_mutex_unlock(&t->running_mutex)); + + return !!b; +} + +void sa_thread_free(sa_thread_t *t) { + sa_assert(t); + + sa_thread_join(t); + sa_assert_success(pthread_mutex_destroy(&t->running_mutex)); + sa_free(t); +} + +int sa_thread_join(sa_thread_t *t) { + sa_assert(t); + + return pthread_join(t->id, NULL); +} + +sa_thread_t* sa_thread_self(void) { + sa_thread_t *t; + + if (sa_once(&thread_tls_once, thread_tls_once_func) < 0 || !thread_tls) + return NULL; + + if ((t = sa_tls_get(thread_tls))) + return t; + + /* This is a foreign thread, let's create a pthread structure to + * make sure that we can always return a sensible pointer */ + + if (!(t = sa_new(sa_thread_t, 1))) + return NULL; + + t->id = pthread_self(); + t->thread_func = NULL; + t->userdata = NULL; + t->running = 1; + + sa_tls_set(thread_tls, t); + + return t; +} + +void* sa_thread_get_data(sa_thread_t *t) { + sa_assert(t); + + return t->userdata; +} + +void sa_thread_set_data(sa_thread_t *t, void *userdata) { + sa_assert(t); + + t->userdata = userdata; +} + +void sa_thread_yield(void) { +#ifdef HAVE_PTHREAD_YIELD + pthread_yield(); +#else + sa_assert_success(sched_yield()); +#endif +} + +sa_tls_t* sa_tls_new(sa_free_func_t free_cb) { + sa_tls_t *t; + + if (!(t = sa_new(sa_tls_t, 1))) + return NULL; + + if (pthread_key_create(&t->key, free_cb) < 0) { + sa_free(t); + return NULL; + } + + return t; +} + +void sa_tls_free(sa_tls_t *t) { + sa_assert(t); + + sa_assert_success(pthread_key_delete(t->key)); + sa_free(t); +} + +void *sa_tls_get(sa_tls_t *t) { + sa_assert(t); + + return pthread_getspecific(t->key); +} + +void *sa_tls_set(sa_tls_t *t, void *userdata) { + void *r; + + r = pthread_getspecific(t->key); + sa_assert_success(pthread_setspecific(t->key, userdata)); + return r; +} + diff --git a/thread.h b/thread.h new file mode 100644 index 0000000..1a61e7a --- /dev/null +++ b/thread.h @@ -0,0 +1,27 @@ +#ifndef foosydneythreadhfoo +#define foosydneythreadhfoo + +typedef struct sa_thread sa_thread_t; + +typedef void (*sa_thread_func_t) (void *userdata); + +sa_thread_t* sa_thread_new(sa_thread_func_t sa_thread_func, void *userdata); +void sa_thread_free(sa_thread_t *t); +int sa_thread_join(sa_thread_t *t); +int sa_thread_is_running(sa_thread_t *t); +sa_thread_t *sa_thread_self(void); +void sa_thread_yield(void); + +void* sa_thread_get_data(sa_thread_t *t); +void sa_thread_set_data(sa_thread_t *t, void *userdata); + +typedef struct sa_tls sa_tls_t; + +typedef void (*sa_free_func_t) (void *data); + +sa_tls_t* sa_tls_new(sa_free_func_t f); +void sa_tls_free(sa_tls_t *t); +void * sa_tls_get(sa_tls_t *t); +void *sa_tls_set(sa_tls_t *t, void *userdata); + +#endif -- cgit