From 4aa41ec854d09ef70283bc0fabbb39b45f020aae Mon Sep 17 00:00:00 2001 From: Sean DuBois Date: Fri, 12 Apr 2024 14:42:31 -0400 Subject: [PATCH] obs-webrtc: Add Link Header support WHIP/WHEP allows ICE Servers to be specified via Link Headers[0] [0] https://www.ietf.org/archive/id/draft-ietf-wish-whip-13.html#name-stun-turn-server-configurat Co-authored-by: Takeru Ohta --- plugins/obs-webrtc/whip-output.cpp | 93 +++++++++++++++++++++++++++++- plugins/obs-webrtc/whip-output.h | 2 + 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/plugins/obs-webrtc/whip-output.cpp b/plugins/obs-webrtc/whip-output.cpp index 48639c667..935824ea9 100644 --- a/plugins/obs-webrtc/whip-output.cpp +++ b/plugins/obs-webrtc/whip-output.cpp @@ -224,8 +224,13 @@ bool WHIPOutput::Init() */ bool WHIPOutput::Setup() { + rtc::Configuration cfg; - peer_connection = std::make_shared(); +#if RTC_VERSION_MAJOR == 0 && RTC_VERSION_MINOR > 20 || RTC_VERSION_MAJOR > 1 + cfg.disableAutoGathering = true; +#endif + + peer_connection = std::make_shared(cfg); peer_connection->onStateChange([this](rtc::PeerConnection::State state) { switch (state) { @@ -283,6 +288,68 @@ bool WHIPOutput::Setup() return true; } +// Given a Link header extract URL/Username/Credential and create rtc::IceServer +// ; username="user"; credential="myPassword"; +// +// https://www.ietf.org/archive/id/draft-ietf-wish-whip-13.html#section-4.4 +void WHIPOutput::ParseLinkHeader(std::string val, + std::vector &iceServers) +{ + std::string url, username, password; + + auto extractUrl = [](std::string input) -> std::string { + auto head = input.find("<") + 1; + auto tail = input.find(">"); + + if (head == std::string::npos || tail == std::string::npos) { + return ""; + } + return input.substr(head, tail - head); + }; + + auto extractValue = [](std::string input) -> std::string { + auto head = input.find("\"") + 1; + auto tail = input.find_last_of("\""); + + if (head == std::string::npos || tail == std::string::npos) { + return ""; + } + return input.substr(head, tail - head); + }; + + while (true) { + std::string token = val; + auto pos = token.find(";"); + if (pos != std::string::npos) { + token = val.substr(0, pos); + } + + if (token.find(" iceServers; + while ((h = curl_easy_nextheader(c, CURLH_HEADER, 0, prev))) { + if (astrcmpi("Link", h->name) == 0) { + auto value = std::string(h->value); + // Parse multiple links separated by ',' + for (auto end = value.find(","); + end != std::string::npos; end = value.find(",")) { + this->ParseLinkHeader(value.substr(0, end), + iceServers); + value = value.substr(end + 1); + } + this->ParseLinkHeader(value, iceServers); + } + prev = h; + } + // If Location header doesn't start with `http` it is a relative URL. // Construct a absolute URL using the host of the effective URL if (last_location_header.find("http") != 0) { @@ -446,6 +532,11 @@ bool WHIPOutput::Connect() return false; } cleanup(); + +#if RTC_VERSION_MAJOR == 0 && RTC_VERSION_MINOR > 20 || RTC_VERSION_MAJOR > 1 + peer_connection->gatherLocalCandidates(iceServers); +#endif + return true; } diff --git a/plugins/obs-webrtc/whip-output.h b/plugins/obs-webrtc/whip-output.h index 0f9a66e9e..88fd433ee 100644 --- a/plugins/obs-webrtc/whip-output.h +++ b/plugins/obs-webrtc/whip-output.h @@ -37,6 +37,8 @@ private: void StartThread(); void SendDelete(); void StopThread(bool signal); + void ParseLinkHeader(std::string linkHeader, + std::vector &iceServers); void Send(void *data, uintptr_t size, uint64_t duration, std::shared_ptr track,