summaryrefslogtreecommitdiffstats
path: root/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'common.c')
-rw-r--r--common.c450
1 files changed, 322 insertions, 128 deletions
diff --git a/common.c b/common.c
index b7a92d7..ea9858c 100644
--- a/common.c
+++ b/common.c
@@ -1,40 +1,135 @@
+#include <string.h>
+#include <errno.h>
+#include <liboil/liboil.h>
+
#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) {
+/* contains code */
+#include "meta-name-table.h"
+
+static sa_device_t *device_alloc(void) {
+ sa_device_t *d;
+
+ if (!(d = sa_new0(sa_device_t, 1)))
+ return NULL;
+
+ /* All fields a carefully chosen in a way that initializing them
+ * NUL bytes is sufficient */
+
+ return d;
+}
+
+int sa_device_create_opaque(
+ sa_device_t **dev,
+ sa_mode_t mode,
+ const char *codec) {
+
+ int error;
+
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);
+ if (!(*dev = device_alloc()))
+ return SA_ERROR_OOM;
+
+ (*dev)->mode = mode;
+
+ if (!((*dev)->codec = sa_strdup(codec))) {
+ error = SA_ERROR_OOM;
+ goto fail;
+ }
+
+ oil_init();
+
+ return SA_SUCCESS;
+
+fail:
+ sa_device_destroy(*dev);
+ return error;
}
-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) {
+int sa_device_create_pcm(
+ sa_device_t **dev,
+ sa_mode_t mode,
+ sa_pcm_format_t format,
+ unsigned rate,
+ unsigned nchannels) {
+
+ int ret;
+
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);
+ sa_return_val_if_fail(nchannels > 0, SA_ERROR_INVALID);
+
+ if (!(*dev = device_alloc()))
+ return SA_ERROR_OOM;
+
+ (*dev)->mode = mode;
+ (*dev)->pcm_attrs.format = format;
+ (*dev)->pcm_attrs.nchannels = nchannels;
+ (*dev)->pcm_sample_size = get_pcm_sample_size(format);
+ (*dev)->pcm_frame_size = (*dev)->pcm_sample_size * nchannels;
+
+ 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 };
- return device_create_pcm(dev, client_name, mode, format, rate, channels);
+ if ((ret = sa_device_set_channel_map(*dev, nchannels == 2 ? map_stereo : map_mono)))
+ goto fail;
+ }
+
+ if ((ret = sa_device_change_rate(*dev, rate)))
+ goto fail;
+
+ oil_init();
+
+ return SA_SUCCESS;
+
+fail:
+
+ sa_device_destroy(*dev);
+ return ret;
}
int sa_device_open(sa_device_t *dev) {
+ int ret;
+
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);
+ if ((ret = device_open(dev)) == 0)
+ dev->state = SA_STATE_STOPPED;
+
+ return ret;
}
int sa_device_destroy(sa_device_t *dev) {
+ int ret;
+ unsigned u;
+
sa_return_val_if_fail(dev, SA_ERROR_INVALID);
- return device_destroy(dev);
+ ret = device_destroy(dev);
+
+ sa_free(dev->codec);
+ sa_free(dev->driver);
+ sa_free(dev->device);
+ sa_free(dev->pcm_attrs.channel_map);
+ sa_free(dev->input_volume);
+ sa_free(dev->output_volume);
+
+ for (u = 0; u < META_NAMES_MAX; u++)
+ sa_free(dev->meta_data[u]);
+
+ sa_free(dev);
+ return ret;
}
int sa_device_set_write_lower_watermark(sa_device_t *dev, size_t size) {
@@ -87,15 +182,15 @@ int sa_device_set_channel_map(sa_device_t *dev, const sa_channel_t *map) {
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--)
+ for (c = map, n = dev->pcm_attrs.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)))
+ if (!(m = sa_memdup(map, sizeof(sa_channel_t) * dev->pcm_attrs.nchannels)))
return SA_ERROR_OOM;
- sa_free(dev->channel_map);
- dev->channel_map = m;
+ sa_free(dev->pcm_attrs.channel_map);
+ dev->pcm_attrs.channel_map = m;
return SA_SUCCESS;
}
@@ -118,12 +213,12 @@ int sa_device_set_ni(sa_device_t *dev, int enable) {
return SA_SUCCESS;
}
-int sa_device_set_dsr(sa_device_t *dev, int enable) {
+int sa_device_set_dynamic_rate(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;
+ dev->dynamic_rate_enabled = !!enable;
return SA_SUCCESS;
}
@@ -147,103 +242,90 @@ 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);
+ sa_return_val_if_fail(dev->codec || dev->pcm_attrs.channel_map, SA_ERROR_NO_INIT);
return device_start_thread(dev, callback);
}
int sa_device_change_device(sa_device_t *dev, const char *device_name) {
char *d;
+ int ret;
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;
+ if (!(d = sa_strdup(device_name)))
+ return SA_ERROR_OOM;
+ ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_device(dev, device_name);
+
+ if (ret == SA_SUCCESS) {
sa_free(dev->device);
dev->device = d;
+ } else
+ sa_free(d);
- return SA_SUCCESS;
- }
-
- return device_change_device(dev, device_name);
+ return ret;
}
-int sa_device_change_input_volume(sa_device_t *dev, int *vol) {
+int sa_device_change_input_volume(sa_device_t *dev, const int vol[]) {
+ int *v, ret;
+
sa_return_val_if_fail(dev, SA_ERROR_INVALID);
sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_NOT_SUPPORTED);
+ sa_return_val_if_fail(dev->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
- if (dev->state == SA_STATE_INIT) {
- dev->input_volume = *vol;
- return SA_SUCCESS;
- }
+ if (!(v = sa_newdup(vol, int, dev->pcm_attrs.nchannels)))
+ return SA_ERROR_OOM;
- return device_change_input_volume(dev, vol);
-}
+ ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_input_volume(dev, v);
-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;
- }
+ if (ret == SA_SUCCESS) {
+ sa_free(dev->input_volume);
+ dev->input_volume = v;
+ } else
+ sa_free(v);
- return device_change_output_volume(dev, vol);
+ return ret;
}
-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);
+int sa_device_change_output_volume(sa_device_t *dev, const int vol[]) {
+ int *v, ret;
- 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);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!dev->codec, SA_ERROR_NOT_SUPPORTED);
+ sa_return_val_if_fail(dev->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- if (dev->state == SA_STATE_INIT) {
- if (!(n = sa_strdup(client_name)))
- return SA_ERROR_OOM;
+ if (!(v = sa_newdup(vol, int, dev->pcm_attrs.nchannels)))
+ return SA_ERROR_OOM;
- sa_free(dev->client_name);
- dev->client_name = n;
+ ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_output_volume(dev, v);
- return SA_SUCCESS;
- }
-
- return device_change_client_name(dev, client_name);
+ if (ret == SA_SUCCESS) {
+ sa_free(dev->output_volume);
+ dev->output_volume = v;
+ } else
+ sa_free(v);
+
+ return ret;
}
-int sa_device_change_stream_name(sa_device_t *dev, const char *stream_name) {
- char *n;
+int sa_device_change_rate(sa_device_t *dev, unsigned rate) {
+ int ret;
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_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->dynamic_rate_enabled || dev->state == SA_STATE_INIT, SA_ERROR_STATE);
- sa_free(dev->stream_name);
- dev->stream_name = n;
+ ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_rate(dev, rate);
- return SA_SUCCESS;
- }
+ if (ret == SA_SUCCESS)
+ dev->pcm_attrs.rate = rate;
- return device_change_stream_name(dev, stream_name);
+ return ret;
}
int sa_device_change_user_data(sa_device_t *dev, void *value) {
@@ -287,12 +369,12 @@ int sa_device_get_state(sa_device_t *dev, sa_state_t *state) {
return device_get_state(dev, state);
}
-int sa_device_get_sampling_rate(sa_device_t *dev, unsigned *rate) {
+int sa_device_get_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;
+ *rate = dev->pcm_attrs.rate;
return SA_SUCCESS;
}
@@ -301,7 +383,7 @@ int sa_device_get_nchannels(sa_device_t *dev, int *nchannels) {
sa_return_val_if_fail(nchannels, SA_ERROR_INVALID);
sa_return_val_if_fail(!dev->codec, SA_ERROR_STATE);
- *nchannels = dev->nchannels;
+ *nchannels = dev->pcm_attrs.nchannels;
return SA_SUCCESS;
}
@@ -310,7 +392,7 @@ int sa_device_get_pcm_format(sa_device_t *dev, sa_pcm_format_t *pcm_format) {
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;
+ *pcm_format = dev->pcm_attrs.format;
return SA_SUCCESS;
}
@@ -371,6 +453,8 @@ int sa_device_pread(sa_device_t *dev, void *data, size_t nbytes, int64_t offset,
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->codec || (nbytes % dev->pcm_frame_size) == 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->codec || (offset % dev->pcm_frame_size) == 0, 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);
@@ -383,6 +467,8 @@ int sa_device_pwrite(sa_device_t *dev, const void *data, size_t nbytes, int64_t
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->codec || (nbytes % dev->pcm_frame_size) == 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(dev->codec || (offset % dev->pcm_frame_size) == 0, 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);
@@ -393,9 +479,12 @@ int sa_device_pread_ni(sa_device_t *dev, unsigned channel, void *data, size_t nb
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(!dev->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 < dev->nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(channel < dev->pcm_attrs.nchannels, SA_ERROR_INVALID);
sa_return_val_if_fail(dev->ni_enabled, SA_ERROR_STATE);
+ sa_return_val_if_fail((nbytes % dev->pcm_sample_size) == 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail((offset % dev->pcm_sample_size) == 0, 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);
@@ -406,9 +495,12 @@ int sa_device_pwrite_ni(sa_device_t *dev, unsigned channel, const void *data, si
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(!dev->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 < dev->nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(channel < dev->pcm_attrs.nchannels, SA_ERROR_INVALID);
sa_return_val_if_fail(dev->ni_enabled, SA_ERROR_STATE);
+ sa_return_val_if_fail((nbytes % dev->pcm_sample_size) == 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail((offset % dev->pcm_sample_size) == 0, 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);
@@ -449,75 +541,177 @@ int sa_device_pause(sa_device_t *dev) {
int sa_device_drain(sa_device_t *dev) {
sa_return_val_if_fail(dev, 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_drain(dev);
}
-sa_device_t *device_alloc(size_t total) {
- sa_device_t *d;
+size_t get_pcm_sample_size(sa_pcm_format_t f) {
+
+ switch (f) {
+ case SA_PCM_FORMAT_U8:
+ case SA_PCM_FORMAT_ULAW:
+ case SA_PCM_FORMAT_ALAW:
+ return 1;
+
+ case SA_PCM_FORMAT_S16_LE:
+ case SA_PCM_FORMAT_S16_BE:
+ return 2;
+ case SA_PCM_FORMAT_S24_LE:
+ case SA_PCM_FORMAT_S24_BE:
+ return 3;
+
+ case SA_PCM_FORMAT_S32_LE:
+ case SA_PCM_FORMAT_S32_BE:
+ case SA_PCM_FORMAT_FLOAT32_LE:
+ case SA_PCM_FORMAT_FLOAT32_BE:
+ return 4;
+
+ case SA_PCM_FORMAT_MAX:
+ ;
+ }
- sa_assert(total >= sizeof(sa_device_t));
+ sa_assert_not_reached();
+}
- if (!(d = sa_malloc0(total)))
- return NULL;
+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);
- /* All fields a carefully chosen in a way that initializing them
- * NUL bytes is sufficient */
+ if (size < sizeof(png_signature))
+ return 0;
- return d;
+ return memcmp(data, png_signature, 8) == 0;
}
-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);
+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;
}
-int device_alloc_opaque(sa_device_t **dev, size_t total, const char *client_name, sa_mode_t mode, const char *codec) {
- int error;
+static int meta_check_pid(const void *data, size_t size) {
+ long int pid;
+ char *t;
+
+ if (size <= 0)
+ return 0;
+
+ if (memchr(data, 0, size))
+ return 0;
- if (!(*dev = device_alloc(total)))
- return SA_ERROR_OOM;
+ if (!(t = sa_strndup(data, size)))
+ return 0;
+
+ errno = 0;
+ pid = strtol(t, NULL, 10);
+ sa_free(t);
+
+ if (errno != 0)
+ return 0;
- (*dev)->mode = mode;
+ if (pid <= 1)
+ return 0;
- if (!((*dev)->codec = sa_strdup(codec))) {
- device_free(*dev);
- return SA_ERROR_OOM;
- }
+ return 1;
+}
- if ((error = sa_device_change_client_name(*dev, client_name))) {
- device_free(*dev);
- return error;
- }
+static int meta_check_icon_name(const void *data, size_t size) {
+ const char *t = data;
+
+ if (size <= 0)
+ return 0;
+
+ if (memchr(data, 0, size))
+ return 0;
- return SA_SUCCESS;
+ if (size == 1 && t[0] == '.')
+ return 0;
+
+ if (size == 2 && t[0] == '.' && t[1] == '.')
+ return 0;
+
+ if (memchr(t, '/', size))
+ return 0;
+
+ return 1;
}
-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;
+static int meta_check_word(const void *data, size_t size) {
+ const char *t = data;
+
+ for (; size > 0; size --, t++)
+ if (*t <= 32 || *t >= 127)
+ return 0;
- if (!(*dev = device_alloc(total)))
- return SA_ERROR_OOM;
+ return 1;
+}
- (*dev)->mode = mode;
- (*dev)->pcm_format = format;
- (*dev)->nchannels = nchannels;
+typedef int (*meta_check_func_t)(const void *data, size_t size);
- if ((error = sa_device_change_sampling_rate(*dev, rate))) {
- device_free(*dev);
- return error;
- }
+int sa_device_change_meta_data(sa_device_t *dev, const char *name, const void *data, size_t size) {
+ void *d = NULL;
+ const struct meta_name *m;
+ int ret;
- if ((error = sa_device_change_client_name(*dev, client_name))) {
- device_free(*dev);
- return error;
- }
+ 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 */
+ };
+
+ sa_return_val_if_fail(dev, SA_ERROR_INVALID);
+ sa_return_val_if_fail(name, SA_ERROR_INVALID);
+ sa_return_val_if_fail(data || size == 0, SA_ERROR_INVALID);
- return SA_SUCCESS;
+ if (!(m = lookup_meta_name(name, strlen(name))))
+ return SA_ERROR_NO_META;
+
+ if (!check_table[m->idx](data, size))
+ return SA_ERROR_INVALID;
+
+ if (data)
+ if (!(d = sa_memdup(data, size)))
+ return SA_ERROR_OOM;
+
+ ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_meta_data(dev, name, data, size);
+
+ if (ret == SA_SUCCESS) {
+ sa_free(dev->meta_data[m->idx]);
+ dev->meta_data[m->idx] = d;
+ dev->meta_data_size[m->idx] = size;
+ }
+
+ return ret;
+}
+
+
+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_assert(code <= 0);
+ sa_assert(code > SA_ERROR_MAX);
+
+ return error_table[-code];
}