diff --git a/src/library.c b/src/library.c index 63f7f890..ecdd79f6 100644 --- a/src/library.c +++ b/src/library.c @@ -48,6 +48,14 @@ #include "listener.h" #include "player.h" +#define LIBRARY_MAX_CALLBACKS 16 + +struct library_callback_register +{ + library_cb cb; + void *arg; +}; + struct playlist_item_add_param { const char *vp_playlist; @@ -107,6 +115,9 @@ static struct event *updateev; static unsigned int deferred_update_notifications; static short deferred_update_events; +// Stores callbacks that backends may have requested +static struct library_callback_register library_cb_register[LIBRARY_MAX_CALLBACKS]; + /* ------------------- CALLED BY LIBRARY SOURCE MODULES -------------------- */ @@ -155,6 +166,50 @@ library_playlist_save(struct playlist_info *pli) return db_pl_update(pli); } +static void +scheduled_cb(int fd, short what, void *arg) +{ + struct library_callback_register *cbreg = arg; + + DPRINTF(E_DBG, L_LIB, "Executing library callback to %p\n", cbreg->cb); + + cbreg->cb(cbreg->arg); + + memset(cbreg, 0, sizeof(struct library_callback_register)); +} + +int +library_callback_schedule(library_cb cb, void *arg, struct timeval *wait) +{ + struct library_callback_register *cbreg; + int callback_id; + + // Find a free slot in the queue + for (callback_id = 0; callback_id < ARRAY_SIZE(library_cb_register); callback_id++) + { + if (library_cb_register[callback_id].cb == NULL) + break; + } + + if (callback_id == ARRAY_SIZE(library_cb_register)) + { + DPRINTF(E_LOG, L_LIB, "Library callback register is full! (size is %d)\n", LIBRARY_MAX_CALLBACKS); + return -1; + } + + cbreg = &library_cb_register[callback_id]; + + cbreg->cb = cb; + cbreg->arg = arg; + + // One-time event, freed automatically by libevent + CHECK_ERR(L_LIB, event_base_once(evbase_lib, -1, EV_TIMEOUT, scheduled_cb, cbreg, wait)); + + DPRINTF(E_DBG, L_LIB, "Added library callback to %p (id %d)\n", cbreg->cb, callback_id); + + return callback_id; +} + /* ---------------------- LIBRARY ABSTRACTION --------------------- */ /* thread: library */ @@ -446,11 +501,11 @@ queue_save(void *arg, int *retval) static enum command_state item_add(void *arg, int *retval) { - struct item_add_params *params = arg; + const char *path = arg; int i; int ret = LIBRARY_ERROR; - DPRINTF(E_DBG, L_LIB, "Adding item to library '%s' '%s'\n", params->name, params->path); + DPRINTF(E_DBG, L_LIB, "Adding item to library '%s'\n", path); for (i = 0; sources[i]; i++) { @@ -460,11 +515,11 @@ item_add(void *arg, int *retval) continue; } - ret = sources[i]->item_add(params->name, params->path, params->limit); + ret = sources[i]->item_add(path); if (ret == LIBRARY_OK) { - DPRINTF(E_DBG, L_LIB, "Add item to path '%s' with library source '%s'\n", params->path, sources[i]->name); + DPRINTF(E_DBG, L_LIB, "Add item to path '%s' with library source '%s'\n", path, sources[i]->name); listener_notify(LISTENER_DATABASE); break; } @@ -474,38 +529,6 @@ item_add(void *arg, int *retval) return COMMAND_END; } -static enum command_state -item_remove(void *arg, int *retval) -{ - const char *path = arg; - int i; - int ret = LIBRARY_ERROR; - - DPRINTF(E_DBG, L_LIB, "Removing item from library '%s'\n", path); - - for (i = 0; sources[i]; i++) - { - if (sources[i]->disabled || !sources[i]->item_remove) - { - DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support add_remove\n", sources[i]->name); - continue; - } - - ret = sources[i]->item_remove(path); - - if (ret == LIBRARY_OK) - { - DPRINTF(E_DBG, L_LIB, "Removing item from path '%s' with library source '%s'\n", path, sources[i]->name); - listener_notify(LISTENER_DATABASE); - break; - } - } - - *retval = ret; - return COMMAND_END; -} - - // Callback to notify listeners of database changes static void update_trigger_cb(int fd, short what, void *arg) @@ -709,40 +732,12 @@ library_queue_item_add(const char *path, int position, char reshuffle, uint32_t } int -library_item_add(const char *name, const char *path, long limit) -{ - struct item_add_params params; - - if (library_is_scanning()) - return -1; - - params.name = name; - params.path = path; - params.limit = limit; - return commands_exec_sync(cmdbase, item_add, NULL, ¶ms); -} - -int -library_item_remove(const char *path) +library_item_add(const char *path) { if (library_is_scanning()) return -1; - return commands_exec_sync(cmdbase, item_remove, NULL, path); -} - -struct event* -library_register_event(void (*ev_cb)(int fd, short what, void *arg), void *ev_cb_arg, const struct timeval* cb_interval) -{ - struct event *ev; - ev = evtimer_new(evbase_lib, ev_cb, ev_cb_arg); - if (!ev) - { - DPRINTF(E_FATAL, L_LIB, "Failed to create timer event\n"); - return NULL; - } - evtimer_add(ev, cb_interval); - return ev; + return commands_exec_sync(cmdbase, item_add, NULL, (char *)path); } int @@ -807,21 +802,18 @@ library_init(void) for (i = 0; sources[i]; i++) { - if (!sources[i]->init) - { - DPRINTF(E_FATAL, L_LIB, "BUG: library source '%s' has no init()\n", sources[i]->name); - return -1; - } - if (!sources[i]->initscan || !sources[i]->rescan || !sources[i]->metarescan || !sources[i]->fullrescan) { DPRINTF(E_FATAL, L_LIB, "BUG: library source '%s' is missing a scanning method\n", sources[i]->name); return -1; } - ret = sources[i]->init(); - if (ret < 0) - sources[i]->disabled = 1; + if (sources[i]->init && !sources[i]->disabled) + { + ret = sources[i]->init(); + if (ret < 0) + sources[i]->disabled = 1; + } } CHECK_NULL(L_LIB, cmdbase = commands_base_new(evbase_lib, NULL)); @@ -858,7 +850,7 @@ library_deinit() for (i = 0; sources[i]; i++) { if (sources[i]->deinit && !sources[i]->disabled) - sources[i]->deinit(); + sources[i]->deinit(); } event_free(updateev); diff --git a/src/library.h b/src/library.h index 7d739904..878ce010 100644 --- a/src/library.h +++ b/src/library.h @@ -30,11 +30,7 @@ #define LIBRARY_ERROR -1 #define LIBRARY_PATH_INVALID -2 -struct item_add_params { - const char *name; - const char *path; - int limit; -}; +typedef void (*library_cb)(void *arg); /* * Definition of a library source @@ -78,10 +74,9 @@ struct library_source int (*fullrescan)(void); /* - * Perform an add to library of single item + * Add an item to the library */ - int (*item_add)(const char *name, const char *path, int limit); - int (*item_remove)(const char *path); + int (*item_add)(const char *path); /* * Add item to playlist @@ -106,6 +101,12 @@ struct library_source /* --------------------- Interface towards source backends ----------------- */ +/* + * Adds a mfi if mfi->id == 0, otherwise updates. + * + * @param mfi Media to save + * @return 0 if operation succeeded, -1 on failure. + */ int library_media_save(struct media_file_info *mfi); @@ -113,11 +114,27 @@ library_media_save(struct media_file_info *mfi); * Adds a playlist if pli->id == 0, otherwise updates. * * @param pli Playlist to save - * @return playlist id if operation succeeded, -1 on failure. + * @return Playlist id if operation succeeded, -1 on failure. */ int library_playlist_save(struct playlist_info *pli); +/* + * @param cb Callback to call + * @param arg Argument to call back with + * @param timeval How long to wait before calling back + * @return id of the scheduled event, -1 on failure + */ +int +library_callback_schedule(library_cb cb, void *arg, struct timeval *wait); + +/* + * @return true if a running scan should be aborted due to imminent shutdown + */ +bool +library_is_exiting(); + + /* ------------------------ Library external interface --------------------- */ void @@ -141,12 +158,6 @@ library_is_scanning(); void library_set_scanning(bool is_scanning); -/* - * @return true if a running scan should be aborted due to imminent shutdown, otherwise false - */ -bool -library_is_exiting(); - /* * Trigger for sending the DATABASE event * @@ -169,15 +180,8 @@ int library_queue_item_add(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id); int -library_item_add(const char *name, const char *url, long limit); +library_item_add(const char *path); -int -library_item_remove(const char *url); - -/* Register any timer events for library modules - */ -struct event* -library_register_event(void (*ev_cb)(int fd, short what, void *arg), void *ev_cb_arg, const struct timeval* cb_interval); /* * Execute the function 'func' with the given argument 'arg' in the library thread.