summaryrefslogtreecommitdiffstats
path: root/common.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-04-25 10:27:13 +0000
committerLennart Poettering <lennart@poettering.net>2007-04-25 10:27:13 +0000
commit2eb6dec8e9f0114bdbad59cf8f11f197f8fdaaf3 (patch)
tree88a2b13b2fc9abdd9fa43136d4ed91bdc084d929 /common.c
parent130f9f7046eec89f7674cad7f66c831fa8d0127d (diff)
initial commit
git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@3 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce
Diffstat (limited to 'common.c')
-rw-r--r--common.c523
1 files changed, 523 insertions, 0 deletions
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..b7a92d7
--- /dev/null
+++ b/common.c
@@ -0,0 +1,523 @@
+#include "sydney.h"
+#include "macro.h"
+#include "malloc.h"
+#include "common.h"
+#include "driver.h"
+
+int sa_device_create_opaque(sa_device_t **dev, const char *client_name, sa_mode_t mode, const char *codec) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(client_name, 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);
+
+ return device_create_opaque(dev, client_name, mode, codec);
+}
+
+int sa_device_create_pcm(sa_device_t **dev, const char *client_name, sa_mode_t mode, sa_pcm_format_t format, unsigned rate, unsigned channels) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(client_name, 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(format < SA_PCM_FORMAT_MAX, SA_ERROR_INVALID);
+ sa_return_val_if_fail(rate > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(channels > 0, SA_ERROR_INVALID);
+
+ return device_create_pcm(dev, client_name, mode, format, rate, channels);
+}
+
+int sa_device_open(sa_device_t *dev) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ return device_open(dev);
+}
+
+int sa_device_destroy(sa_device_t *dev) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+
+ return device_destroy(dev);
+}
+
+int sa_device_set_write_lower_watermark(sa_device_t *dev, size_t size) {
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(size > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->write_lower_watermark = size;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_read_lower_watermark(sa_device_t *dev, size_t size) {
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(size > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->read_lower_watermark = size;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_write_upper_watermark(sa_device_t *dev, size_t size) {
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(size > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->write_upper_watermark = size;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_read_upper_watermark(sa_device_t *dev, size_t size) {
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(size > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->read_upper_watermark = size;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_channel_map(sa_device_t *dev, const sa_channel_t *map) {
+ const sa_channel_t *c;
+ sa_channel_t *m;
+ unsigned n;
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(map, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+
+ for (c = map, n = dev->nchannels; n > 0; c++, n--)
+ if (*c >= SA_CHANNEL_MAX)
+ return SA_ERROR_INVALID;
+
+ if (!(m = sa_memdup(map, sizeof(sa_channel_t) * dev->nchannels)))
+ return SA_ERROR_OOM;
+
+ sa_free(dev->channel_map);
+ dev->channel_map = m;
+
+ return SA_SUCCESS;
+}
+
+int sa_device_set_xrun_mode(sa_device_t *dev, sa_xrun_mode_t mode) {
+ sa_return_val_if_fail(dev, 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(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->xrun_mode = mode;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_ni(sa_device_t *dev, int enable) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+
+ dev->ni_enabled = !!enable;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_dsr(sa_device_t *dev, int enable) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+
+ dev->dsr_enabled = !!enable;
+ return SA_SUCCESS;
+}
+
+int sa_device_set_driver(sa_device_t *dev, const char *driver) {
+ char *d;
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(driver, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ if (!(d = sa_strdup(driver)))
+ return SA_ERROR_OOM;
+
+ sa_free(dev->driver);
+ dev->driver = d;
+
+ return SA_SUCCESS;
+}
+
+int sa_device_start_thread(sa_device_t *dev, sa_event_callback_t *callback) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(callback, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ return device_start_thread(dev, callback);
+}
+
+int sa_device_change_device(sa_device_t *dev, const char *device_name) {
+ char *d;
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(device_name, SA_ERROR_INVALID);
+
+ if (dev->state == SA_STATE_INIT) {
+ if (!(d = sa_strdup(device_name)))
+ return SA_ERROR_OOM;
+
+ sa_free(dev->device);
+ dev->device = d;
+
+ return SA_SUCCESS;
+ }
+
+ return device_change_device(dev, device_name);
+}
+
+int sa_device_change_input_volume(sa_device_t *dev, int *vol) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+
+ if (dev->state == SA_STATE_INIT) {
+ dev->input_volume = *vol;
+ return SA_SUCCESS;
+ }
+
+ return device_change_input_volume(dev, vol);
+}
+
+int sa_device_change_output_volume(sa_device_t *dev, int *vol) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+
+ if (dev->state == SA_STATE_INIT) {
+ dev->output_volume = *vol;
+ return SA_SUCCESS;
+ }
+
+ return device_change_output_volume(dev, vol);
+}
+
+int sa_device_change_sampling_rate(sa_device_t *dev, unsigned rate) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(rate > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->dsr_enabled || dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ if (dev->state == SA_STATE_INIT) {
+ dev->rate = rate;
+ return SA_SUCCESS;
+ }
+
+ return device_change_sampling_rate(dev, rate);
+}
+
+int sa_device_change_client_name(sa_device_t *dev, const char *client_name) {
+ char *n;
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(client_name, SA_ERROR_INVALID);
+
+ if (dev->state == SA_STATE_INIT) {
+ if (!(n = sa_strdup(client_name)))
+ return SA_ERROR_OOM;
+
+ sa_free(dev->client_name);
+ dev->client_name = n;
+
+ return SA_SUCCESS;
+ }
+
+ return device_change_client_name(dev, client_name);
+}
+
+int sa_device_change_stream_name(sa_device_t *dev, const char *stream_name) {
+ char *n;
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(stream_name, SA_ERROR_INVALID);
+
+ if (dev->state == SA_STATE_INIT) {
+ if (!(n = sa_strdup(stream_name)))
+ return SA_ERROR_OOM;
+
+ sa_free(dev->stream_name);
+ dev->stream_name = n;
+
+ return SA_SUCCESS;
+ }
+
+ return device_change_stream_name(dev, stream_name);
+}
+
+int sa_device_change_user_data(sa_device_t *dev, void *value) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+
+ dev->user_data = value;
+ return SA_SUCCESS;
+}
+
+int sa_device_adjust_rate(sa_device_t *dev, sa_adjust_t direction) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->adjust_rate = direction;
+ return SA_SUCCESS;
+}
+
+int sa_device_adjust_nchannels(sa_device_t *dev, sa_adjust_t direction) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->adjust_rate = direction;
+ return SA_SUCCESS;
+}
+
+int sa_device_adjust_pcm_format(sa_device_t *dev, sa_adjust_t direction) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_INIT, SA_ERROR_STATE);
+
+ dev->adjust_pcm_format = direction;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_state(sa_device_t *dev, sa_state_t *state) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(state, SA_ERROR_INVALID);
+
+ return device_get_state(dev, state);
+}
+
+int sa_device_get_sampling_rate(sa_device_t *dev, unsigned *rate) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(rate, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+
+ *rate = dev->rate;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_nchannels(sa_device_t *dev, int *nchannels) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+
+ *nchannels = dev->nchannels;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_pcm_format(sa_device_t *dev, sa_pcm_format_t *pcm_format) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(pcm_format, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
+
+ *pcm_format = dev->pcm_format;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_user_data(sa_device_t *dev, void **value) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(value, SA_ERROR_INVALID);
+
+ *value = dev->user_data;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_event_error(sa_device_t *dev, sa_error_t *error) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(error, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->event == SA_EVENT_ERROR, SA_ERROR_STATE);
+
+ *error = dev->error;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_event_notify(sa_device_t *dev, sa_notify_t *notify) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(notify, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->event == SA_EVENT_NOTIFY, SA_ERROR_STATE);
+
+ *notify = dev->notify;
+ return SA_SUCCESS;
+}
+
+int sa_device_get_position(sa_device_t *dev, sa_position_t position, int64_t *pos) {
+ sa_return_val_if_fail(dev, 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(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_get_position(dev, position, pos);
+}
+
+int sa_device_read(sa_device_t *dev, void *data, size_t nbytes) {
+ return sa_device_pread(dev, data, nbytes, 0, SA_SEEK_RELATIVE);
+}
+
+int sa_device_write(sa_device_t *dev, const void *data, size_t nbytes) {
+ return sa_device_pwrite(dev, data, nbytes, 0, SA_SEEK_RELATIVE);
+}
+
+int sa_device_read_ni(sa_device_t *dev, unsigned channel, void *data, size_t nbytes) {
+ return sa_device_pread_ni(dev, channel, data, nbytes, 0, SA_SEEK_RELATIVE);
+}
+
+int sa_device_write_ni(sa_device_t *dev, unsigned channel, const void *data, size_t nbytes) {
+ return sa_device_pwrite_ni(dev, channel, data, nbytes, 0, SA_SEEK_RELATIVE);
+}
+
+int sa_device_pread(sa_device_t *dev, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ sa_return_val_if_fail(dev, 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(!dev->ni_enabled, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_pread(dev, data, nbytes, offset, whence);
+}
+
+int sa_device_pwrite(sa_device_t *dev, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ sa_return_val_if_fail(dev, 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(!dev->ni_enabled, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_pwrite(dev, data, nbytes, offset, whence);
+}
+
+int sa_device_pread_ni(sa_device_t *dev, unsigned channel, void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ sa_return_val_if_fail(dev, 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(channel < dev->nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->ni_enabled, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_pread_ni(dev, channel, data, nbytes, offset, whence);
+}
+
+int sa_device_pwrite_ni(sa_device_t *dev, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ sa_return_val_if_fail(dev, 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(channel < dev->nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->ni_enabled, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_pwrite_ni(dev, channel, data, nbytes, offset, whence);
+}
+
+int sa_device_get_read_size(sa_device_t *dev, size_t *size) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(size, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_get_read_size(dev, size);
+}
+
+int sa_device_get_write_size(sa_device_t *dev, size_t *size) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(size, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_get_write_size(dev, size);
+}
+
+int sa_device_resume(sa_device_t *dev) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_resume(dev);
+}
+
+int sa_device_pause(sa_device_t *dev) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_pause(dev);
+}
+
+int sa_device_drain(sa_device_t *dev) {
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->state == SA_STATE_RUNNING || dev->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ return device_drain(dev);
+}
+
+sa_device_t *device_alloc(size_t total) {
+ sa_device_t *d;
+
+ sa_assert(total >= sizeof(sa_device_t));
+
+ if (!(d = sa_malloc0(total)))
+ return NULL;
+
+ /* All fields a carefully chosen in a way that initializing them
+ * NUL bytes is sufficient */
+
+ return d;
+}
+
+void device_free(sa_device_t *d) {
+ sa_free(d->codec);
+ sa_free(d->driver);
+ sa_free(d->device);
+ sa_free(d->channel_map);
+ sa_free(d->client_name);
+ sa_free(d->stream_name);
+ sa_free(d);
+}
+
+int device_alloc_opaque(sa_device_t **dev, size_t total, const char *client_name, sa_mode_t mode, const char *codec) {
+ int error;
+
+ if (!(*dev = device_alloc(total)))
+ return SA_ERROR_OOM;
+
+ (*dev)->mode = mode;
+
+ if (!((*dev)->codec = sa_strdup(codec))) {
+ device_free(*dev);
+ return SA_ERROR_OOM;
+ }
+
+ if ((error = sa_device_change_client_name(*dev, client_name))) {
+ device_free(*dev);
+ return error;
+ }
+
+ return SA_SUCCESS;
+}
+
+int device_alloc_pcm(sa_device_t **dev, size_t total, const char *client_name, sa_mode_t mode, sa_pcm_format_t format, unsigned rate, unsigned nchannels) {
+ int error;
+
+ if (!(*dev = device_alloc(total)))
+ return SA_ERROR_OOM;
+
+ (*dev)->mode = mode;
+ (*dev)->pcm_format = format;
+ (*dev)->nchannels = nchannels;
+
+ if ((error = sa_device_change_sampling_rate(*dev, rate))) {
+ device_free(*dev);
+ return error;
+ }
+
+ if ((error = sa_device_change_client_name(*dev, client_name))) {
+ device_free(*dev);
+ return error;
+ }
+
+ return SA_SUCCESS;
+}