Browse Source

Merge pull request #1914 from YouNow/master

rtmp-services: Add YouNow service and implement ingest lookup
Jim 6 years ago
parent
commit
0f8472e8a8

+ 9 - 1
plugins/rtmp-services/CMakeLists.txt

@@ -1,15 +1,21 @@
 project(rtmp-services)
 
+find_package(Libcurl REQUIRED)
+
+include_directories(${LIBCURL_INCLUDE_DIRS})
+
 include_directories(${OBS_JANSSON_INCLUDE_DIRS})
 
 set(rtmp-services_SOURCES
 	twitch.c
+	younow.c
 	rtmp-common.c
 	rtmp-custom.c
 	rtmp-services-main.c)
 
 set(rtmp-services_HEADERS
 	twitch.h
+	younow.h
 	rtmp-format-ver.h)
 
 set(RTMP_SERVICES_URL
@@ -28,10 +34,12 @@ add_library(rtmp-services MODULE
 	${rtmp-services_SOURCES}
 	${rtmp-services_HEADERS}
 	${rtmp-services_config_HEADERS})
+
 target_link_libraries(rtmp-services
 	libobs
 	file-updater
-	${OBS_JANSSON_IMPORT})
+	${OBS_JANSSON_IMPORT}
+	${LIBCURL_LIBRARIES})
 
 target_include_directories(rtmp-services
 	PUBLIC

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

@@ -1514,6 +1514,24 @@
                 "x264opts": "tune=zerolatency"
             }
         },
+        {
+            "name": "YouNow",
+            "common": false,
+            "servers": [
+                {
+                    "name": "younow.com",
+                    "url": "https://signaling-api.younow-prod.video.propsproject.com/api/v1/ingest/server/"
+                }
+            ],
+            "recommended": {
+                "keyint": 2,
+                "output": "ftl_output",
+                "max audio bitrate": 160,
+                "max video bitrate": 7000,
+                "profile": "main",
+                "bframes": 0
+            }
+        },
         {
             "name": "Steam",
             "common": false,

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

@@ -5,6 +5,7 @@
 
 #include "rtmp-format-ver.h"
 #include "twitch.h"
+#include "younow.h"
 
 struct rtmp_common {
 	char *service;
@@ -596,6 +597,12 @@ static const char *rtmp_common_url(void *data)
 		}
 	}
 
+	if (service->service && strcmp(service->service, "YouNow") == 0) {
+		if (service->server && service->key) {
+			return younow_get_ingest(service->server, service->key);
+		}
+	}
+
 	return service->server;
 }
 

+ 113 - 0
plugins/rtmp-services/younow.c

@@ -0,0 +1,113 @@
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <util/dstr.h>
+#include "util/base.h"
+#include "younow.h"
+
+struct younow_mem_struct {
+	char *memory;
+	size_t size;
+};
+
+static char *current_ingest = NULL;
+
+static size_t younow_write_cb(void *contents, size_t size, size_t nmemb,
+			      void *userp)
+{
+	size_t realsize = size * nmemb;
+	struct younow_mem_struct *mem = (struct younow_mem_struct *)userp;
+
+	mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+	if (mem->memory == NULL) {
+		blog(LOG_WARNING, "yyounow_write_cb: realloc returned NULL");
+		return 0;
+	}
+
+	memcpy(&(mem->memory[mem->size]), contents, realsize);
+	mem->size += realsize;
+	mem->memory[mem->size] = 0;
+
+	return realsize;
+}
+
+const char *younow_get_ingest(const char *server, const char *key)
+{
+	CURL *curl_handle;
+	CURLcode res;
+	struct younow_mem_struct chunk;
+	struct dstr uri;
+	long response_code;
+
+	// find the delimiter in stream key
+	const char *delim = strchr(key, '_');
+	if (delim == NULL) {
+		blog(LOG_WARNING,
+		     "younow_get_ingest: delimiter not found in stream key");
+		return server;
+	}
+
+	curl_handle = curl_easy_init();
+
+	chunk.memory = malloc(1); /* will be grown as needed by realloc */
+	chunk.size = 0;           /* no data at this point */
+
+	dstr_init(&uri);
+	dstr_copy(&uri, server);
+	dstr_ncat(&uri, key, delim - key);
+
+	curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
+	curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
+	curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
+	curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 3L);
+	curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, younow_write_cb);
+	curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
+
+#if LIBCURL_VERSION_NUM >= 0x072400
+	// A lot of servers don't yet support ALPN
+	curl_easy_setopt(curl_handle, CURLOPT_SSL_ENABLE_ALPN, 0);
+#endif
+
+	res = curl_easy_perform(curl_handle);
+	dstr_free(&uri);
+
+	if (res != CURLE_OK) {
+		blog(LOG_WARNING,
+		     "younow_get_ingest: curl_easy_perform() failed: %s",
+		     curl_easy_strerror(res));
+		curl_easy_cleanup(curl_handle);
+		free(chunk.memory);
+		return server;
+	}
+
+	curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
+	if (response_code != 200) {
+		blog(LOG_WARNING,
+		     "younow_get_ingest: curl_easy_perform() returned code: %ld",
+		     response_code);
+		curl_easy_cleanup(curl_handle);
+		free(chunk.memory);
+		return server;
+	}
+
+	curl_easy_cleanup(curl_handle);
+
+	if (chunk.size == 0) {
+		blog(LOG_WARNING,
+		     "younow_get_ingest: curl_easy_perform() returned empty response");
+		free(chunk.memory);
+		return server;
+	}
+
+	if (current_ingest) {
+		free(current_ingest);
+		current_ingest = NULL;
+	}
+
+	current_ingest = strdup(chunk.memory);
+	free(chunk.memory);
+	blog(LOG_INFO, "younow_get_ingest: returning ingest: %s",
+	     current_ingest);
+	return current_ingest;
+}

+ 3 - 0
plugins/rtmp-services/younow.h

@@ -0,0 +1,3 @@
+#pragma once
+
+extern const char *younow_get_ingest(const char *server, const char *key);