Browse Source

rtmp-services: Add Dacast

Faeez Kadiri 4 years ago
parent
commit
85334d562f

+ 2 - 0
plugins/rtmp-services/CMakeLists.txt

@@ -11,6 +11,7 @@ set(rtmp-services_SOURCES
 	service-specific/younow.c
 	service-specific/nimotv.c
 	service-specific/showroom.c
+	service-specific/dacast.c
 	rtmp-common.c
 	rtmp-custom.c
 	rtmp-services-main.c)
@@ -27,6 +28,7 @@ set(rtmp-services_HEADERS
 	service-specific/younow.h
 	service-specific/nimotv.h
 	service-specific/showroom.h
+	service-specific/dacast.h
 	rtmp-format-ver.h)
 
 set(RTMP_SERVICES_URL

+ 15 - 0
plugins/rtmp-services/data/services.json

@@ -2078,6 +2078,21 @@
                 "max audio bitrate": 192,
                 "x264opts": "tune=zerolatency b-pyramid=0 scenecut=0"
             }
+        },
+        {
+            "name": "Dacast",
+            "servers": [
+                {
+                    "name": "Default",
+                    "url": "https://developer.dacast.com/v3/encoder-setup/"
+                }
+            ],
+            "recommended": {
+                "keyint": 1,
+                "profile": "high",
+                "max video bitrate": 7000,
+                "max audio bitrate": 128
+            }
         }
     ]
 }

+ 47 - 0
plugins/rtmp-services/rtmp-common.c

@@ -9,6 +9,7 @@
 #include "service-specific/younow.h"
 #include "service-specific/nimotv.h"
 #include "service-specific/showroom.h"
+#include "service-specific/dacast.h"
 
 struct rtmp_common {
 	char *service;
@@ -684,6 +685,16 @@ static const char *rtmp_common_url(void *data)
 			return ingest->url;
 		}
 	}
+
+	if (service->service && strcmp(service->service, "Dacast") == 0) {
+		if (service->server && service->key) {
+			dacast_ingests_load_data(service->server, service->key);
+
+			struct dacast_ingest *ingest;
+			ingest = dacast_ingest(service->key);
+			return ingest->url;
+		}
+	}
 	return service->server;
 }
 
@@ -698,6 +709,14 @@ static const char *rtmp_common_key(void *data)
 			return ingest->key;
 		}
 	}
+
+	if (service->service && strcmp(service->service, "Dacast") == 0) {
+		if (service->key) {
+			struct dacast_ingest *ingest;
+			ingest = dacast_ingest(service->key);
+			return ingest->streamkey;
+		}
+	}
 	return service->key;
 }
 
@@ -758,6 +777,32 @@ fail:
 	json_decref(root);
 }
 
