Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PeerConnection::setConfiguration() method #920

Merged
merged 1 commit into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
191 changes: 117 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,44 @@ 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");

// Filter STUN servers
servers.erase(std::remove_if(servers.begin(), servers.end(),
[](const IceServer &server) {
return server.hostname.empty() ||
server.type != IceServer::Type::Turn;
}),
servers.end());

// Add TURN servers
for (auto &server : servers) {
if (mTURNServersAdded++ >= MAX_TURN_SERVERS_COUNT) {
break;
}
paullouisageneau marked this conversation as resolved.
Show resolved Hide resolved

addIceServer(server);
}
}

void IceTransport::addIceServer(IceServer server) {
if (server.hostname.empty() || server.type != IceServer::Type::Turn) {
PLOG_WARNING << "Only TURN servers are supported as additional ICE servers";
return;
}

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,8 +227,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);
std::shuffle(additionalIceServers.begin(), additionalIceServers.end(), utils::random_engine());

for (auto &server : additionalIceServers) {
paullouisageneau marked this conversation as resolved.
Show resolved Hide resolved
if (mTURNServersAdded++ >= MAX_TURN_SERVERS_COUNT) {
break;
}

addIceServer(server);
}

// Change state now as candidates calls can be synchronous
changeGatheringState(GatheringState::InProgress);
Expand Down Expand Up @@ -533,59 +559,17 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
break;
}

// Filter STUN servers
servers.erase(std::remove_if(servers.begin(), servers.end(),
[](const IceServer &server) {
return server.hostname.empty() ||
server.type != IceServer::Type::Turn;
}),
servers.end());

// 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);
addIceServer(server);
}

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

void IceTransport::addIceServer(IceServer server) {
if (server.hostname.empty() || server.type != IceServer::Type::Turn) {
PLOG_WARNING << "Only TURN servers are supported as additional ICE servers";
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,8 +722,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);
std::shuffle(additionalIceServers.begin(), additionalIceServers.end(), utils::random_engine());

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

// Change state now as candidates calls can be synchronous
changeGatheringState(GatheringState::InProgress);
Expand Down
5 changes: 4 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 addIceServer(IceServer server);

Description::Role mRole;
string mMid;
std::chrono::milliseconds mTrickleTimeout;
Expand All @@ -79,6 +81,7 @@ class IceTransport : public Transport {

#if !USE_NICE
unique_ptr<juice_agent_t, void (*)(juice_agent_t *)> mAgent;
int mTURNServersAdded = 0;

static void StateChangeCallback(juice_agent_t *agent, juice_state_t state, void *user_ptr);
static void CandidateCallback(juice_agent_t *agent, const char *sdp, void *user_ptr);
Expand Down
15 changes: 14 additions & 1 deletion src/peerconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,24 @@ 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()->getIceTransport();
if (!iceTransport) {
throw std::logic_error("No IceTransport. Local Description has not been set");
}

if (impl()->gatheringState == GatheringState::New) {
iceTransport->gatherLocalCandidates(impl()->localBundleMid(), additionalIceServers);
} else {
PLOG_WARNING << "Candidates gathering already started";
}
paullouisageneau marked this conversation as resolved.
Show resolved Hide resolved
}

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