//slfi.h: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2014 * * This file is part of libroardsp a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroardsp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "libroarlight.h" static const struct roar_slfi_filter * __find_impl_registered(const char * name, struct roar_dl_lhandle ** lhandle) { const void * impl; size_t impl_size; int options; ssize_t i; for (i = 0; ; i++) { if ( roar_dl_query_fn(lhandle, ROAR_DL_FN_FILTER, ROAR_DL_FILTER_SUBTYPE_SLFI, &impl, &impl_size, ROAR_DL_FILTER_VERSION_SLFI, &options, i) == -1 ) { return NULL; } if ( impl_size != ROAR_DL_FILTER_SIZE_SLFI ) { ROAR_WARN("__find_impl_registered(*): Object %p has wrong size of %u. Strange.", impl, (unsigned int)impl_size); continue; } if ( ((const struct roar_slfi_filter *)impl)->name == NULL ) { ROAR_WARN("__find_impl_registered(*): Object %p has no name. Strange.", impl); continue; } if ( !!strcmp(((const struct roar_slfi_filter *)impl)->name, name) ) continue; return impl; } } static struct roar_dl_lhandle * __find_impl_autoload(const char * name) { struct roar_dl_lhandle * lhandle = NULL; struct roar_dl_librarypara * para = NULL; char buf[80]; int err; para = roar_dl_para_new(NULL, NULL, LIBROAR_DL_APPNAME, LIBROAR_DL_ABIVERSION); if ( para == NULL ) return NULL; snprintf(buf, sizeof(buf), "filter-slfi-%s", name); lhandle = roar_dl_open(buf, ROAR_DL_FLAG_PLUGIN, 1, para); err = roar_error; roar_dl_para_unref(para); roar_error = err; return lhandle; } static const struct roar_slfi_filter * __find_impl(const char * name, int autoload, struct roar_dl_lhandle ** lhandle) { const struct roar_slfi_filter * impl; struct roar_dl_lhandle * loaded_lhandle = NULL; int err; impl = __find_impl_registered(name, lhandle); if ( impl != NULL ) { roar_dl_ref(*lhandle); return impl; } if ( autoload ) { loaded_lhandle = __find_impl_autoload(name); if ( loaded_lhandle == NULL ) return NULL; impl = __find_impl_registered(name, lhandle); if ( impl == NULL ) { err = roar_error; roar_dl_unref(loaded_lhandle); roar_err_set(err); return NULL; } else if ( *lhandle != loaded_lhandle ) { ROAR_WARN("__find_impl(name='%s', autoload=%i, lhandle=%p): Loaded handle and found handle do not match. Strange.", name, autoload, lhandle); roar_dl_unref(loaded_lhandle); roar_err_set(ROAR_ERROR_BADFH); return NULL; } else { *lhandle = loaded_lhandle; return impl; } } roar_err_set(ROAR_ERROR_NOENT); return NULL; } struct roar_slfi_inst * roar_slfi_new(const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen) { const struct roar_slfi_filter * impl; struct roar_dl_lhandle * lhandle = NULL; struct roar_slfi_inst * inst; int err; impl = __find_impl(name, autoload, &lhandle); if ( impl == NULL ) return NULL; inst = roar_mm_malloc(sizeof(*inst)); if ( inst == NULL ) return NULL; memset(inst, 0, sizeof(*inst)); inst->refc = 1; inst->impl = impl; inst->flags = impl->flags; inst->userdata = NULL; inst->lhandle = lhandle; if ( inst->impl->init != NULL ) { if ( lhandle != NULL ) roar_dl_context_restore(lhandle); if ( inst->impl->init(inst, para, paralen) != 0 ) { err = roar_error; if ( lhandle != NULL ) roar_dl_context_store(lhandle); if ( inst->userdata != NULL ) roar_mm_free(inst->userdata); roar_mm_free(inst); if ( lhandle != NULL ) roar_dl_unref(lhandle); roar_err_set(err); return NULL; } if ( lhandle != NULL ) roar_dl_context_store(lhandle); } return inst; } int roar_slfi_ref(struct roar_slfi_inst * inst) { if ( inst == NULL || inst->impl == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } inst->refc++; return 0; } int roar_slfi_unref(struct roar_slfi_inst * inst) { if ( inst == NULL || inst->impl == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } inst->refc--; if ( inst->refc ) return 0; if ( inst->impl->uninit != NULL ) { if ( inst->lhandle != NULL ) roar_dl_context_restore(inst->lhandle); inst->impl->uninit(inst); if ( inst->lhandle != NULL ) roar_dl_context_store(inst->lhandle); } if ( inst->userdata != NULL ) roar_mm_free(inst->userdata); if ( inst->lhandle != NULL ) roar_dl_unref(inst->lhandle); roar_mm_free(inst); return 0; } int roar_slfi_update(struct roar_slfi_inst * inst, uint8_t * universe, ssize_t size_of_universe, int32_t usecspassed, const uint8_t * event, size_t eventlen) { int ret; if ( inst == NULL || inst->impl == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( inst->impl->update == NULL ) { roar_err_set(ROAR_ERROR_NOSYS); return -1; } if ( inst->lhandle != NULL ) roar_dl_context_restore(inst->lhandle); ret = inst->impl->update(inst, universe, size_of_universe, usecspassed, event, eventlen); if ( inst->lhandle != NULL ) roar_dl_context_store(inst->lhandle); return ret; } int roar_slfi_ctl(struct roar_slfi_inst * inst, enum roar_slfi_command command, void * argp) { int ret; if ( inst == NULL || inst->impl == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( inst->impl->ctl == NULL ) { roar_err_set(ROAR_ERROR_NOSYS); return -1; } if ( inst->lhandle != NULL ) roar_dl_context_restore(inst->lhandle); ret = inst->impl->ctl(inst, command, argp); if ( inst->lhandle != NULL ) roar_dl_context_store(inst->lhandle); return ret; } int roar_slfi_event_add(struct roar_slfi_inst * inst, uint8_t event) { if ( inst == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( inst->cb_event_add == NULL ) { roar_err_set(ROAR_ERROR_NOSYS); return -1; } return inst->cb_event_add(inst, inst->cb_event_add_userdata, event); } int roar_slfi_cb_set_event_add(struct roar_slfi_inst * inst, int (*cb)(struct roar_slfi_inst * inst, void * userdata, uint8_t event), void * userdata) { if ( inst == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } inst->cb_event_add = cb; inst->cb_event_add_userdata = userdata; return 0; } //ll