Skip to content

Commit

Permalink
Add disableAutoGathering
Browse files Browse the repository at this point in the history
When enabled PeerConnection::gatherLocalCandidates must be called
explicitly to start the gathering process. This new API enabled ICE
Servers to be used with WHIP/WHEP.

For WHIP/WHEP the ICE Servers is only provided after the client makes
the initial offer.
  • Loading branch information
Sean-Der committed Apr 15, 2024
1 parent fe7bec8 commit f9abd05
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 76 deletions.
1 change: 1 addition & 0 deletions include/rtc/configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct RTC_CPP_EXPORT Configuration {
bool enableIceTcp = false; // libnice only
bool enableIceUdpMux = false; // libjuice only
bool disableAutoNegotiation = false;
bool disableAutoGathering = false;
bool forceMediaTransport = false;

// Port range
Expand Down
1 change: 1 addition & 0 deletions include/rtc/peerconnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class RTC_CPP_EXPORT PeerConnection final : CheshireCat<impl::PeerConnection> {
void setLocalDescription(Description::Type type = Description::Type::Unspec);
void setRemoteDescription(Description description);
void addRemoteCandidate(Candidate candidate);
void gatherLocalCandidates(std::vector<IceServer> additionalIceServers = {});

void setMediaHandler(shared_ptr<MediaHandler> handler);
shared_ptr<MediaHandler> getMediaHandler();
Expand Down
168 changes: 94 additions & 74 deletions src/impl/icetransport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,27 +117,6 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
}
}

juice_turn_server_t turn_servers[MAX_TURN_SERVERS_COUNT];
std::memset(turn_servers, 0, sizeof(turn_servers));

// Add TURN servers
int k = 0;
for (auto &server : servers) {
if (!server.hostname.empty() && server.type == IceServer::Type::Turn) {
if (server.port == 0)
server.port = 3478; // TURN UDP port
PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\"";
turn_servers[k].host = server.hostname.c_str();
turn_servers[k].username = server.username.c_str();
turn_servers[k].password = server.password.c_str();
turn_servers[k].port = server.port;
if (++k >= MAX_TURN_SERVERS_COUNT)
break;
}
}
jconfig.turn_servers = k > 0 ? turn_servers : nullptr;
jconfig.turn_servers_count = k;

// Bind address
if (config.bindAddress) {
jconfig.bind_address = config.bindAddress->c_str();
Expand All @@ -154,6 +133,32 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
mAgent = decltype(mAgent)(juice_create(&jconfig), juice_destroy);
if (!mAgent)
throw std::runtime_error("Failed to create the ICE agent");

// Add TURN servers
int k = 0;
for (auto &server : servers) {
addTURNServer(server);
if (++k >= MAX_TURN_SERVERS_COUNT) {
break;
}
}
}

void IceTransport::addTURNServer(IceServer server) {
if (!server.hostname.empty() && server.type == IceServer::Type::Turn) {
if (server.port == 0)
server.port = 3478; // TURN UDP port
PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\"";
juice_turn_server_t turn_server = {};
turn_server.host = server.hostname.c_str();
turn_server.username = server.username.c_str();
turn_server.password = server.password.c_str();
turn_server.port = server.port;

if (juice_add_turn_server(mAgent.get(), &turn_server) != 0) {
throw std::runtime_error("Failed to add TURN server");
}
}
}

IceTransport::~IceTransport() {
Expand Down Expand Up @@ -210,9 +215,17 @@ bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
return juice_add_remote_candidate(mAgent.get(), string(candidate).c_str()) >= 0;
}

void IceTransport::gatherLocalCandidates(string mid) {
void IceTransport::gatherLocalCandidates(string mid, std::vector<IceServer> additionalIceServers) {
mMid = std::move(mid);

int k = 0;
for (auto &server : additionalIceServers) {
addTURNServer(server);
if (++k >= MAX_TURN_SERVERS_COUNT) {
break;
}
}

// Change state now as candidates calls can be synchronous
changeGatheringState(GatheringState::InProgress);

Expand Down Expand Up @@ -535,57 +548,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi

// Add TURN servers
for (auto &server : servers) {
if (server.hostname.empty())
continue;
if (server.type != IceServer::Type::Turn)
continue;
if (server.port == 0)
server.port = server.relayType == IceServer::RelayType::TurnTls ? 5349 : 3478;

struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype =
server.relayType == IceServer::RelayType::TurnUdp ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol =
server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP;
hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *result = nullptr;
if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints,
&result) != 0) {
PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':'
<< server.port;
continue;
}

for (auto p = result; p; p = p->ai_next) {
if (p->ai_family == AF_INET || p->ai_family == AF_INET6) {
char nodebuffer[MAX_NUMERICNODE_LEN];
char servbuffer[MAX_NUMERICSERV_LEN];
if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
servbuffer, MAX_NUMERICSERV_LEN,
NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port
<< "\"";
NiceRelayType niceRelayType;
switch (server.relayType) {
case IceServer::RelayType::TurnTcp:
niceRelayType = NICE_RELAY_TYPE_TURN_TCP;
break;
case IceServer::RelayType::TurnTls:
niceRelayType = NICE_RELAY_TYPE_TURN_TLS;
break;
default:
niceRelayType = NICE_RELAY_TYPE_TURN_UDP;
break;
}
nice_agent_set_relay_info(mNiceAgent.get(), mStreamId, 1, nodebuffer,
std::stoul(servbuffer), server.username.c_str(),
server.password.c_str(), niceRelayType);
}
}
}