+static const char *rtmp_common_username(void *data)
+{
+	struct rtmp_common *service = data;
+	if (service->service && strcmp(service->service, "Dacast") == 0) {
+		if (service->key) {
+			struct dacast_ingest *ingest;
+			ingest = dacast_ingest(service->key);
+			return ingest->username;
+		}
+	}
+	return NULL;
+}
+
+static const char *rtmp_common_password(void *data)
+{
+	struct rtmp_common *service = data;
+	if (service->service && strcmp(service->service, "Dacast") == 0) {
+		if (service->key) {
+			struct dacast_ingest *ingest;
+			ingest = dacast_ingest(service->key);
+			return ingest->password;
+		}
+	}
+	return NULL;
+}
+
 struct obs_service_info rtmp_common_service = {
 	.id = "rtmp_common",
 	.get_name = rtmp_common_getname,
@@ -767,6 +812,8 @@ struct obs_service_info rtmp_common_service = {
 	.get_properties = rtmp_common_properties,
 	.get_url = rtmp_common_url,
 	.get_key = rtmp_common_key,
+	.get_username = rtmp_common_username,
+	.get_password = rtmp_common_password,
 	.apply_encoder_settings = rtmp_common_apply_settings,
 	.get_output_type = rtmp_common_get_output_type,
 	.get_supported_resolutions = rtmp_common_get_supported_resolutions,

+ 3 - 0
plugins/rtmp-services/rtmp-services-main.c

@@ -9,6 +9,7 @@
 #include "lookup-config.h"
 
 #include "service-specific/showroom.h"
+#include "service-specific/dacast.h"
 
 OBS_DECLARE_MODULE()
 OBS_MODULE_USE_DEFAULT_LOCALE("rtmp-services", "en-US")
@@ -73,6 +74,7 @@ static void refresh_callback(void *unused, calldata_t *cd)
 bool obs_module_load(void)
 {
 	init_twitch_data();
+	init_dacast_data();
 
 	dstr_copy(&module_name, "rtmp-services plugin (libobs ");
 	dstr_cat(&module_name, obs_get_version_string());
@@ -110,5 +112,6 @@ void obs_module_unload(void)
 	update_info_destroy(update_info);
 	unload_twitch_data();
 	free_showroom_data();
+	unload_dacast_data();
 	dstr_free(&module_name);
 }

+ 177 - 0
plugins/rtmp-services/service-specific/dacast.c

@@ -0,0 +1,177 @@
+#include <file-updater/file-updater.h>
+#include <util/threading.h>
+#include <util/platform.h>
+#include <util/dstr.h>
+#include <jansson.h>
+
+#include "dacast.h"
+
+#ifndef SEC_TO_NSEC
+#define SEC_TO_NSEC 1000000000ULL
+#endif
+
+static update_info_t *dacast_update_info = NULL;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool ingests_loaded = false;
+
+struct dacast_ingest_info {
+	char *key;
+	uint64_t last_time;
+	struct dacast_ingest ingest;
+};
+
+struct dacast_ingest dacast_invalid_ingest = {"rtmp://dacast", "", "",
+					      "fake_key"};
+
+static DARRAY(struct dacast_ingest_info) cur_ingests;
+
+static void free_ingest(struct dacast_ingest ingest)
+{
+	bfree((void *)ingest.url);
+	bfree((void *)ingest.username);
+	bfree((void *)ingest.password);
+	bfree((void *)ingest.streamkey);
+}
+
+static void free_ingests(void)
+{
+	for (size_t i = 0; i < cur_ingests.num; i++) {
+		struct dacast_ingest_info *info = &cur_ingests.array[i];
+		bfree(info->key);
+		free_ingest(info->ingest);
+	}
+	da_free(cur_ingests);
+}
+
+static struct dacast_ingest_info *find_ingest(const char *key)
+{
+	struct dacast_ingest_info *ret = NULL;
+	for (size_t i = 0; i < cur_ingests.num; i++) {
+		struct dacast_ingest_info *info = &cur_ingests.array[i];
+		if (strcmp(info->key, key) == 0) {
+			ret = info;
+			break;
+		}
+	}
+	return (struct dacast_ingest_info *)ret;
+}
+
+static bool load_ingests(const char *json, const char *key)
+{
+	json_t *root;
+	json_t *stream;
+	bool success = false;
+	struct dacast_ingest_info *info = find_ingest(key);
+	if (!info) {
+		info = da_push_back_new(cur_ingests);
+		info->key = bstrdup(key);
+	} else {
+		free_ingest(info->ingest);
+	}
+
+	root = json_loads(json, 0, NULL);
+	if (!root)
+		goto finish;
+
+	stream = json_object_get(root, "stream");
+	if (!stream)
+		goto finish;
+
+	json_t *item_server = json_object_get(stream, "server");
+	json_t *item_username = json_object_get(stream, "username");
+	json_t *item_password = json_object_get(stream, "password");
+	json_t *item_streamkey = json_object_get(stream, "streamkey");
+
+	if (!item_server || !item_username || !item_password || !item_streamkey)
+		goto finish;
+
+	const char *server = json_string_value(item_server);
+	const char *username = json_string_value(item_username);
+	const char *password = json_string_value(item_password);
+	const char *streamkey = json_string_value(item_streamkey);
+
+	info->ingest.url = bstrdup(server);
+	info->ingest.username = bstrdup(username);
+	info->ingest.password = bstrdup(password);
+	info->ingest.streamkey = bstrdup(streamkey);
+
+	info->last_time = os_gettime_ns() / SEC_TO_NSEC;
+
+	success = true;
+
+finish:
+	if (root)
+		json_decref(root);
+	return success;
+}
+
+static bool dacast_ingest_update(void *param, struct file_download_data *data)
+{
+	bool success;
+
+	pthread_mutex_lock(&mutex);
+	success = load_ingests((const char *)data->buffer.array,
+			       (const char *)param);
+	pthread_mutex_unlock(&mutex);
+
+	if (success) {
+		os_atomic_set_bool(&ingests_loaded, true);
+	}
+
+	return true;
+}
+
+struct dacast_ingest *dacast_ingest(const char *key)
+{
+	pthread_mutex_lock(&mutex);
+	struct dacast_ingest_info *info = find_ingest(key);
+	pthread_mutex_unlock(&mutex);
+	return info == NULL ? &dacast_invalid_ingest : &info->ingest;
+}
+
+void init_dacast_data(void)
+{
+	da_init(cur_ingests);
+	pthread_mutex_init(&mutex, NULL);
+}
+
+extern const char *get_module_name(void);
+
+#define TIMEOUT_SEC 3
+
+void dacast_ingests_load_data(const char *server, const char *key)
+{
+	struct dstr uri = {0};
+
+	os_atomic_set_bool(&ingests_loaded, false);
+
+	dstr_copy(&uri, server);
+	dstr_cat(&uri, key);
+
+	if (dacast_update_info) {
+		update_info_destroy(dacast_update_info);
+		dacast_update_info = NULL;
+	}
+
+	dacast_update_info = update_info_create_single(
+		"[dacast ingest load data] ", get_module_name(), uri.array,
+		dacast_ingest_update, (void *)key);
+
+	if (!os_atomic_load_bool(&ingests_loaded)) {
+		for (int i = 0; i < TIMEOUT_SEC * 100; i++) {
+			if (os_atomic_load_bool(&ingests_loaded)) {
+				break;
+			}
+			os_sleep_ms(10);
+		}
+	}
+
+	dstr_free(&uri);
+}
+
+void unload_dacast_data(void)
+{
+	update_info_destroy(dacast_update_info);
+	free_ingests();
+	pthread_mutex_destroy(&mutex);
+}

+ 14 - 0
plugins/rtmp-services/service-specific/dacast.h

@@ -0,0 +1,14 @@
+#pragma once
+
+struct dacast_ingest {
+	const char *url;
+	const char *username;
+	const char *password;
+	const char *streamkey;
+};
+
+extern void init_dacast_data(void);
+extern void unload_dacast_data(void);
+
+extern void dacast_ingests_load_data(const char *server, const char *key);
+extern struct dacast_ingest *dacast_ingest(const char *key);