/** * ca_strerror: * @code: Numerical error code as returned by a libcanberra API function * * Converts a numerical error code as returned by most libcanberra API functions into a human readable error string. * * Returns: a human readable error string. */ const char *ca_strerror(int code) { const char * const error_table[-_CA_ERROR_MAX] = { [-CA_SUCCESS] = "Success", [-CA_ERROR_NOTSUPPORTED] = "Operation not supported", [-CA_ERROR_INVALID] = "Invalid argument", [-CA_ERROR_STATE] = "Invalid state", [-CA_ERROR_OOM] = "Out of memory", [-CA_ERROR_NODRIVER] = "No such driver", [-CA_ERROR_SYSTEM] = "System error", [-CA_ERROR_CORRUPT] = "File or data corrupt", [-CA_ERROR_TOOBIG] = "File or data too large", [-CA_ERROR_NOTFOUND] = "File or data not found", [-CA_ERROR_DESTROYED] = "Destroyed", [-CA_ERROR_CANCELED] = "Canceled", [-CA_ERROR_NOTAVAILABLE] = "Not available", [-CA_ERROR_ACCESS] = "Access forbidden", [-CA_ERROR_IO] = "IO error", [-CA_ERROR_INTERNAL] = "Internal error", [-CA_ERROR_DISABLED] = "Sound disabled", [-CA_ERROR_FORKED] = "Process forked", [-CA_ERROR_DISCONNECTED] = "Disconnected" }; ca_return_val_if_fail(code <= 0, NULL); ca_return_val_if_fail(code > _CA_ERROR_MAX, NULL); return error_table[-code]; }
int ca_context_change_props_full(ca_context *c, ca_proplist *p) { int ret; ca_proplist *merged; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(p, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); if ((ret = ca_proplist_merge(&merged, c->props, p)) < 0) goto finish; ret = c->opened ? driver_change_props(c, p, merged) : CA_SUCCESS; if (ret == CA_SUCCESS) { ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); c->props = merged; } else ca_assert_se(ca_proplist_destroy(merged) == CA_SUCCESS); finish: ca_mutex_unlock(c->mutex); return ret; }
/** * ca_context_cache_full: * @c: The context to use for uploading. * @p: The property list for this event sound. * * Upload the specified sample into the server and attach the * specified properties to it. Similar to ca_context_cache() but takes * a ca_proplist instead of a variable number of arguments. * * If the backend doesn't support caching sound samples this function * will return CA_ERROR_NOTSUPPORTED. * * Returns: 0 on success, negative error code on error. */ int ca_context_cache_full(ca_context *c, ca_proplist *p) { int ret; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(p, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex); if ((ret = context_open_unlocked(c)) < 0) goto finish; ca_assert(c->opened); ret = driver_cache(c, p); finish: ca_mutex_unlock(c->mutex); return ret; }
/** * ca_context_change_device: * @c: the context to change the backend device for * @device: the backend device to use, in a format that is specific to the backend. * * Specify the backend device to use. This function may be called not be called after * ca_context_open() suceeded. This function might suceed even when * the specified driver backend is not available. Use * ca_context_open() to find out whether the backend is available * * Depending on the backend use this might or might not cause all * currently playing event sounds to be moved to the new device.. * * Returns: 0 on success, negative error code on error. */ int ca_context_change_device(ca_context *c, const char *device) { char *n; int ret; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); if (!device) n = NULL; else if (!(n = ca_strdup(device))) { ret = CA_ERROR_OOM; goto fail; } ret = c->opened ? driver_change_device(c, n) : CA_SUCCESS; if (ret == CA_SUCCESS) { ca_free(c->device); c->device = n; } else ca_free(n); fail: ca_mutex_unlock(c->mutex); return ret; }
/** * ca_context_set_driver: * @c: the context to change the backend driver for * @driver: the backend driver to use (e.g. "alsa", "pulse", "null", ...) * * Specify the backend driver used. This function may not be called again after * ca_context_open() suceeded. This function might suceed even when * the specified driver backend is not available. Use * ca_context_open() to find out whether the backend is available. * * Returns: 0 on success, negative error code on error. */ int ca_context_set_driver(ca_context *c, const char *driver) { char *n; int ret; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); if (!driver) n = NULL; else if (!(n = ca_strdup(driver))) { ret = CA_ERROR_OOM; goto fail; } ca_free(c->driver); c->driver = n; ret = CA_SUCCESS; fail: ca_mutex_unlock(c->mutex); return ret; }
/** * ca_context_destroy: * @c: the context to destroy. * * Destroy a (connected or unconnected) context object. * * Returns: 0 on success, negative error code on error. */ int ca_context_destroy(ca_context *c) { int ret = CA_SUCCESS; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); /* 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 (c->opened) ret = driver_destroy(c); if (c->props) ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); if (c->mutex) ca_mutex_free(c->mutex); ca_free(c->driver); ca_free(c->device); ca_free(c); return ret; }
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) { ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(changed, CA_ERROR_INVALID); ca_return_val_if_fail(merged, CA_ERROR_INVALID); return CA_SUCCESS; }
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) { ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(proplist, CA_ERROR_INVALID); ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); if (cb) cb(c, id, CA_SUCCESS, userdata); return CA_SUCCESS; }
int ca_sound_file_open(ca_sound_file **_f, const char *fn) { FILE *file; ca_sound_file *f; int ret; ca_return_val_if_fail(_f, CA_ERROR_INVALID); ca_return_val_if_fail(fn, CA_ERROR_INVALID); if (!(f = ca_new0(ca_sound_file, 1))) return CA_ERROR_OOM; if (!(f->filename = ca_strdup(fn))) { ret = CA_ERROR_OOM; goto fail; } if (!(file = fopen(fn, "r"))) { ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM; goto fail; } if ((ret = ca_wav_open(&f->wav, file)) == CA_SUCCESS) { f->nchannels = ca_wav_get_nchannels(f->wav); f->rate = ca_wav_get_rate(f->wav); f->type = ca_wav_get_sample_type(f->wav); *_f = f; return CA_SUCCESS; } if (ret == CA_ERROR_CORRUPT) { if (fseek(file, 0, SEEK_SET) < 0) { ret = CA_ERROR_SYSTEM; goto fail; } if ((ret = ca_vorbis_open(&f->vorbis, file)) == CA_SUCCESS) { f->nchannels = ca_vorbis_get_nchannels(f->vorbis); f->rate = ca_vorbis_get_rate(f->vorbis); f->type = CA_SAMPLE_S16NE; *_f = f; return CA_SUCCESS; } } fail: ca_free(f->filename); ca_free(f); return ret; }
/** * * ca_context_cancel: * @c: the context to cancel the sounds on * @id: the id that identify the sounds to cancel. * * Cancel one or more event sounds that have been started via * ca_context_play(). If the sound was started with * ca_context_play_full() and a callback function was passed this * might cause this function to be called with %CA_ERROR_CANCELED as * error code. * * Returns: 0 on success, negative error code on error. */ int ca_context_cancel(ca_context *c, uint32_t id) { int ret; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex); ret = driver_cancel(c, id); ca_mutex_unlock(c->mutex); return ret; }
/** * ca_context_open: * @c: the context to connect. * * Connect the context to the sound system. This call is implicitly * called in ca_context_play() or ca_context_cache() if not called * explicitly. It is recommended to initialize application properties * with ca_context_change_props() before calling this function. * * Returns: 0 on success, negative error code on error. */ int ca_context_open(ca_context *c) { int ret; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); ret = context_open_unlocked(c); ca_mutex_unlock(c->mutex); return ret; }
static int context_open_unlocked(ca_context *c) { int ret; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); if (c->opened) return CA_SUCCESS; if ((ret = driver_open(c)) == CA_SUCCESS) c->opened = TRUE; return ret; }
/* Not exported */ int ca_parse_cache_control(ca_cache_control_t *control, const char *c) { ca_return_val_if_fail(control, CA_ERROR_INVALID); ca_return_val_if_fail(c, CA_ERROR_INVALID); if (ca_streq(c, "never")) *control = CA_CACHE_CONTROL_NEVER; else if (ca_streq(c, "permanent")) *control = CA_CACHE_CONTROL_PERMANENT; else if (ca_streq(c, "volatile")) *control = CA_CACHE_CONTROL_VOLATILE; else return CA_ERROR_INVALID; return CA_SUCCESS; }
int ca_vorbis_read_s16ne(ca_vorbis *v, int16_t *d, size_t *n){ long r; int section; int length; size_t n_read = 0; ca_return_val_if_fail(v, CA_ERROR_INVALID); ca_return_val_if_fail(d, CA_ERROR_INVALID); ca_return_val_if_fail(n, CA_ERROR_INVALID); ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); length = (int) (*n * sizeof(int16_t)); do { r = ov_read(&v->ovf, (char*) d, length, #ifdef WORDS_BIGENDIAN 1, #else 0, #endif 2, 1, §ion); if (r < 0) return convert_error((int) r); if (r == 0) break; /* We only read the first section */ if (section != 0) break; length -= (int) r; d += r/sizeof(int16_t); n_read += (size_t) r; } while (length >= 4096); ca_assert(v->size >= (off_t) n_read); v->size -= (off_t) n_read; *n = n_read/sizeof(int16_t); return CA_SUCCESS; }
off_t ca_sound_file_get_size(ca_sound_file *f) { ca_return_val_if_fail(f, (off_t) -1); if (f->wav) return ca_wav_get_size(f->wav); else return ca_vorbis_get_size(f->vorbis); }
int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) { int ret; const char *t; ca_bool_t enabled = TRUE; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(p, CA_ERROR_INVALID); ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); ca_mutex_lock(c->mutex); ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || ca_proplist_contains(c->props, CA_PROP_EVENT_ID) || ca_proplist_contains(p, CA_PROP_MEDIA_FILENAME) || ca_proplist_contains(c->props, CA_PROP_MEDIA_FILENAME), CA_ERROR_INVALID, c->mutex); ca_mutex_lock(c->props->mutex); if ((t = ca_proplist_gets_unlocked(c->props, CA_PROP_CANBERRA_ENABLE))) enabled = !ca_streq(t, "0"); ca_mutex_unlock(c->props->mutex); ca_mutex_lock(p->mutex); if ((t = ca_proplist_gets_unlocked(p, CA_PROP_CANBERRA_ENABLE))) enabled = !ca_streq(t, "0"); ca_mutex_unlock(p->mutex); ca_return_val_if_fail_unlock(enabled, CA_ERROR_DISABLED, c->mutex); if ((ret = context_open_unlocked(c)) < 0) goto finish; ca_assert(c->opened); ret = driver_play(c, id, p, cb, userdata); vizaudio_display(p); finish: ca_mutex_unlock(c->mutex); return ret; }
int ca_context_cache(ca_context *c, ...) { int ret; va_list ap; ca_proplist *p = NULL; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(c, CA_ERROR_INVALID); va_start(ap, c); ret = ca_proplist_from_ap(&p, ap); va_end(ap); if (ret < 0) return ret; ret = ca_context_cache_full(c, p); ca_assert_se(ca_proplist_destroy(p) == 0); return ret; }
int ca_vorbis_open(ca_vorbis **_v, FILE *f) { int ret, or; ca_vorbis *v; int64_t n; ca_return_val_if_fail(_v, CA_ERROR_INVALID); ca_return_val_if_fail(f, CA_ERROR_INVALID); if (!(v = ca_new0(ca_vorbis, 1))) return CA_ERROR_OOM; if ((or = ov_open(f, &v->ovf, NULL, 0)) < 0) { ret = convert_error(or); goto fail; } if ((n = ov_pcm_total(&v->ovf, -1)) < 0) { ret = convert_error(or); ov_clear(&v->ovf); goto fail; } if (((off_t) n * (off_t) sizeof(int16_t)) > FILE_SIZE_MAX) { ret = CA_ERROR_TOOBIG; ov_clear(&v->ovf); goto fail; } v->size = (off_t) n * (off_t) sizeof(int16_t) * ca_vorbis_get_nchannels(v); *_v = v; return CA_SUCCESS; fail: ca_free(v); return ret; }
int ca_context_create(ca_context **_c) { ca_context *c; int ret; const char *d; ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED); ca_return_val_if_fail(_c, CA_ERROR_INVALID); if (!(c = ca_new0(ca_context, 1))) return CA_ERROR_OOM; if (!(c->mutex = ca_mutex_new())) { ca_context_destroy(c); return CA_ERROR_OOM; } if ((ret = ca_proplist_create(&c->props)) < 0) { ca_context_destroy(c); return ret; } if ((d = getenv("CANBERRA_DRIVER"))) { if ((ret = ca_context_set_driver(c, d)) < 0) { ca_context_destroy(c); return ret; } } if ((d = getenv("CANBERRA_DEVICE"))) { if ((ret = ca_context_change_device(c, d)) < 0) { ca_context_destroy(c); return ret; } } *_c = c; return CA_SUCCESS; }
int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n) { int ret; ca_return_val_if_fail(f, CA_ERROR_INVALID); ca_return_val_if_fail(d, CA_ERROR_INVALID); ca_return_val_if_fail(n, CA_ERROR_INVALID); ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); switch (f->type) { case CA_SAMPLE_S16NE: case CA_SAMPLE_S16RE: { size_t k; k = *n / sizeof(int16_t); if ((ret = ca_sound_file_read_int16(f, d, &k)) == CA_SUCCESS) *n = k * sizeof(int16_t); break; } case CA_SAMPLE_U8: { size_t k; k = *n; if ((ret = ca_sound_file_read_uint8(f, d, &k)) == CA_SUCCESS) *n = k; break; } default: ca_assert_not_reached(); } return ret; }
int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n) { ca_return_val_if_fail(f, CA_ERROR_INVALID); ca_return_val_if_fail(d, CA_ERROR_INVALID); ca_return_val_if_fail(n, CA_ERROR_INVALID); ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); ca_return_val_if_fail(f->wav && !f->vorbis, CA_ERROR_STATE); ca_return_val_if_fail(f->type == CA_SAMPLE_U8, CA_ERROR_STATE); if (f->wav) return ca_wav_read_u8(f->wav, d, n); return CA_ERROR_STATE; }
int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n) { ca_return_val_if_fail(f, CA_ERROR_INVALID); ca_return_val_if_fail(d, CA_ERROR_INVALID); ca_return_val_if_fail(n, CA_ERROR_INVALID); ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID); ca_return_val_if_fail(f->wav || f->vorbis, CA_ERROR_STATE); ca_return_val_if_fail(f->type == CA_SAMPLE_S16NE || f->type == CA_SAMPLE_S16RE, CA_ERROR_STATE); if (f->wav) return ca_wav_read_s16le(f->wav, d, n); else return ca_vorbis_read_s16ne(f->vorbis, d, n); }
off_t ca_vorbis_get_size(ca_vorbis *v) { ca_return_val_if_fail(v, (off_t) -1); return v->size; }
int driver_cache(ca_context *c, ca_proplist *proplist) { ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(proplist, CA_ERROR_INVALID); return CA_ERROR_NOTSUPPORTED; }
int driver_cancel(ca_context *c, uint32_t id) { ca_return_val_if_fail(c, CA_ERROR_INVALID); return CA_SUCCESS; }
int driver_change_device(ca_context *c, const char *device) { ca_return_val_if_fail(c, CA_ERROR_INVALID); return CA_SUCCESS; }
int driver_destroy(ca_context *c) { ca_return_val_if_fail(c, CA_ERROR_INVALID); return CA_SUCCESS; }
int driver_open(ca_context *c) { ca_return_val_if_fail(c, CA_ERROR_INVALID); ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "null"), CA_ERROR_NODRIVER); return CA_SUCCESS; }