freeaddrinfo(result);
addTURNServer(server);
}

g_signal_connect(G_OBJECT(mNiceAgent.get()), "component-state-changed",
Expand All @@ -603,6 +566,59 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
RecvCallback, this);
}

void IceTransport::addTURNServer(IceServer server) {
if (server.hostname.empty())
return;
if (server.type != IceServer::Type::Turn)
return;
if (server.port == 0)
server.port = server.relayType == IceServer::RelayType::TurnTls ? 5349 : 3478;

struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype =
server.relayType == IceServer::RelayType::TurnUdp ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol =
server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP;
hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *result = nullptr;
if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints,
&result) != 0) {
PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':'
<< server.port;
return;
}

for (auto p = result; p; p = p->ai_next) {
if (p->ai_family == AF_INET || p->ai_family == AF_INET6) {
char nodebuffer[MAX_NUMERICNODE_LEN];
char servbuffer[MAX_NUMERICSERV_LEN];
if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, servbuffer,
MAX_NUMERICSERV_LEN, NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port
<< "\"";
NiceRelayType niceRelayType;
switch (server.relayType) {
case IceServer::RelayType::TurnTcp:
niceRelayType = NICE_RELAY_TYPE_TURN_TCP;
break;
case IceServer::RelayType::TurnTls:
niceRelayType = NICE_RELAY_TYPE_TURN_TLS;
break;
default:
niceRelayType = NICE_RELAY_TYPE_TURN_UDP;
break;
}
nice_agent_set_relay_info(mNiceAgent.get(), mStreamId, 1, nodebuffer,
std::stoul(servbuffer), server.username.c_str(),
server.password.c_str(), niceRelayType);
}
}
}

freeaddrinfo(result);
}

IceTransport::~IceTransport() {
PLOG_DEBUG << "Destroying ICE transport";
nice_agent_attach_recv(mNiceAgent.get(), mStreamId, 1, g_main_loop_get_context(MainLoop.get()),
Expand Down Expand Up @@ -684,9 +700,13 @@ bool IceTransport::addRemoteCandidate(const Candidate &candidate) {
return ret > 0;
}

void IceTransport::gatherLocalCandidates(string mid) {
void IceTransport::gatherLocalCandidates(string mid, std::vector<IceServer> additionalIceServers) {
mMid = std::move(mid);

for (auto &server : additionalIceServers) {
addTURNServer(server);
}

// Change state now as candidates calls can be synchronous
changeGatheringState(GatheringState::InProgress);

Expand Down
4 changes: 3 additions & 1 deletion src/impl/icetransport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class IceTransport : public Transport {
Description getLocalDescription(Description::Type type) const;
void setRemoteDescription(const Description &description);
bool addRemoteCandidate(const Candidate &candidate);
void gatherLocalCandidates(string mid);
void gatherLocalCandidates(string mid, std::vector<IceServer> additionalIceServers = {});

optional<string> getLocalAddress() const;
optional<string> getRemoteAddress() const;
Expand All @@ -69,6 +69,8 @@ class IceTransport : public Transport {
void processGatheringDone();
void processTimeout();

void addTURNServer(IceServer server);

Description::Role mRole;
string mMid;
std::chrono::milliseconds mTrickleTimeout;
Expand Down
12 changes: 11 additions & 1 deletion src/peerconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,21 @@ void PeerConnection::setLocalDescription(Description::Type type) {
impl()->changeSignalingState(newSignalingState);
signalingLock.unlock();

if (impl()->gatheringState == GatheringState::New) {
if (impl()->gatheringState == GatheringState::New && !impl()->config.disableAutoGathering) {
iceTransport->gatherLocalCandidates(impl()->localBundleMid());
}
}

void PeerConnection::gatherLocalCandidates(std::vector<IceServer> additionalIceServers) {
auto iceTransport = impl()->initIceTransport();
if (!iceTransport)
return; // closed

if (impl()->gatheringState == GatheringState::New) {
iceTransport->gatherLocalCandidates(impl()->localBundleMid(), additionalIceServers);
}
}

void PeerConnection::setRemoteDescription(Description description) {
std::unique_lock signalingLock(impl()->signalingMutex);
PLOG_VERBOSE << "Setting remote description: " << string(description);
Expand Down

0 comments on commit f9abd05

Please sign in to comment.