#include #include #include #include "sydney.h" #include "macro.h" #include "malloc.h" #include "common.h" #include "driver.h" /* 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(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 (!(*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, 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(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(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 }; 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); 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); 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) { 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->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->pcm_attrs.nchannels))) return SA_ERROR_OOM; sa_free(dev->pcm_attrs.channel_map); dev->pcm_attrs.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_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->dynamic_rate_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); 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 (!(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 ret; } 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 (!(v = sa_newdup(vol, int, dev->pcm_attrs.nchannels))) return SA_ERROR_OOM; ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_input_volume(dev, v); if (ret == SA_SUCCESS) { sa_free(dev->input_volume); dev->input_volume = v; } else sa_free(v); return ret; } int sa_device_change_output_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_WRONLY, SA_ERROR_STATE); if (!(v = sa_newdup(vol, int, dev->pcm_attrs.nchannels))) return SA_ERROR_OOM; ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_output_volume(dev, v); if (ret == SA_SUCCESS) { sa_free(dev->output_volume); dev->output_volume = v; } else sa_free(v); return ret; } 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(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); ret = dev->state == SA_STATE_INIT ? SA_SUCCESS : device_change_rate(dev, rate); if (ret == SA_SUCCESS) dev->pcm_attrs.rate = rate; return ret; } 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_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->pcm_attrs.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->pcm_attrs.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_attrs.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->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); 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->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); 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(!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->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); 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(!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->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); 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->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); } 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_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); if (size < sizeof(png_signature)) return 0; return memcmp(data, png_signature, 8) == 0; } 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; } 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 (!(t = sa_strndup(data, size))) return 0; errno = 0; pid = strtol(t, NULL, 10); sa_free(t); if (errno != 0) return 0; if (pid <= 1) return 0; return 1; } 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; if (size == 1 && t[0] == '.') return 0; if (size == 2 && t[0] == '.' && t[1] == '.') return 0; if (memchr(t, '/', size)) return 0; return 1; } 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; return 1; } typedef int (*meta_check_func_t)(const void *data, size_t size); 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; 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); 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]; }