From a64e85acf96bc0c55363fe55c9e9116aef2a8584 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 May 2007 23:38:38 +0000 Subject: resampling works git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@4 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- common.c | 450 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 322 insertions(+), 128 deletions(-) (limited to 'common.c') diff --git a/common.c b/common.c index b7a92d7..ea9858c 100644 --- a/common.c +++ b/common.c @@ -1,40 +1,135 @@ +#include +#include +#include + #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]; } -- cgit