Skip to content

Commit

Permalink
obs-webrtc: Add Link Header support
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Sean-Der and sile committed Jun 3, 2024
1 parent 64f6c30 commit 4a58c0e
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 1 deletion.
93 changes: 92 additions & 1 deletion plugins/obs-webrtc/whip-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,13 @@ bool WHIPOutput::Init()
*/
bool WHIPOutput::Setup()
{
rtc::Configuration cfg;

peer_connection = std::make_shared<rtc::PeerConnection>();
#if RTC_VERSION_MAJOR == 0 && RTC_VERSION_MINOR > 20 || RTC_VERSION_MAJOR > 1
cfg.disableAutoGathering = true;
#endif

peer_connection = std::make_shared<rtc::PeerConnection>(cfg);

peer_connection->onStateChange([this](rtc::PeerConnection::State state) {
switch (state) {
Expand Down Expand Up @@ -279,6 +284,68 @@ bool WHIPOutput::Setup()
return true;
}

// Given a Link header extract URL/Username/Credential and create rtc::IceServer
// <turn:turn.example.net>; 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<rtc::IceServer> &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("<turn:", 0) == 0) {
url = extractUrl(token);
} else if (token.find("username=") != std::string::npos) {
username = extractValue(token);
} else if (token.find("credential=") != std::string::npos) {
password = extractValue(token);
}

if (pos == std::string::npos) {
break;
}
val.erase(0, pos + 1);
}

try {
auto iceServer = rtc::IceServer(url);
iceServer.username = username;
iceServer.password = password;
iceServers.push_back(iceServer);
} catch (const std::invalid_argument &err) {
do_log(LOG_WARNING,
"Failed to construct ICE Server from %s: %s",
val.c_str(), err.what());
}
}

bool WHIPOutput::Connect()
{
struct curl_slist *headers = NULL;
Expand Down Expand Up @@ -368,6 +435,25 @@ bool WHIPOutput::Connect()
CURLU *url_builder = curl_url();
auto last_location_header = location_headers.back();

// Parse Link headers to extract STUN/TURN server configuration URLs
struct curl_header *prev = nullptr;
struct curl_header *h = nullptr;
std::vector<rtc::IceServer> 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) {
Expand Down Expand Up @@ -442,6 +528,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;
}

Expand Down
2 changes: 2 additions & 0 deletions plugins/obs-webrtc/whip-output.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class WHIPOutput {
void StartThread();
void SendDelete();
void StopThread(bool signal);
void ParseLinkHeader(std::string linkHeader,
std::vector<rtc::IceServer> &iceServers);

void Send(void *data, uintptr_t size, uint64_t duration,
std::shared_ptr<rtc::Track> track,
Expand Down

0 comments on commit 4a58c0e

Please sign in to comment.