MT#61822 support preloading media from DB

Change-Id: Ieba8c9dd7ee413c64292a2fd48a16d38bade6be3
pull/1897/head
Richard Fuchs 11 months ago
parent 52b6e6ea58
commit e7c424d1ac

@ -111,6 +111,8 @@ static void cli_incoming_tag_detdtmf(str *instr, struct cli_writer *cw, const cl
static void cli_incoming_media_reload_file(str *instr, struct cli_writer *cw, const cli_handler_t *);
static void cli_incoming_media_reload_files(str *instr, struct cli_writer *cw, const cli_handler_t *);
static void cli_incoming_media_reload_db(str *instr, struct cli_writer *cw, const cli_handler_t *);
static void cli_incoming_media_reload_dbs(str *instr, struct cli_writer *cw, const cli_handler_t *);
#endif
static const cli_handler_t cli_set_handlers[] = {
@ -186,6 +188,8 @@ static const cli_handler_t cli_params_handlers[] = {
static const cli_handler_t cli_media_reload_handlers[] = {
{ "file", cli_incoming_media_reload_file, NULL },
{ "files", cli_incoming_media_reload_files, NULL },
{ "db", cli_incoming_media_reload_db, NULL },
{ "dbs", cli_incoming_media_reload_dbs, NULL },
{ NULL, },
};
static const cli_handler_t cli_media_handlers[] = {
@ -1792,4 +1796,27 @@ static void cli_incoming_media_reload_files(str *instr, struct cli_writer *cw, c
unsigned int num = media_player_reload_files();
cw->cw_printf(cw, "%u media files reloaded\n", num);
}
static void cli_incoming_media_reload_db(str *instr, struct cli_writer *cw, const cli_handler_t *handler) {
if (instr->len == 0) {
cw->cw_printf(cw, "More parameters required.\n");
return ;
}
unsigned long long id = str_to_ui(instr, 0);
if (id == 0 || id == ULLONG_MAX)
cw->cw_printf(cw, "Invalid ID '" STR_FORMAT "'\n", STR_FMT(instr));
else {
bool ok = media_player_reload_db_media(id);
if (ok)
cw->cw_printf(cw, "Success\n");
else
cw->cw_printf(cw, "Failed to reload '" STR_FORMAT "'\n", STR_FMT(instr));
}
}
static void cli_incoming_media_reload_dbs(str *instr, struct cli_writer *cw, const cli_handler_t *handler) {
unsigned int num = media_player_reload_db_medias();
cw->cw_printf(cw, "%u media entries reloaded\n", num);
}
#endif

@ -675,6 +675,7 @@ static void options(int *argc, char ***argv, GHashTable *templates) {
{ "kernel-player-media",0,0,G_OPTION_ARG_INT, &rtpe_config.kernel_player_media,"Max number of kernel media files","INT"},
{ "preload-media-files",0,0,G_OPTION_ARG_FILENAME_ARRAY,&rtpe_config.preload_media_files,"Preload media file(s) for playback into memory","FILE"},
{ "media-files-reload",0,0,G_OPTION_ARG_INT, &rtpe_config.media_refresh,"Refresh/reload preloaded media files at a certain interval","SECONDS"},
{ "preload-db-media",0,0,G_OPTION_ARG_STRING_ARRAY,&rtpe_config.preload_db_media,"Preload media from database for playback into memory","INT"},
{ "audio-buffer-length",0,0, G_OPTION_ARG_INT,&rtpe_config.audio_buffer_length,"Length in milliseconds of audio buffer","INT"},
{ "audio-buffer-delay",0,0, G_OPTION_ARG_INT,&rtpe_config.audio_buffer_delay,"Initial delay in milliseconds for buffered audio","INT"},
{ "audio-player",0,0, G_OPTION_ARG_STRING, &use_audio_player, "When to enable the internal audio player","on-demand|play-media|transcoding|always"},
@ -1484,6 +1485,9 @@ static void create_everything(void) {
if (!media_player_preload_files(rtpe_config.preload_media_files))
die("Failed to preload media files");
if (!media_player_preload_db(rtpe_config.preload_db_media))
die("Failed to preload media from database");
}

@ -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;

@ -1172,6 +1172,12 @@ call to inject-DTMF won't be sent to __\-\-dtmf-log-dest=__ or __\-\-listen-tcp-
since then, it will be re-read and will replace the previous cached
contents.
- __\-\-preload-db-media=__*INT*
Similar to the __preload-media-files__ option, but preloads media from
database instead of reading them from files. Each entry must be an integer
corresponding to an index from the database.
- __\-\-audio-buffer-length=__*INT*
Set the buffer length used by the audio player (see below) in milliseconds. The

@ -167,6 +167,7 @@ recording-method = proc
# preload-media-files = /var/media/file1.wav ; /var/media/file2.wav ; /var/media/file3.wav ; on-demand
# media-files-reload = 60
# preload-db-media = 1; 2; 3; 4
# signalling templates (see key `templates` above)
[templates]

@ -184,6 +184,7 @@ enum endpoint_learning {
X(http_ifs) \
X(https_ifs) \
X(preload_media_files) \
X(preload_db_media) \
// these are not automatically included in rtpe_config due to different types
#define RTPE_CONFIG_ENUM_PARAMS \

@ -152,7 +152,10 @@ void media_player_launch(void);
bool media_player_preload_files(char **);
bool media_player_reload_file(str *name);
unsigned int media_player_reload_files(void);
bool media_player_reload_db_media(unsigned long long);
unsigned int media_player_reload_db_medias(void);
enum thread_looper_action media_player_refresh_timer(void);
bool media_player_preload_db(char **);
struct send_timer *send_timer_new(struct packet_stream *);
void send_timer_push(struct send_timer *, struct codec_packet *);

@ -167,6 +167,8 @@ sub showusage {
print " reload <option>\n";
print " file <file name> : reload one media file into memory\n";
print " files : reload all media files currently in memory\n";
print " db <index> : reload one media entry from database into memory\n";
print " dbs : reload all media entries from database currently in memory\n";
print "\n";
print "\n";
print " Return Value:\n";

Loading…
Cancel
Save