|
|
|
|
@ -88,6 +88,7 @@ struct media_player_media_file {
|
|
|
|
|
str blob;
|
|
|
|
|
union {
|
|
|
|
|
str_list *str_link;
|
|
|
|
|
GList *gen_link;
|
|
|
|
|
};
|
|
|
|
|
time_t ts;
|
|
|
|
|
};
|
|
|
|
|
@ -103,6 +104,14 @@ static rwlock_t media_player_media_files_names_lock = RWLOCK_STATIC_INIT;
|
|
|
|
|
static str_q media_player_media_files_names = TYPED_GQUEUE_INIT;
|
|
|
|
|
// lock order: media_player_media_files_names_lock first, media_player_media_files_lock second
|
|
|
|
|
|
|
|
|
|
TYPED_GHASHTABLE(media_player_db_media_ht, void, struct media_player_media_file, g_direct_hash, g_direct_equal,
|
|
|
|
|
NULL, __obj_put);
|
|
|
|
|
static mutex_t media_player_db_media_lock = MUTEX_STATIC_INIT;
|
|
|
|
|
static media_player_db_media_ht media_player_db_media;
|
|
|
|
|
static rwlock_t media_player_db_media_ids_lock = RWLOCK_STATIC_INIT;
|
|
|
|
|
static GQueue media_player_db_media_ids = G_QUEUE_INIT;
|
|
|
|
|
// lock order: media_player_db_media_ids_lock first, media_player_db_media_lock second
|
|
|
|
|
|
|
|
|
|
static bool media_player_read_packet(struct media_player *mp);
|
|
|
|
|
static mp_cached_code __media_player_add_blob_id(struct media_player *mp,
|
|
|
|
|
media_player_opts_t opts,
|
|
|
|
|
@ -1218,6 +1227,16 @@ static struct media_player_media_file *media_player_media_file_read_str(const st
|
|
|
|
|
return media_player_media_file_read_c(file_s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *media_player_get_db_id(str *out, unsigned long long id, str (*dup_fn)(const char *, size_t));
|
|
|
|
|
|
|
|
|
|
static struct media_player_media_file *media_player_db_id_read(unsigned long long id) {
|
|
|
|
|
str blob;
|
|
|
|
|
const char *err = media_player_get_db_id(&blob, id, str_dup_len);
|
|
|
|
|
if (err || blob.len == 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
return media_player_media_file_new(blob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct media_player_media_file *media_player_media_files_get_only(const str *fn) {
|
|
|
|
|
struct media_player_media_file *fo;
|
|
|
|
|
|
|
|
|
|
@ -1235,6 +1254,24 @@ static struct media_player_media_file *media_player_media_files_get_only(const s
|
|
|
|
|
return fo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// lock must be held, reference will be taken over
|
|
|
|
|
static struct media_player_media_file *media_player_db_id_get_only(unsigned long long id) {
|
|
|
|
|
struct media_player_media_file *fo;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
LOCK(&media_player_db_media_lock);
|
|
|
|
|
if (!t_hash_table_is_set(media_player_db_media))
|
|
|
|
|
return NULL;
|
|
|
|
|
fo = t_hash_table_lookup(media_player_db_media, GUINT_TO_POINTER(id));
|
|
|
|
|
if (!fo)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
obj_hold(fo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// locks must be held, reference will be taken over
|
|
|
|
|
static void media_player_media_files_insert(const str *fn, struct media_player_media_file *fo) {
|
|
|
|
|
if (!t_hash_table_is_set(media_player_media_files))
|
|
|
|
|
@ -1258,9 +1295,20 @@ static mp_cached_code media_player_set_media_file(struct media_player *mp,
|
|
|
|
|
// switch to blob playing
|
|
|
|
|
opts.file = STR_NULL;
|
|
|
|
|
opts.blob = fo->blob;
|
|
|
|
|
// db_id remains set if it was, so that the cache lookup can succeed
|
|
|
|
|
return __media_player_add_blob_id(mp, opts, dst_pt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// locks must be held, reference will be taken over
|
|
|
|
|
static void media_player_db_id_insert(unsigned long long id, struct media_player_media_file *fo) {
|
|
|
|
|
if (!t_hash_table_is_set(media_player_db_media))
|
|
|
|
|
media_player_db_media = media_player_db_media_ht_new();
|
|
|
|
|
t_hash_table_insert(media_player_db_media, GUINT_TO_POINTER(id), fo);
|
|
|
|
|
g_queue_push_tail(&media_player_db_media_ids, GUINT_TO_POINTER(id));
|
|
|
|
|
fo->gen_link = media_player_db_media_ids.tail;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct media_player_media_file *media_player_media_files_get_create(const str *fn) {
|
|
|
|
|
__auto_type fo = media_player_media_files_get_only(fn);
|
|
|
|
|
if (fo)
|
|
|
|
|
@ -1285,6 +1333,9 @@ static struct media_player_media_file *media_player_media_files_get_create(const
|
|
|
|
|
static struct media_player_media_file *(*media_player_media_files_get)(const str *fn)
|
|
|
|
|
= media_player_media_files_get_only;
|
|
|
|
|
|
|
|
|
|
static struct media_player_media_file *(*media_player_db_id_get)(unsigned long long)
|
|
|
|
|
= media_player_db_id_get_only;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void __media_player_set_opts(struct media_player *mp, media_player_opts_t opts) {
|
|
|
|
|
mp->opts = opts;
|
|
|
|
|
@ -1749,6 +1800,13 @@ static mp_cached_code __media_player_add_db(struct media_player *mp,
|
|
|
|
|
{
|
|
|
|
|
const char *err;
|
|
|
|
|
|
|
|
|
|
// check if we have it in memory
|
|
|
|
|
__auto_type fo = media_player_db_id_get(opts.db_id);
|
|
|
|
|
if (fo) {
|
|
|
|
|
ilog(LOG_DEBUG, "Using cached DB media for playback");
|
|
|
|
|
return media_player_set_media_file(mp, opts, dst_pt, fo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = media_player_get_db_id(&opts.blob, opts.db_id, call_str_cpy_len);
|
|
|
|
|
if (err)
|
|
|
|
|
return MPC_ERR;
|
|
|
|
|
@ -1922,6 +1980,10 @@ void media_player_free(void) {
|
|
|
|
|
if (t_hash_table_is_set(media_player_media_files))
|
|
|
|
|
t_hash_table_destroy(media_player_media_files);
|
|
|
|
|
t_queue_clear_full(&media_player_media_files_names, str_free);
|
|
|
|
|
|
|
|
|
|
if (t_hash_table_is_set(media_player_db_media))
|
|
|
|
|
t_hash_table_destroy(media_player_db_media);
|
|
|
|
|
g_queue_clear(&media_player_db_media_ids);
|
|
|
|
|
#endif
|
|
|
|
|
timerthread_free(&send_timer_thread);
|
|
|
|
|
}
|
|
|
|
|
@ -1970,6 +2032,40 @@ bool media_player_preload_files(char **files) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool media_player_preload_db(char **ids) {
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
if (!ids || !ids[0])
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
for (char **idp = ids; *idp; idp++) {
|
|
|
|
|
char *id_s = *idp;
|
|
|
|
|
|
|
|
|
|
char *endp = NULL;
|
|
|
|
|
unsigned long long id = strtoull(id_s, &endp, 0);
|
|
|
|
|
if (id == 0 || id == ULLONG_MAX || (endp && *endp != '\0')) {
|
|
|
|
|
ilog(LOG_CRIT, "Invalid DB ID string number: '%s'", id_s);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Reading media ID %llu from DB for caching", id);
|
|
|
|
|
|
|
|
|
|
if (t_hash_table_is_set(media_player_db_media)
|
|
|
|
|
&& t_hash_table_lookup(media_player_db_media, GUINT_TO_POINTER(id)))
|
|
|
|
|
{
|
|
|
|
|
ilog(LOG_CRIT, "Duplicate entry for caching media ID %llu", id);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__auto_type fo = media_player_db_id_read(id);
|
|
|
|
|
if (!fo)
|
|
|
|
|
return false;
|
|
|
|
|
media_player_db_id_insert(id, fo);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool media_player_reload_file(str *name) {
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
@ -2027,6 +2123,53 @@ unsigned int media_player_reload_files(void) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool media_player_reload_db_media(unsigned long long id) {
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
__auto_type fo = media_player_db_id_get(id);
|
|
|
|
|
if (!fo)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// read fresh copy
|
|
|
|
|
__auto_type fonew = media_player_db_id_read(id);
|
|
|
|
|
if (fonew) {
|
|
|
|
|
// got a new entry. swap it out against the old one
|
|
|
|
|
LOCK(&media_player_db_media_lock);
|
|
|
|
|
if (t_hash_table_is_set(media_player_db_media)
|
|
|
|
|
&& t_hash_table_lookup(media_player_db_media, GUINT_TO_POINTER(id)) == fo)
|
|
|
|
|
{
|
|
|
|
|
t_hash_table_insert(media_player_db_media, GUINT_TO_POINTER(id), fonew); // releases `fo` reference
|
|
|
|
|
ilog(LOG_DEBUG, "Reloaded cached media DB entry %llu", id);
|
|
|
|
|
ret = true;
|
|
|
|
|
}
|
|
|
|
|
else // somebody beat us to it
|
|
|
|
|
obj_put(fonew);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj_put(fo);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int media_player_reload_db_medias(void) {
|
|
|
|
|
unsigned int ret = 0;
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
RWLOCK_R(&media_player_db_media_ids_lock);
|
|
|
|
|
|
|
|
|
|
for (__auto_type l = media_player_db_media_ids.head; l; l = l->next) {
|
|
|
|
|
unsigned long long id = GPOINTER_TO_UINT(l->data);
|
|
|
|
|
if (media_player_reload_db_media(id))
|
|
|
|
|
ret++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum thread_looper_action media_player_refresh_timer(void) {
|
|
|
|
|
if (rtpe_config.media_refresh <= 0)
|
|
|
|
|
return TLA_BREAK;
|
|
|
|
|
|