rtmp-services: Only update Twitch ingests when necessary

(This commit also modifies UI)

Instead of pinging Twitch every time the program starts up, only pings
for new servers when the ingests are actually being used, and when the
UI uses the auto-configuration dialog.

If ingests have not been cached when using the "Auto" server, it will
wait for 3 seconds max to query the Twitch ingest API.  If it takes
longer than 3 seconds or fails, it will defer to SF.  If ingests were
already cached, then it will use the existing cache immediately.
master
jp9000 2017-10-09 10:06:50 -07:00
parent 3dc96fbe43
commit d768717b8c
4 changed files with 108 additions and 22 deletions

View File

@ -545,6 +545,13 @@ void AutoConfigStreamPage::UpdateCompleted()
AutoConfig::AutoConfig(QWidget *parent)
: QWizard(parent)
{
calldata_t cd = {0};
calldata_set_int(&cd, "seconds", 5);
proc_handler_t *ph = obs_get_proc_handler();
proc_handler_call(ph, "twitch_ingests_refresh", &cd);
calldata_free(&cd);
OBSBasic *main = reinterpret_cast<OBSBasic*>(parent);
main->EnableOutputs(false);

View File

@ -24,6 +24,8 @@ static json_t *open_services_file(void);
static inline json_t *find_service(json_t *root, const char *name);
static inline const char *get_string_val(json_t *service, const char *key);
extern void twitch_ingests_refresh(int seconds);
static void rtmp_common_update(void *data, obs_data_t *settings)
{
struct rtmp_common *service = data;
@ -247,12 +249,12 @@ static bool fill_twitch_servers_locked(obs_property_t *servers_prop)
{
size_t count = twitch_ingest_count();
if (count <= 1)
return false;
obs_property_list_add_string(servers_prop,
obs_module_text("Server.Auto"), "auto");
if (count <= 1)
return false;
for (size_t i = 0; i < count; i++) {
struct twitch_ingest ing = twitch_ingest(i);
obs_property_list_add_string(servers_prop, ing.name, ing.url);
@ -508,6 +510,8 @@ static const char *rtmp_common_url(void *data)
if (service->server && strcmp(service->server, "auto") == 0) {
struct twitch_ingest ing;
twitch_ingests_refresh(3);
twitch_ingests_lock();
ing = twitch_ingest(0);
twitch_ingests_unlock();

View File

@ -18,6 +18,12 @@ extern struct obs_service_info rtmp_common_service;
extern struct obs_service_info rtmp_custom_service;
static update_info_t *update_info = NULL;
static struct dstr module_name = {0};
const char *get_module_name(void)
{
return module_name.array;
}
static bool confirm_service_file(void *param, struct file_download_data *file)
{
@ -41,22 +47,39 @@ static bool confirm_service_file(void *param, struct file_download_data *file)
}
extern void init_twitch_data(void);
extern void load_twitch_data(const char *module_str);
extern void load_twitch_data(void);
extern void unload_twitch_data(void);
extern void twitch_ingests_refresh(int seconds);
static void refresh_callback(void *unused, calldata_t *cd)
{
int seconds = calldata_int(cd, "seconds");
if (seconds <= 0)
seconds = 3;
if (seconds > 10)
seconds = 10;
twitch_ingests_refresh(seconds);
UNUSED_PARAMETER(unused);
}
bool obs_module_load(void)
{
init_twitch_data();
#if !defined(_WIN32) || CHECK_FOR_SERVICE_UPDATES
char *local_dir = obs_module_file("");
char *cache_dir = obs_module_config_path("");
struct dstr module_name = {0};
dstr_copy(&module_name, "rtmp-services plugin (libobs ");
dstr_cat(&module_name, obs_get_version_string());
dstr_cat(&module_name, ")");
proc_handler_t *ph = obs_get_proc_handler();
proc_handler_add(ph, "void twitch_ingests_refresh(int seconds)",
refresh_callback, NULL);
#if !defined(_WIN32) || CHECK_FOR_SERVICE_UPDATES
char *local_dir = obs_module_file("");
char *cache_dir = obs_module_config_path("");
if (cache_dir) {
update_info = update_info_create(
RTMP_SERVICES_LOG_STR,
@ -67,11 +90,10 @@ bool obs_module_load(void)
confirm_service_file, NULL);
}
load_twitch_data(module_name.array);
load_twitch_data();
bfree(local_dir);
bfree(cache_dir);
dstr_free(&module_name);
#endif
obs_register_service(&rtmp_common_service);
@ -83,4 +105,5 @@ void obs_module_unload(void)
{
update_info_destroy(update_info);
unload_twitch_data();
dstr_free(&module_name);
}

View File

@ -9,6 +9,9 @@
static update_info_t *twitch_update_info = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool ingests_refreshed = false;
static bool ingests_refreshing = false;
static bool ingests_loaded = false;
struct ingest {
char *name;
@ -28,7 +31,7 @@ static void free_ingests(void)
da_free(cur_ingests);
}
static void load_ingests(const char *json, bool write_file)
static bool load_ingests(const char *json, bool write_file)
{
json_t *root;
json_t *ingests;
@ -79,7 +82,12 @@ static void load_ingests(const char *json, bool write_file)
da_push_back(cur_ingests, &ingest);
}
if (!write_file || !cur_ingests.num)
if (!cur_ingests.num)
goto finish;
success = true;
if (!write_file)
goto finish;
cache_old = obs_module_config_path("twitch_ingests.json");
@ -94,14 +102,22 @@ static void load_ingests(const char *json, bool write_file)
finish:
if (root)
json_decref(root);
return success;
}
static bool twitch_ingest_update(void *param, struct file_download_data *data)
{
bool success;
pthread_mutex_lock(&mutex);
load_ingests(data->buffer.array, true);
success = load_ingests(data->buffer.array, true);
pthread_mutex_unlock(&mutex);
if (success) {
os_atomic_set_bool(&ingests_refreshed, true);
os_atomic_set_bool(&ingests_loaded, true);
}
UNUSED_PARAMETER(param);
return true;
}
@ -141,26 +157,62 @@ void init_twitch_data(void)
pthread_mutex_init(&mutex, NULL);
}
void load_twitch_data(const char *module_str)
extern const char *get_module_name(void);
void twitch_ingests_refresh(int seconds)
{
if (os_atomic_load_bool(&ingests_refreshed))
return;
if (!os_atomic_load_bool(&ingests_refreshing)) {
os_atomic_set_bool(&ingests_refreshing, true);
twitch_update_info = update_info_create_single(
"[twitch ingest update] ",
get_module_name(),
"https://ingest.twitch.tv/api/v2/ingests",
twitch_ingest_update, NULL);
}
/* wait five seconds max when loading ingests for the first time */
if (!os_atomic_load_bool(&ingests_loaded)) {
for (int i = 0; i < seconds * 100; i++) {
if (os_atomic_load_bool(&ingests_refreshed)) {
break;
}
os_sleep_ms(10);
}
}
}
void load_twitch_data(void)
{
char *twitch_cache = obs_module_config_path("twitch_ingests.json");
struct ingest def = {
.name = bstrdup("Default"),
.url = bstrdup("rtmp://live.twitch.tv/app")
};
pthread_mutex_lock(&mutex);
da_push_back(cur_ingests, &def);
pthread_mutex_unlock(&mutex);
if (os_file_exists(twitch_cache)) {
char *data = os_quick_read_utf8_file(twitch_cache);
bool success;
pthread_mutex_lock(&mutex);
load_ingests(data, false);
success = load_ingests(data, false);
pthread_mutex_unlock(&mutex);
if (success) {
os_atomic_set_bool(&ingests_loaded, true);
}
bfree(data);
}
twitch_update_info = update_info_create_single(
"[twitch ingest update] ",
module_str,
"https://ingest.twitch.tv/api/v2/ingests",
twitch_ingest_update, NULL);
bfree(twitch_cache);
}