summaryrefslogtreecommitdiffstats
path: root/src/common.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-10-09 18:15:23 +0200
committerLennart Poettering <lennart@poettering.net>2008-10-09 18:15:23 +0200
commit181e9c6d5d11cb1e5d36a2777eeb233ad8ed00e5 (patch)
tree7c280968ce3fded5b325b1480d7f2440ddf93207 /src/common.c
parent30a4b516c8d591c11f05df38531f46452d930d2b (diff)
big pile of updates to match more what happened with libcanberra
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c1406
1 files changed, 855 insertions, 551 deletions
diff --git a/src/common.c b/src/common.c
index 0187990..5a50f9e 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1,9 +1,30 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 2.1 of the
+ License, or (at your option) any later version.
+
+ libsydney is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <errno.h>
+#include <math.h>
#include <liboil/liboil.h>
#include "sydney.h"
@@ -12,72 +33,114 @@
#include "common.h"
#include "driver.h"
#include "mutex.h"
+#include "proplist.h"
+
+/*
+ Requirements & General observations
+
+ - In sync mode, the device will automatically write data so that an
+ initial read causes writes of zeros to be issued to that one can
+ do "while (1); {read(); write()}
+ - All functions are thread-safe and can be called in any thread
+ context. None of the functions is async-signal safe.
+ - It is assumed that duplex streams have a single clock (synchronised)
+ - Property set extensible. To be kept in sync with PulseAudio and libcanberra
+ - Error codes are returned immediately, as negative integers
+ - It is recommended to set most properties before the _open() call.
+
+*/
-/* contains code */
-#include "meta-name-table.h"
+#define DEFAULT_LATENCY_USEC (2000000ULL) /* 2s */
+#define DEFAULT_PROCESS_TIME_USEC (20000ULL) /* 20ms */
-static sa_stream_t *stream_alloc(void) {
- sa_stream_t *d;
+static int stream_alloc(sa_stream **_s) {
+ sa_stream *s;
+ const char *d;
+ int ret;
+
+ sa_assert(_s);
- if (!(d = sa_new0(sa_stream_t, 1)))
- return NULL;
+ if (!(s = sa_new0(sa_stream, 1))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
+ }
/* All fields a carefully chosen in a way that initializing them
- * NUL bytes is sufficient */
+ * with NUL bytes is sufficient */
- if (!(d->mutex = sa_mutex_new(FALSE, TRUE))) {
- sa_free(d);
- return NULL;
+ if (!(s->mutex = sa_mutex_new(TRUE, TRUE))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- return d;
+ if ((ret = sa_proplist_create(&s->props)) < 0)
+ goto fail;
+
+ if ((d = getenv("SYDNEY_DRIVER")))
+ if ((ret = sa_stream_set_driver(s, d)) < 0)
+ goto fail;
+
+ if ((d = getenv("SYDNEY_DEVICE")))
+ if ((ret = sa_stream_change_device(s, d)) < 0)
+ goto fail;
+
+ *_s = s;
+
+ return SA_SUCCESS;
+
+fail:
+
+ if (s)
+ sa_assert_se(sa_stream_destroy(s) == SA_SUCCESS);
+
+ return ret;
}
int sa_stream_create_opaque(
- sa_stream_t **s,
- const char *client_name,
+ sa_stream **_s,
sa_mode_t mode,
const char *codec) {
- int error;
+ int ret;
+ sa_stream *s;
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(_s, SA_ERROR_INVALID);
sa_return_val_if_fail(mode == SA_MODE_RDONLY || mode == SA_MODE_WRONLY || mode == SA_MODE_RDWR, SA_ERROR_INVALID);
sa_return_val_if_fail(codec, SA_ERROR_INVALID);
- if (!(*s = stream_alloc()))
+ if ((ret = stream_alloc(&s)) < 0)
return SA_ERROR_OOM;
- (*s)->mode = mode;
+ s->mode = mode;
- if (!((*s)->codec = sa_strdup(codec))) {
- error = SA_ERROR_OOM;
+ if (!(s->codec = sa_strdup(codec))) {
+ ret = SA_ERROR_OOM;
goto fail;
}
oil_init();
- if (client_name)
- if ((error = sa_stream_change_meta_data(*s, SA_META_CLIENT_NAME, client_name, strlen(client_name)+1)) < 0)
- goto fail;
+ *_s = s;
return SA_SUCCESS;
fail:
- sa_stream_destroy(*s);
- return error;
+
+ if (s)
+ sa_assert_se(sa_stream_destroy(s) == SA_SUCCESS);
+
+ return ret;
}
int sa_stream_create_pcm(
- sa_stream_t **s,
- const char *client_name,
+ sa_stream **_s,
sa_mode_t mode,
sa_pcm_format_t format,
unsigned rate,
unsigned nchannels) {
int ret;
- size_t lwm;
+ sa_stream *s;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(mode == SA_MODE_RDONLY || mode == SA_MODE_WRONLY || mode == SA_MODE_RDWR, SA_ERROR_INVALID);
@@ -85,90 +148,122 @@ int sa_stream_create_pcm(
sa_return_val_if_fail(rate > 0, SA_ERROR_INVALID);
sa_return_val_if_fail(nchannels > 0, SA_ERROR_INVALID);
- if (!(*s = stream_alloc()))
+ if ((ret = stream_alloc(&s)) < 0)
return SA_ERROR_OOM;
- (*s)->mode = mode;
- (*s)->pcm_attrs.format = format;
- (*s)->pcm_attrs.nchannels = nchannels;
- (*s)->pcm_sample_size = sa_get_pcm_sample_size(format);
- (*s)->pcm_frame_size = (*s)->pcm_sample_size * nchannels;
+ s->mode = mode;
+ s->pcm_attrs.format = format;
+ s->pcm_attrs.nchannels = nchannels;
+ s->pcm_sample_size = sa_get_pcm_sample_size(format);
+ s->pcm_frame_size = s->pcm_sample_size * nchannels;
+
+ if ((ret = sa_stream_change_pcm_rate(s, rate)))
+ goto fail;
if (nchannels <= 2) {
static const sa_channel_t map_stereo[2] = { SA_CHANNEL_LEFT, SA_CHANNEL_RIGHT };
static const sa_channel_t map_mono[1] = { SA_CHANNEL_MONO };
- if ((ret = sa_stream_set_channel_map(*s, nchannels == 2 ? map_stereo : map_mono, nchannels)))
+ if ((ret = sa_stream_set_channel_map(s, nchannels == 2 ? map_stereo : map_mono, nchannels)))
goto fail;
}
- if ((ret = sa_stream_change_rate(*s, rate)))
- goto fail;
+ oil_init();
- lwm = ((*s)->pcm_frame_size * (*s)->pcm_attrs.rate) / 20; /* 50 ms */
+ *_s = s;
- if (lwm <= 0)
- lwm = (*s)->pcm_frame_size * (*s)->pcm_attrs.rate; /* 1s */
+ return SA_SUCCESS;
-/* if (mode & SA_MODE_RDONLY) { */
+fail:
-/* if ((ret = sa_stream_set_read_lower_watermark(*s, lwm))) */
-/* goto fail; */
+ sa_assert_se(sa_stream_destroy(s) == SA_SUCCESS);
+ return ret;
+}
-/* if ((ret = sa_stream_set_read_upper_watermark(*s, lwm*2))) */
-/* goto fail; */
-/* } */
+static int fix_latency(sa_stream *s, size_t *latency_nbytes, size_t *process_time_nbytes) {
-/* if (mode & SA_MODE_WRONLY) { */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(latency_nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(process_time_nbytes, SA_ERROR_INVALID);
-/* if ((ret = sa_stream_set_write_lower_watermark(*s, lwm))) */
-/* goto fail; */
+ if (*latency_nbytes <= 0)
+ *latency_nbytes = sa_stream_usec_to_bytes(s, DEFAULT_LATENCY_USEC, 0);
-/* if ((ret = sa_stream_set_write_upper_watermark(*s, lwm*2))) */
-/* goto fail; */
-/* } */
+ if (*process_time_nbytes <= 0) {
+ size_t n, m;
- oil_init();
+ n = sa_stream_frames_to_bytes(s, sa_stream_bytes_to_frames(s, *latency_nbytes, 1)/2);
+ m = sa_stream_usec_to_bytes(s, DEFAULT_PROCESS_TIME_USEC, 0);
- if (client_name)
- if ((ret = sa_stream_change_meta_data(*s, SA_META_CLIENT_NAME, client_name, strlen(client_name))) < 0)
- goto fail;
+ *process_time_nbytes = SA_MIN(n, m);
+ }
+
+ sa_return_val_if_fail(*latency_nbytes > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(*process_time_nbytes >= *latency_nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(sa_stream_frame_aligned(s, (int64_t) *latency_nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(sa_stream_frame_aligned(s, (int64_t) *process_time_nbytes), SA_ERROR_INVALID);
return SA_SUCCESS;
+}
-fail:
- sa_stream_destroy(*s);
+static int stream_open_unlocked(sa_stream *s) {
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || s->pcm_attrs.channel_map, SA_ERROR_STATE);
+
+ if (s->state == SA_STATE_DEAD)
+ return SA_ERROR_STATE;
+ else if (s->state != SA_STATE_INIT)
+ return SA_SUCCESS;
+
+ if (s->mode & SA_MODE_RDONLY)
+ if ((ret = fix_latency(s, &s->read_latency, &s->read_process_time)) < 0)
+ return ret;
+
+ if (s->mode & SA_MODE_WRONLY)
+ if ((ret = fix_latency(s, &s->write_latency, &s->write_process_time)) < 0)
+ return ret;
+
+ if ((ret = driver_open(s)) == SA_SUCCESS)
+ s->state = SA_STATE_STOPPED;
+
return ret;
}
-int sa_stream_open(sa_stream_t *s) {
+int sa_stream_open(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, 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 || 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_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
+
+ ret = stream_open_unlocked(s);
sa_mutex_unlock(s->mutex);
return ret;
}
-int sa_stream_destroy(sa_stream_t *s) {
- int ret;
- unsigned u;
+int sa_stream_destroy(sa_stream *s) {
+ int ret = SA_SUCCESS;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- ret = driver_destroy(s);
+ /* There's no locking necessary here, because the application is
+ * broken anyway if it destructs this object in one thread and
+ * still is calling a method of it in another. */
+
+ if (s->state != SA_STATE_INIT)
+ ret = driver_destroy(s);
+
+ if (s->props)
+ sa_assert_se(sa_proplist_destroy(s->props) == SA_SUCCESS);
+
+ if (s->mutex)
+ sa_mutex_free(s->mutex);
sa_free(s->codec);
sa_free(s->driver);
@@ -176,106 +271,100 @@ int sa_stream_destroy(sa_stream_t *s) {
sa_free(s->pcm_attrs.channel_map);
sa_free(s->read_volume);
sa_free(s->write_volume);
-
- for (u = 0; u < _META_NAMES_MAX; u++)
- sa_free(s->meta_data[u]);
-
- sa_mutex_free(s->mutex);
sa_free(s);
+
return ret;
}
-/* 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_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); */
+int sa_stream_change_write_latency(sa_stream *s, size_t latency_nbytes, size_t process_time_nbytes) {
+ int ret;
-/* s->write_lower_watermark = size; */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
-/* sa_mutex_unlock(s->mutex); */
+ if ((ret = fix_latency(s, &latency_nbytes, &process_time_nbytes)) < 0)
+ return ret;
-/* return SA_SUCCESS; */
-/* } */
+ sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state != SA_STATE_DEAD, SA_ERROR_STATE, s->mutex);
-/* int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size) { */
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_write_latency(s, &latency_nbytes, &process_time_nbytes);
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, 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->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+ if (ret == SA_SUCCESS) {
+ s->write_latency = latency_nbytes;
+ s->write_process_time = process_time_nbytes;
+ }
-/* s->read_lower_watermark = size; */
+ sa_mutex_unlock(s->mutex);
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ return ret;
+}
-/* int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size) { */
+int sa_stream_change_read_latency(sa_stream *s, size_t latency_nbytes, size_t process_time_nbytes) {
+ int ret;
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, 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->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
-/* s->write_upper_watermark = size; */
+ if ((ret = fix_latency(s, &latency_nbytes, &process_time_nbytes)) < 0)
+ return ret;
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state != SA_STATE_DEAD, SA_ERROR_STATE, s->mutex);
-/* int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size) { */
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_read_latency(s, &latency_nbytes, &process_time_nbytes);
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, 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->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+ if (ret == SA_SUCCESS) {
+ s->read_latency = latency_nbytes;
+ s->read_process_time = process_time_nbytes;
+ }
-/* s->read_upper_watermark = size; */
+ sa_mutex_unlock(s->mutex);
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ return ret;
+}
-int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t *map, unsigned n) {
+int sa_stream_set_channel_map(sa_stream *s, const sa_channel_t *map, unsigned n) {
const sa_channel_t *c;
sa_channel_t *m;
+ int ret;
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 == 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);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
for (c = map; n > 0; c++, n--)
if (*c >= _SA_CHANNEL_MAX) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_INVALID;
+ ret = SA_ERROR_INVALID;
+ goto fail;
}
if (!(m = sa_memdup(map, sizeof(sa_channel_t) * s->pcm_attrs.nchannels))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
sa_free(s->pcm_attrs.channel_map);
s->pcm_attrs.channel_map = m;
+ ret = SA_SUCCESS;
+
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+
+ return ret;
}
-int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode) {
+int sa_stream_set_xrun_mode(sa_stream *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_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_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->xrun_mode = mode;
@@ -283,11 +372,12 @@ int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode) {
return SA_SUCCESS;
}
-int sa_stream_set_non_interleaved(sa_stream_t *s, int enable) {
+int sa_stream_set_non_interleaved(sa_stream *s, int enable) {
sa_return_val_if_fail(s, 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);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_INVALID, s->mutex);
s->ni_enabled = !!enable;
@@ -295,11 +385,12 @@ int sa_stream_set_non_interleaved(sa_stream_t *s, int enable) {
return SA_SUCCESS;
}
-int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable) {
+int sa_stream_set_dynamic_pcm_rate(sa_stream *s, int enable) {
sa_return_val_if_fail(s, 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);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_INVALID, s->mutex);
s->dynamic_rate_enabled = !!enable;
@@ -307,74 +398,63 @@ int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable) {
return SA_SUCCESS;
}
-int sa_stream_set_driver(sa_stream_t *s, const char *driver) {
+int sa_stream_set_driver(sa_stream *s, const char *driver) {
char *d;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(driver, 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_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
- if (!(d = sa_strdup(driver))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ if (!driver)
+ d = NULL;
+ else if (!(d = sa_strdup(driver))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
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_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);
- sa_return_val_if_fail_mutex(s->mutex, !s->callback, SA_ERROR_STATE);
-
- r = driver_start_thread(s, callback);
-
- if (r == SA_SUCCESS)
- s->callback = callback;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return r;
-}
-int sa_stream_stop_thread(sa_stream_t *s) {
- int r;
+ return ret;
+}
+int sa_stream_set_event_callback(sa_stream *s, sa_event_callback_t callback) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- 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);
- sa_return_val_if_fail_mutex(s->mutex, s->callback, SA_ERROR_STATE);
- r = driver_stop_thread(s);
+ sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
- if (r == SA_SUCCESS)
- s->callback = NULL;
+ s->callback = callback;
sa_mutex_unlock(s->mutex);
- return r;
+
+ return SA_SUCCESS;
}
-int sa_stream_change_device(sa_stream_t *s, const char *device_name) {
+int sa_stream_change_device(sa_stream *s, const char *device) {
char *d;
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(device_name, SA_ERROR_INVALID);
-
- if (!(d = sa_strdup(device_name)))
- return SA_ERROR_OOM;
sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state != SA_STATE_DEAD, SA_ERROR_STATE, s->mutex);
- ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_device(s, device_name);
+ if (!device)
+ d = NULL;
+ else if (!(d = sa_strdup(device))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
+ }
+
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_device(s, d);
if (ret == SA_SUCCESS) {
sa_free(s->device);
@@ -382,31 +462,36 @@ int sa_stream_change_device(sa_stream_t *s, const char *device_name) {
} else
sa_free(d);
+fail:
sa_mutex_unlock(s->mutex);
return ret;
}
-int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n) {
+int sa_stream_change_read_volume(sa_stream *s, const int32_t vol[], unsigned n) {
int *v, ret;
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, SA_ERROR_STATE);
+ sa_return_val_if_fail(n == s->pcm_attrs.nchannels || n == 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 (s->pcm_attrs.nchannels == n) {
if (!(v = sa_newdup(int32_t, vol, n))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
} else {
unsigned i;
+ sa_assert_se(n == 1);
+
if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
for (i = 0; i < s->pcm_attrs.nchannels; i++)
@@ -421,30 +506,36 @@ int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n
} else
sa_free(v);
+ ret = SA_SUCCESS;
+
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned n) {
+int sa_stream_change_write_volume(sa_stream *s, const int32_t vol[], unsigned n) {
int *v, ret;
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, SA_ERROR_STATE);
+ sa_return_val_if_fail(n == s->pcm_attrs.nchannels || n == 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 (s->pcm_attrs.nchannels == n) {
if (!(v = sa_newdup(int32_t, vol, n))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
} else {
unsigned i;
if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
for (i = 0; i < s->pcm_attrs.nchannels; i++)
@@ -459,20 +550,23 @@ int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned
} else
sa_free(v);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_change_rate(sa_stream_t *s, unsigned rate) {
+int sa_stream_change_pcm_rate(sa_stream *s, unsigned rate) {
int ret;
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_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);
+ sa_return_val_if_fail_unlock(s->dynamic_rate_enabled || s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
- ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_rate(s, rate);
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_pcm_rate(s, rate);
if (ret == SA_SUCCESS)
s->pcm_attrs.rate = rate;
@@ -481,7 +575,55 @@ int sa_stream_change_rate(sa_stream_t *s, unsigned rate) {
return ret;
}
-int sa_stream_change_user_data(sa_stream_t *s, const void *value) {
+int sa_stream_change_props(sa_stream *s, ...) {
+ va_list ap;
+ int ret;
+ sa_proplist *p = NULL;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+
+ va_start(ap, s);
+ ret = sa_proplist_from_ap(&p, ap);
+ va_end(ap);
+
+ if (ret < 0)
+ return ret;
+
+ ret = sa_stream_change_props_full(s, p);
+
+ sa_assert_se(sa_proplist_destroy(p) == 0);
+
+ return ret;
+}
+
+int sa_stream_change_props_full(sa_stream *s, sa_proplist *p) {
+ int ret;
+ sa_proplist *merged;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+
+ sa_mutex_lock(s->mutex);
+
+ if ((ret = sa_proplist_merge(&merged, s->props, p)) < 0)
+ goto finish;
+
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_props(s, p, merged);
+
+ if (ret == SA_SUCCESS) {
+ sa_assert_se(sa_proplist_destroy(s->props) == SA_SUCCESS);
+ s->props = merged;
+ } else
+ sa_assert_se(sa_proplist_destroy(merged) == SA_SUCCESS);
+
+finish:
+
+ sa_mutex_unlock(s->mutex);
+
+ return ret;
+}
+
+int sa_stream_change_user_data(sa_stream *s, const void *value) {
sa_return_val_if_fail(s->mutex, SA_ERROR_INVALID);
sa_mutex_lock(s->mutex);
@@ -491,11 +633,12 @@ int sa_stream_change_user_data(sa_stream_t *s, const void *value) {
return SA_SUCCESS;
}
-int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction) {
+int sa_stream_set_adjust_rate(sa_stream *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_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);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->adjust_rate = direction;
@@ -503,11 +646,12 @@ int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction) {
return SA_SUCCESS;
}
-int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction) {
+int sa_stream_set_adjust_nchannels(sa_stream *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_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);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->adjust_rate = direction;
@@ -515,11 +659,12 @@ int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction) {
return SA_SUCCESS;
}
-int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction) {
+int sa_stream_set_adjust_pcm_format(sa_stream *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_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);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->adjust_pcm_format = direction;
@@ -527,22 +672,12 @@ int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction) {
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_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 sa_stream_get_state(sa_stream *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);
if (s->state == SA_STATE_INIT) {
*state = s->state;
@@ -554,508 +689,713 @@ int sa_stream_get_state(sa_stream_t *s, sa_state_t *state) {
return ret;
}
-int sa_stream_get_rate(sa_stream_t *s, unsigned *rate) {
+int sa_stream_get_pcm_rate(sa_stream *s, unsigned *rate) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(rate, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*rate = s->pcm_attrs.rate;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels) {
+int sa_stream_get_pcm_nchannels(sa_stream *s, unsigned *nchannels) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(nchannels, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ /* No locking necessary since we only touch immutable fields here */
*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) {
+int sa_stream_get_pcm_format(sa_stream *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_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ /* No locking necessary since we only touch immutable fields here */
*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) {
+int sa_stream_get_mode(sa_stream *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);
+ /* No locking necessary since we only touch immutable fields here */
*access_mode = s->mode;
- sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size) {
- size_t n;
+int sa_stream_get_codec(sa_stream *s, char **codec) {
+ char *t;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || codec), SA_ERROR_INVALID);
+ sa_return_val_if_fail(codec, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec, SA_ERROR_STATE);
+
+ /* No locking necessary since we only touch immutable fields here */
+ if (!(t = sa_strdup(s->codec)))
+ return SA_ERROR_OOM;
+
+ *codec = t;
+ return SA_SUCCESS;
+}
+
+int sa_stream_get_write_latency(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, 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->codec, SA_ERROR_STATE);
- n = strlen(s->codec)+1;
- if (*size < n) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
- }
+ latency = s->write_latency;
+ process_time = s->write_process_time;
- if (codec)
- strcpy(codec, s->codec);
- *size = n;
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
+
+ *nbytes = latency;
+ ret = SA_SUCCESS;
+
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
+}
+
+int sa_stream_get_read_latency(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
+ sa_mutex_lock(s->mutex);
+
+ latency = s->read_latency;
+ process_time = s->read_process_time;
+
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
+
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
+
+ *nbytes = latency;
+ ret = SA_SUCCESS;
+
+fail:
+ sa_mutex_unlock(s->mutex);
+ return ret;
}
-/* 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_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+int sa_stream_get_write_process_time(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
+ sa_mutex_lock(s->mutex);
+
+ latency = s->write_latency;
+ process_time = s->write_process_time;
+
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
+
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
-/* *size = s->write_lower_watermark; */
+ *nbytes = process_time;
+ ret = SA_SUCCESS;
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+fail:
+ sa_mutex_unlock(s->mutex);
+ return ret;
+}
-/* 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_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+int sa_stream_get_read_process_time(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
-/* *size = s->read_lower_watermark; */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ sa_mutex_lock(s->mutex);
-/* 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_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+ latency = s->read_latency;
+ process_time = s->read_process_time;
-/* *size = s->write_upper_watermark; */
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
-/* 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_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+ *nbytes = process_time;
+ ret = SA_SUCCESS;
-/* *size = s->read_upper_watermark; */
+fail:
+ sa_mutex_unlock(s->mutex);
+ return ret;
+}
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+int sa_stream_get_pcm_channel_map(sa_stream *s, sa_channel_t **map, unsigned *n) {
+ sa_channel_t *m;
+ int ret;
-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(n && (*n == 0 || map), SA_ERROR_INVALID);
+ sa_return_val_if_fail(map, SA_ERROR_INVALID);
+ sa_return_val_if_fail(n, 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);
- if (*n < s->pcm_attrs.nchannels) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
+ if (!(m = sa_newdup(sa_channel_t, s->pcm_attrs.channel_map, s->pcm_attrs.nchannels))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (map)
- memcpy(map, s->pcm_attrs.channel_map, s->pcm_attrs.nchannels * sizeof(sa_channel_t));
+ *map = m;
*n = s->pcm_attrs.nchannels;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode) {
+int sa_stream_get_xrun_mode(sa_stream *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);
+ 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) {
+int sa_stream_get_non_interleaved(sa_stream *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);
+ 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) {
+int sa_stream_get_dynamic_pcm_rate(sa_stream *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);
+ sa_mutex_lock(s->mutex);
*enabled = s->dynamic_rate_enabled;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_driver(sa_stream_t *s, char *driver, size_t *size) {
- size_t n;
+int sa_stream_get_driver(sa_stream *s, char **driver) {
+ char *t;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || driver), SA_ERROR_INVALID);
+ sa_return_val_if_fail(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;
+ sa_return_val_if_fail_unlock(s->driver, SA_ERROR_STATE, s->mutex);
+
+ if (!(t = sa_strdup(s->driver))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (driver)
- strcpy(driver, s->driver);
- *size = n;
+ *driver = t;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+
+ return ret;
}
-int sa_stream_get_device(sa_stream_t *s, char *device, size_t *size) {
- size_t n;
+int sa_stream_get_device(sa_stream *s, char **device) {
+ char *t;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || device), SA_ERROR_INVALID);
+ sa_return_val_if_fail(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;
+ sa_return_val_if_fail_unlock(s->device, SA_ERROR_STATE, s->mutex);
+
+ if (!(t = sa_strdup(s->device))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (device)
- strcpy(device, s->device);
- *size = n;
+ *device = t;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+
+ return ret;
}
-int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n) {
+int sa_stream_get_read_volume(sa_stream *s, int32_t **vol, unsigned *n) {
+ int32_t *v;
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(n && (*n == 0 || vol), SA_ERROR_INVALID);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(n, 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);
- 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;
+ sa_return_val_if_fail_unlock(s->read_volume, SA_ERROR_STATE, s->mutex);
+
+ if (!(v = sa_newdup(int32_t, s->read_volume, s->pcm_attrs.nchannels))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (vol)
- memcpy(vol, s->read_volume, s->pcm_attrs.nchannels * sizeof(int32_t));
+ *vol = v;
*n = s->pcm_attrs.nchannels;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n) {
+int sa_stream_get_write_volume(sa_stream *s, int32_t **vol, unsigned *n) {
+ int32_t *v;
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(n && (*n == 0 || vol), SA_ERROR_INVALID);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(n, 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);
- 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;
+ sa_return_val_if_fail_unlock(s->write_volume, SA_ERROR_STATE, s->mutex);
+
+ if (!(v = sa_newdup(int32_t, s->write_volume, s->pcm_attrs.nchannels))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (vol)
- memcpy(vol, s->write_volume, s->pcm_attrs.nchannels * sizeof(int32_t));
+ *vol = v;
*n = s->pcm_attrs.nchannels;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction) {
+int sa_stream_get_adjust_pcm_rate(sa_stream *s, sa_adjust_t *direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(direction, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*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) {
+int sa_stream_get_adjust_pcm_nchannels(sa_stream *s, sa_adjust_t *direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(direction, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*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) {
+int sa_stream_get_adjust_pcm_format(sa_stream *s, sa_adjust_t *direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(direction, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*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_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) {
+int sa_stream_get_user_data(sa_stream *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);
+ 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) {
+int sa_stream_get_event_error(sa_stream *s, int *error) {
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(error, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->event == SA_EVENT_ERROR, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->event == SA_EVENT_ERROR, SA_ERROR_STATE, s->mutex);
*error = s->error;
+fail:
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify) {
+int sa_stream_get_event_notify(sa_stream *s, sa_notify_t *notify, void **data, size_t *data_nbytes) {
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(notify, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->event == SA_EVENT_NOTIFY, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->event == SA_EVENT_NOTIFY, SA_ERROR_STATE, s->mutex);
+
+ if (data && s->notify_data) {
+
+ if (s->notify_data_nbytes > 0) {
+ void *d;
+
+ if (!(d = sa_memdup(s->notify_data, s->notify_data_nbytes))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
+ }
+
+ *data = d;
+ } else
+ *data = s->notify_data;
+ }
+
+ if (data_nbytes && s->notify_data_nbytes)
+ *data_nbytes = s->notify_data_nbytes;
*notify = s->notify;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
+int sa_stream_get_position(sa_stream *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_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);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_get_position(s, position, pos);
+fail:
+ sa_mutex_unlock(s->mutex);
+
+ return ret;
+}
+
+int sa_stream_wait(sa_stream *s, sa_event_t *event) {
+ int ret;
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(event, SA_ERROR_INVALID);
+
+ sa_mutex_lock(s->mutex);
+
+ sa_return_val_if_fail_unlock(!s->callback, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
+
+ ret = driver_wait(s);
+
+ if (ret == SA_SUCCESS)
+ *event = s->event;
+
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes) {
+int sa_stream_read(sa_stream *s, void *data, size_t nbytes) {
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_stream_frame_aligned(s, (int64_t) nbytes), 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->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->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);
+
+ sa_return_val_if_fail_unlock(!s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_read(s, data, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes) {
+int sa_stream_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes) {
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(channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(sa_stream_frame_aligned(s, (int64_t) nbytes), 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->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, 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);
+
+ sa_return_val_if_fail_unlock(s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_read_ni(s, channel, data, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
+int sa_stream_write(sa_stream *s, const void *data, size_t nbytes) {
return sa_stream_pwrite(s, data, nbytes, 0, SA_SEEK_RELATIVE);
}
-int sa_stream_write_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes) {
+int sa_stream_write_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes) {
return sa_stream_pwrite_ni(s, channel, data, nbytes, 0, SA_SEEK_RELATIVE);
}
-int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+int sa_stream_pwrite(sa_stream *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->codec || sa_stream_frame_aligned(s, (int64_t) nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) offset), 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->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);
+
+ sa_return_val_if_fail_unlock(!s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_pwrite(s, data, nbytes, offset, whence);
+fail:
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 sa_stream_pwrite_ni(sa_stream *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(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) offset), 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->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);
+
+ sa_return_val_if_fail_unlock(s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_pwrite_ni(s, channel, data, nbytes, offset, whence);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_get_read_size(sa_stream_t *s, size_t *size) {
+int sa_stream_get_read_size(sa_stream *s, size_t *nbytes) {
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(nbytes, 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);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
- ret = driver_get_read_size(s, size);
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
+
+ ret = driver_get_read_size(s, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
+int sa_stream_get_write_size(sa_stream *s, size_t *nbytes) {
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(nbytes, 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);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
- ret = driver_get_write_size(s, size);
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
+
+ ret = driver_get_write_size(s, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_resume(sa_stream_t *s) {
+int sa_stream_start(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+
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);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_resume(s);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_pause(sa_stream_t *s) {
+int sa_stream_stop(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+
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);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_pause(s);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_drain(sa_stream_t *s) {
+int sa_stream_drain(sa_stream *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_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);
+
+ sa_return_val_if_fail_unlock(!s->callback, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_drain(s);
+fail:
+
sa_mutex_unlock(s->mutex);
+
return ret;
}
@@ -1088,184 +1428,148 @@ size_t sa_get_pcm_sample_size(sa_pcm_format_t f) {
sa_assert_not_reached();
}
-static int meta_check_png(const void *data, size_t size) {
- static const uint8_t png_signature[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
- sa_assert(data);
+const char *sa_strerror(int code) {
+ const char * const error_table[-_SA_ERROR_MAX] = {
+ [-SA_SUCCESS] = "Success",
+ [-SA_ERROR_NOTSUPPORTED] = "Operation not supported",
+ [-SA_ERROR_INVALID] = "Invalid argument",
+ [-SA_ERROR_STATE] = "Invalid state",
+ [-SA_ERROR_OOM] = "Out of memory",
+ [-SA_ERROR_NODRIVER] = "No such driver",
+ [-SA_ERROR_SYSTEM] = "System error",
+ [-SA_ERROR_CORRUPT] = "File or data corrupt",
+ [-SA_ERROR_TOOBIG] = "File or data too large",
+ [-SA_ERROR_NOTFOUND] = "File or data not found",
+ [-SA_ERROR_DESTROYED] = "Destroyed",
+ [-SA_ERROR_CANCELED] = "Canceled",
+ [-SA_ERROR_NOTAVAILABLE] = "Not available",
+ [-SA_ERROR_ACCESS] = "Acess forbidden",
+ [-SA_ERROR_IO] = "IO error",
+ [-SA_ERROR_INTERNAL] = "Internal error",
+ [-SA_ERROR_DISABLED] = "Sound disabled",
+ [-SA_ERROR_NODEVICE] = "No such device",
+ [-SA_ERROR_NOCODEC] = "No such codec",
+ [-SA_ERROR_NOPCMFORMAT] = "No such PCM format"
+ };
- if (size < sizeof(png_signature))
- return 0;
+ sa_return_val_if_fail(code <= 0, NULL);
+ sa_return_val_if_fail(code > _SA_ERROR_MAX, NULL);
- return memcmp(data, png_signature, 8) == 0;
+ return error_table[-code];
}
-static int meta_check_utf8(const void *data, size_t size) {
- int32_t idx;
-
- oil_utf8_validate(&idx, data, size);
-
- return (size_t) idx == size;
+float volume_to_dB(int32_t v) {
+ return (float) v / 100.0f;
}
-static int meta_check_pid(const void *data, size_t size) {
- long int pid;
- char *t;
-
- if (size <= 0)
- return 0;
+int32_t volume_from_dB(float dB) {
+ return (int32_t) lrintf(dB * 100.0f);
+}
- if (memchr(data, 0, size))
- return 0;
+float volume_to_linear(int32_t v) {
- if (!(t = sa_strndup(data, size)))
+ if (v <= SA_VOLUME_MUTED)
return 0;
- errno = 0;
- pid = strtol(t, NULL, 10);
- sa_free(t);
+ return powf(10.0f, volume_to_dB(v) / 20.0f);
+}
- if (errno != 0)
- return 0;
+int32_t volume_from_linear(float f) {
- if (pid <= 1)
- return 0;
+ if (f <= 0)
+ return SA_VOLUME_MUTED;
- return 1;
+ return volume_from_dB(20.0f * log10f(f));
}
-static int meta_check_icon_name(const void *data, size_t size) {
- const char *t = data;
+unsigned sa_stream_bytes_to_frames(sa_stream *s, size_t nbytes, sa_bool_t round_up) {
+ sa_return_val_if_fail(s, (unsigned) -1);
+ sa_return_val_if_fail(!s->codec, (unsigned) -1);
- if (size <= 0)
- return 0;
+ /* We don't lock here since the data we access here is immutable */
- if (memchr(data, 0, size))
- return 0;
+ if (round_up)
+ nbytes += s->pcm_frame_size - 1U;
- if (size == 1 && t[0] == '.')
- return 0;
+ return (unsigned) (nbytes / s->pcm_frame_size);
+}
- if (size == 2 && t[0] == '.' && t[1] == '.')
- return 0;
+size_t sa_stream_frames_to_bytes(sa_stream *s, unsigned nframes) {
+ sa_return_val_if_fail(s, (size_t) -1);
+ sa_return_val_if_fail(!s->codec, (size_t) -1);
- if (memchr(t, '/', size))
- return 0;
+ /* We don't lock here since the data we access here is immutable */
- return 1;
+ return (size_t) nframes * s->pcm_frame_size;
}
-static int meta_check_word(const void *data, size_t size) {
- const char *t = data;
+uint64_t sa_stream_bytes_to_usec(sa_stream *s, size_t nbytes, sa_bool_t round_up) {
+ unsigned nframes;
+
+ sa_return_val_if_fail(s, (uint64_t) -1);
+ sa_return_val_if_fail(!s->codec, (uint64_t) -1);
- for (; size > 0; size --, t++)
- if (*t <= 32 || *t >= 127)
- return 0;
+ /* We don't lock here since the data we access here is immutable */
- return 1;
+ nframes = sa_stream_bytes_to_frames(s, nbytes, round_up);
+ return sa_stream_frames_to_usec(s, nframes, round_up);
}
-typedef int (*meta_check_func_t)(const void *data, size_t size);
+size_t sa_stream_usec_to_bytes(sa_stream *s, uint64_t usec, sa_bool_t round_up) {
+ unsigned nframes;
-int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size) {
- void *d = NULL;
- const struct meta_name *m;
- int ret;
+ sa_return_val_if_fail(s, (size_t) -1);
+ sa_return_val_if_fail(!s->codec, (size_t) -1);
- static const meta_check_func_t check_table[] = {
- meta_check_utf8,
- meta_check_pid,
- meta_check_word, /* FIXME */
- meta_check_utf8,
- meta_check_icon_name,
- meta_check_png,
- meta_check_word, /* FIXME */
- meta_check_word, /* FIXME */
- };
+ /* We don't lock here since the data we access here is immutable */
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(name, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, data || size == 0, SA_ERROR_INVALID);
+ nframes = sa_stream_usec_to_frames(s, usec, round_up);
+ return sa_stream_frames_to_bytes(s, nframes);
+}
- if (!(m = sa_lookup_meta_name(name, strlen(name)))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_META;
- }
+uint64_t sa_stream_frames_to_usec(sa_stream *s, unsigned nframes, sa_bool_t round_up) {
+ uint64_t u;
+ sa_return_val_if_fail(s, (uint64_t) -1);
+ sa_return_val_if_fail(!s->codec, (uint64_t) -1);
- if (!check_table[m->idx](data, size)) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_INVALID;
- }
+ u = (uint64_t) nframes;
+ u *= 1000000LLU;
- if (data)
- if (!(d = sa_memdup(data, size))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
- }
+ sa_mutex_lock(s->mutex);
- ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_meta_data(s, name, data, size);
+ if (round_up)
+ u += (uint64_t) s->pcm_attrs.rate - 1LLU;
- if (ret == SA_SUCCESS) {
- sa_free(s->meta_data[m->idx]);
- s->meta_data[m->idx] = d;
- s->meta_data_size[m->idx] = size;
- } else
- sa_free(d);
+ u /= (uint64_t) s->pcm_attrs.rate;
sa_mutex_unlock(s->mutex);
- return ret;
+
+ return u;
}
-int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void *data, size_t *size) {
- const struct meta_name *m;
+unsigned sa_stream_usec_to_frames(sa_stream *s, uint64_t usec, sa_bool_t round_up) {
+ sa_return_val_if_fail(s, (unsigned) -1);
+ sa_return_val_if_fail(!s->codec, (unsigned) -1);
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(name, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || data), SA_ERROR_INVALID);
sa_mutex_lock(s->mutex);
- if (!(m = sa_lookup_meta_name(name, strlen(name)))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_META;
- }
-
- if (!s->meta_data[m->idx]) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_DATA;
- }
+ usec *= (uint64_t) s->pcm_attrs.rate;
- if (*size < s->meta_data_size[m->idx]) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
- }
+ sa_mutex_unlock(s->mutex);
- if (data)
- memcpy(data, s->meta_data[m->idx], s->meta_data_size[m->idx]);
+ if (round_up)
+ usec += 999999LLU;
- *size = s->meta_data_size[m->idx];
+ usec /= 1000000LLU;
- sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return (unsigned) usec;
}
-const char *sa_strerror(int code) {
- const char * const error_table[-_SA_ERROR_MAX] = {
- [-SA_SUCCESS] = "Success",
- [-SA_ERROR_NOT_SUPPORTED] = "Operation not supported",
- [-SA_ERROR_INVALID] = "Invalid argument",
- [-SA_ERROR_STATE] = "Invalid state",
- [-SA_ERROR_OOM] = "Out of memory",
- [-SA_ERROR_NO_DEVICE] = "No such device",
- [-SA_ERROR_NO_DRIVER] = "No such driver",
- [-SA_ERROR_NO_CODEC] = "No such codec",
- [-SA_ERROR_NO_PCM_FORMAT] = "No such PCM format",
- [-SA_ERROR_SYSTEM] = "System error",
- [-SA_ERROR_NO_INIT] = "Not initialized",
- [-SA_ERROR_NO_META] = "No such meta name",
- [-SA_ERROR_NO_DATA] = "No such data"
- };
+sa_bool_t sa_stream_frame_aligned(sa_stream *s, int64_t nbytes) {
+ sa_return_val_if_fail(s, FALSE);
+ sa_return_val_if_fail(!s->codec, FALSE);
- sa_return_val_if_fail(code <= 0, NULL);
- sa_return_val_if_fail(code > _SA_ERROR_MAX, NULL);
+ /* We don't lock here since the data we access here is immutable */
- return error_table[-code];
+ return (nbytes % (int64_t) s->pcm_frame_size) == 0;
}