Browse Source

Enhance candidate parsing and expose the info directly

Paul-Louis Ageneau 4 years ago
parent
commit
137d4e3e8e

+ 3 - 5
examples/copy-paste/answerer.cpp

@@ -127,13 +127,11 @@ int main(int argc, char **argv) {
 				cout << "** Channel is not Open ** ";
 				cout << "** Channel is not Open ** ";
 				break;
 				break;
 			}
 			}
-			CandidateInfo local, remote;
+			Candidate local, remote;
 			std::optional<std::chrono::milliseconds> rtt = pc->rtt();
 			std::optional<std::chrono::milliseconds> rtt = pc->rtt();
 			if (pc->getSelectedCandidatePair(&local, &remote)) {
 			if (pc->getSelectedCandidatePair(&local, &remote)) {
-				cout << "Local: " << local.address << ":" << local.port << " " << local.type << " "
-				     << local.transportType << endl;
-				cout << "Remote: " << remote.address << ":" << remote.port << " " << remote.type
-				     << " " << remote.transportType << endl;
+				cout << "Local: " << local << endl;
+				cout << "Remote: " << remote << endl;
 				cout << "Bytes Sent:" << pc->bytesSent()
 				cout << "Bytes Sent:" << pc->bytesSent()
 				     << " / Bytes Received:" << pc->bytesReceived() << " / Round-Trip Time:";
 				     << " / Bytes Received:" << pc->bytesReceived() << " / Round-Trip Time:";
 				if (rtt.has_value())
 				if (rtt.has_value())

+ 3 - 5
examples/copy-paste/offerer.cpp

@@ -127,13 +127,11 @@ int main(int argc, char **argv) {
 				cout << "** Channel is not Open ** ";
 				cout << "** Channel is not Open ** ";
 				break;
 				break;
 			}
 			}
-			CandidateInfo local, remote;
+			Candidate local, remote;
 			std::optional<std::chrono::milliseconds> rtt = pc->rtt();
 			std::optional<std::chrono::milliseconds> rtt = pc->rtt();
 			if (pc->getSelectedCandidatePair(&local, &remote)) {
 			if (pc->getSelectedCandidatePair(&local, &remote)) {
-				cout << "Local: " << local.address << ":" << local.port << " " << local.type << " "
-				     << local.transportType << endl;
-				cout << "Remote: " << remote.address << ":" << remote.port << " " << remote.type
-				     << " " << remote.transportType << endl;
+				cout << "Local: " << local << endl;
+				cout << "Remote: " << remote << endl;
 				cout << "Bytes Sent:" << pc->bytesSent()
 				cout << "Bytes Sent:" << pc->bytesSent()
 				     << " / Bytes Received:" << pc->bytesReceived() << " / Round-Trip Time:";
 				     << " / Bytes Received:" << pc->bytesReceived() << " / Round-Trip Time:";
 				if (rtt.has_value())
 				if (rtt.has_value())

+ 22 - 14
include/rtc/candidate.hpp

@@ -25,38 +25,46 @@
 
 
 namespace rtc {
 namespace rtc {
 
 
-enum class CandidateType { Host = 0, ServerReflexive, PeerReflexive, Relayed };
-enum class CandidateTransportType { Udp = 0, TcpActive, TcpPassive, TcpSo };
-struct CandidateInfo {
-	string address;
-	int port;
-	CandidateType type;
-	CandidateTransportType transportType;
-};
-
 class Candidate {
 class Candidate {
 public:
 public:
-	Candidate(string candidate, string mid = "");
+	enum class Family { Unresolved, Ipv4, Ipv6 };
+	enum class Type { Unknown, Host, ServerReflexive, PeerReflexive, Relayed };
+	enum class TransportType { Unknown, Udp, TcpActive, TcpPassive, TcpSo, TcpUnknown };
+
+	Candidate(string candidate = "", string mid = "");
 
 
 	enum class ResolveMode { Simple, Lookup };
 	enum class ResolveMode { Simple, Lookup };
 	bool resolve(ResolveMode mode = ResolveMode::Simple);
 	bool resolve(ResolveMode mode = ResolveMode::Simple);
-	bool isResolved() const;
 
 
 	string candidate() const;
 	string candidate() const;
 	string mid() const;
 	string mid() const;
 	operator string() const;
 	operator string() const;
 
 
+	bool isResolved() const;
+	Family family() const;
+	Type type() const;
+	std::optional<string> address() const;
+	std::optional<uint16_t> port() const;
+	std::optional<uint32_t> priority() const;
+
 private:
 private:
 	string mCandidate;
 	string mCandidate;
 	string mMid;
 	string mMid;
-	bool mIsResolved;
+
+	// Extracted on resolution
+	Family mFamily;
+	Type mType;
+	TransportType mTransportType;
+	string mAddress;
+	uint16_t mPort;
+	uint32_t mPriority;
 };
 };
 
 
 } // namespace rtc
 } // namespace rtc
 
 
 std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate);
 std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate);
-std::ostream &operator<<(std::ostream &out, const rtc::CandidateType &type);
-std::ostream &operator<<(std::ostream &out, const rtc::CandidateTransportType &transportType);
+std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type);
+std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType);
 
 
 #endif
 #endif
 
 

+ 2 - 1
include/rtc/description.hpp

@@ -74,7 +74,7 @@ public:
 		void setDirection(Direction dir);
 		void setDirection(Direction dir);
 
 
 		operator string() const;
 		operator string() const;
-		string generateSdp(string_view eol) const;
+		string generateSdp(string_view eol, string_view addr, string_view port) const;
 
 
 		virtual void parseSdpLine(string_view line);
 		virtual void parseSdpLine(string_view line);
 
 
@@ -194,6 +194,7 @@ public:
 	Application *application();
 	Application *application();
 
 
 private:
 private:
+	std::optional<Candidate> defaultCandidate() const;
 	std::shared_ptr<Entry> createEntry(string mline, string mid, Direction dir);
 	std::shared_ptr<Entry> createEntry(string mline, string mid, Direction dir);
 	void removeApplication();
 	void removeApplication();
 
 

+ 1 - 1
include/rtc/peerconnection.hpp

@@ -112,7 +112,7 @@ public:
 	void onTrack(std::function<void(std::shared_ptr<Track> track)> callback);
 	void onTrack(std::function<void(std::shared_ptr<Track> track)> callback);
 
 
 	// libnice only
 	// libnice only
-	bool getSelectedCandidatePair(CandidateInfo *local, CandidateInfo *remote);
+	bool getSelectedCandidatePair(Candidate *local, Candidate *remote);
 
 
 private:
 private:
 	std::shared_ptr<IceTransport> initIceTransport(Description::Role role);
 	std::shared_ptr<IceTransport> initIceTransport(Description::Role role);

+ 98 - 29
src/candidate.cpp

@@ -21,6 +21,7 @@
 #include <algorithm>
 #include <algorithm>
 #include <array>
 #include <array>
 #include <sstream>
 #include <sstream>
+#include <unordered_map>
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #include <winsock2.h>
 #include <winsock2.h>
@@ -47,7 +48,10 @@ inline bool hasprefix(const string &str, const string &prefix) {
 
 
 namespace rtc {
 namespace rtc {
 
 
-Candidate::Candidate(string candidate, string mid) : mIsResolved(false) {
+Candidate::Candidate(string candidate, string mid)
+    : mFamily(Family::Unresolved), mType(Type::Unknown), mTransportType(TransportType::Unknown),
+      mPort(0), mPriority(0) {
+
 	const std::array prefixes{"a=", "candidate:"};
 	const std::array prefixes{"a=", "candidate:"};
 	for (const string &prefix : prefixes)
 	for (const string &prefix : prefixes)
 		if (hasprefix(candidate, prefix))
 		if (hasprefix(candidate, prefix))
@@ -58,9 +62,24 @@ Candidate::Candidate(string candidate, string mid) : mIsResolved(false) {
 }
 }
 
 
 bool Candidate::resolve(ResolveMode mode) {
 bool Candidate::resolve(ResolveMode mode) {
-	if (mIsResolved)
+	using TypeMap_t = std::unordered_map<string, Type>;	
+	using TcpTypeMap_t = std::unordered_map<string, TransportType>;
+
+	static const TypeMap_t TypeMap = {{"host", Type::Host},
+	                                  {"srflx", Type::ServerReflexive},
+	                                  {"prflx", Type::PeerReflexive},
+	                                  {"relay", Type::Relayed}};
+
+	static const TcpTypeMap_t TcpTypeMap = {{"active", TransportType::TcpActive},
+	                                        {"passive", TransportType::TcpPassive},
+	                                        {"so", TransportType::TcpSo}};
+
+	if (mFamily != Family::Unresolved)
 		return true;
 		return true;
 
 
+	if(mCandidate.empty())
+		throw std::logic_error("Candidate is empty");
+
 	PLOG_VERBOSE << "Resolving candidate (mode="
 	PLOG_VERBOSE << "Resolving candidate (mode="
 				 << (mode == ResolveMode::Simple ? "simple" : "lookup")
 				 << (mode == ResolveMode::Simple ? "simple" : "lookup")
 				 << "): " << mCandidate;
 				 << "): " << mCandidate;
@@ -75,16 +94,39 @@ bool Candidate::resolve(ResolveMode mode) {
 		string left;
 		string left;
 		std::getline(iss, left);
 		std::getline(iss, left);
 
 
+		if (auto it = TypeMap.find(type); it != TypeMap.end())
+			mType = it->second;
+		else
+			mType = Type::Unknown;
+		
+		if (transport == "UDP" || transport == "udp") {
+			mTransportType = TransportType::Udp;
+		}
+		else if (transport == "TCP" || transport == "tcp") {
+			std::istringstream iss(left);
+			string tcptype_, tcptype;
+			if(iss >> tcptype_ >> tcptype && tcptype_ == "tcptype") {
+				if (auto it = TcpTypeMap.find(tcptype); it != TcpTypeMap.end())
+					mTransportType = it->second;
+				else 
+					mTransportType = TransportType::TcpUnknown;
+
+			} else {
+				mTransportType = TransportType::TcpUnknown;
+			}
+		} else {
+			mTransportType = TransportType::Unknown;
+		}
+
 		// Try to resolve the node
 		// Try to resolve the node
 		struct addrinfo hints = {};
 		struct addrinfo hints = {};
 		hints.ai_family = AF_UNSPEC;
 		hints.ai_family = AF_UNSPEC;
 		hints.ai_flags = AI_ADDRCONFIG;
 		hints.ai_flags = AI_ADDRCONFIG;
-		if (transport == "UDP" || transport == "udp") {
+		if (mTransportType == TransportType::Udp) {
 			hints.ai_socktype = SOCK_DGRAM;
 			hints.ai_socktype = SOCK_DGRAM;
 			hints.ai_protocol = IPPROTO_UDP;
 			hints.ai_protocol = IPPROTO_UDP;
 		}
 		}
-
-		if (transport == "TCP" || transport == "tcp") {
+		else if (mTransportType != TransportType::Unknown) {
 			hints.ai_socktype = SOCK_STREAM;
 			hints.ai_socktype = SOCK_STREAM;
 			hints.ai_protocol = IPPROTO_TCP;
 			hints.ai_protocol = IPPROTO_TCP;
 		}
 		}
@@ -102,13 +144,18 @@ bool Candidate::resolve(ResolveMode mode) {
 					if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer,
 					if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer,
 					                MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN,
 					                MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN,
 					                NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
 					                NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
+						
+						mAddress = nodebuffer;
+						mPort = uint16_t(std::stoul(servbuffer));
+						mFamily = p->ai_family == AF_INET6 ? Family::Ipv6 : Family::Ipv4;
+						
 						const char sp{' '};
 						const char sp{' '};
 						std::ostringstream oss;
 						std::ostringstream oss;
 						oss << foundation << sp << component << sp << transport << sp << priority;
 						oss << foundation << sp << component << sp << transport << sp << priority;
 						oss << sp << nodebuffer << sp << servbuffer << sp << "typ" << sp << type;
 						oss << sp << nodebuffer << sp << servbuffer << sp << "typ" << sp << type;
 						oss << left;
 						oss << left;
 						mCandidate = oss.str();
 						mCandidate = oss.str();
-						mIsResolved = true;
+
 						PLOG_VERBOSE << "Resolved candidate: " << mCandidate;
 						PLOG_VERBOSE << "Resolved candidate: " << mCandidate;
 						break;
 						break;
 					}
 					}
@@ -119,11 +166,9 @@ bool Candidate::resolve(ResolveMode mode) {
 		}
 		}
 	}
 	}
 
 
-	return mIsResolved;
+	return mFamily != Family::Unresolved;
 }
 }
 
 
-bool Candidate::isResolved() const { return mIsResolved; }
-
 string Candidate::candidate() const { return "candidate:" + mCandidate; }
 string Candidate::candidate() const { return "candidate:" + mCandidate; }
 
 
 string Candidate::mid() const { return mMid; }
 string Candidate::mid() const { return mMid; }
@@ -134,38 +179,62 @@ Candidate::operator string() const {
 	return line.str();
 	return line.str();
 }
 }
 
 
+bool Candidate::isResolved() const { return mFamily != Family::Unresolved; }
+
+Candidate::Family Candidate::family() const {
+	return mFamily;
+
+}
+Candidate::Type Candidate::type() const {
+	return mType;
+}
+
+std::optional<string> Candidate::address() const {
+	return isResolved() ? std::make_optional(mAddress) : nullopt;
+}
+
+std::optional<uint16_t> Candidate::port() const {
+	return isResolved() ? std::make_optional(mPort) : nullopt;
+}
+
+std::optional<uint32_t> Candidate::priority() const {
+	return isResolved() ? std::make_optional(mPriority) : nullopt;
+}
+
 } // namespace rtc
 } // namespace rtc
 
 
 std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate) {
 std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate) {
 	return out << std::string(candidate);
 	return out << std::string(candidate);
 }
 }
 
 
-std::ostream &operator<<(std::ostream &out, const rtc::CandidateType &type) {
+std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type) {
 	switch (type) {
 	switch (type) {
-	case rtc::CandidateType::Host:
-		return out << "Host";
-	case rtc::CandidateType::PeerReflexive:
-		return out << "PeerReflexive";
-	case rtc::CandidateType::Relayed:
-		return out << "Relayed";
-	case rtc::CandidateType::ServerReflexive:
-		return out << "ServerReflexive";
+	case rtc::Candidate::Type::Host:
+		return out << "host";
+	case rtc::Candidate::Type::PeerReflexive:
+		return out << "peer_reflexive";
+	case rtc::Candidate::Type::ServerReflexive:
+		return out << "server_reflexive";
+	case rtc::Candidate::Type::Relayed:
+		return out << "relayed";
 	default:
 	default:
-		return out << "Unknown";
+		return out << "unknown";
 	}
 	}
 }
 }
 
 
-std::ostream &operator<<(std::ostream &out, const rtc::CandidateTransportType &transportType) {
+std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType) {
 	switch (transportType) {
 	switch (transportType) {
-	case rtc::CandidateTransportType::TcpActive:
-		return out << "TcpActive";
-	case rtc::CandidateTransportType::TcpPassive:
-		return out << "TcpPassive";
-	case rtc::CandidateTransportType::TcpSo:
-		return out << "TcpSo";
-	case rtc::CandidateTransportType::Udp:
-		return out << "Udp";
+	case rtc::Candidate::TransportType::Udp:
+		return out << "UDP";
+	case rtc::Candidate::TransportType::TcpActive:
+		return out << "TCP_active";
+	case rtc::Candidate::TransportType::TcpPassive:
+		return out << "TCP_passive";
+	case rtc::Candidate::TransportType::TcpSo:
+		return out << "TCP_so";
+	case rtc::Candidate::TransportType::TcpUnknown:
+		return out << "TCP_unknown";
 	default:
 	default:
-		return out << "Unknown";
+		return out << "unknown";
 	}
 	}
 }
 }

+ 36 - 7
src/description.cpp

@@ -227,10 +227,18 @@ string Description::generateSdp(string_view eol) const {
 	if (mFingerprint)
 	if (mFingerprint)
 		sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol;
 		sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol;
 
 
+	auto cand = defaultCandidate();
+	const string addr = cand && cand->isResolved()
+	                        ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") +
+	                           " " + *cand->address())
+	                        : "IP4 0.0.0.0";
+	const string port = std::to_string(
+	    cand && cand->isResolved() ? *cand->port() : 9); // Port 9 is the discard protocol
+
 	// Entries
 	// Entries
 	bool first = true;
 	bool first = true;
 	for (const auto &entry : mEntries) {
 	for (const auto &entry : mEntries) {
-		sdp << entry->generateSdp(eol);
+		sdp << entry->generateSdp(eol, addr, port);
 
 
 		if (std::exchange(first, false)) {
 		if (std::exchange(first, false)) {
 			// Candidates
 			// Candidates
@@ -254,9 +262,17 @@ string Description::generateApplicationSdp(string_view eol) const {
 	sdp << "s=-" << eol;
 	sdp << "s=-" << eol;
 	sdp << "t=0 0" << eol;
 	sdp << "t=0 0" << eol;
 
 
+	auto cand = defaultCandidate();
+	const string addr = cand && cand->isResolved()
+	                        ? (string(cand->family() == Candidate::Family::Ipv6 ? "IP6" : "IP4") +
+	                           " " + *cand->address())
+	                        : "IP4 0.0.0.0";
+	const string port = std::to_string(
+	    cand && cand->isResolved() ? *cand->port() : 9); // Port 9 is the discard protocol
+
 	// Application
 	// Application
 	auto app = mApplication ? mApplication : std::make_shared<Application>();
 	auto app = mApplication ? mApplication : std::make_shared<Application>();
-	sdp << app->generateSdp(eol);
+	sdp << app->generateSdp(eol, addr, port);
 
 
 	// Session-level attributes
 	// Session-level attributes
 	sdp << "a=msid-semantic:WMS *" << eol;
 	sdp << "a=msid-semantic:WMS *" << eol;
@@ -280,6 +296,20 @@ string Description::generateApplicationSdp(string_view eol) const {
 	return sdp.str();
 	return sdp.str();
 }
 }
 
 
+std::optional<Candidate> Description::defaultCandidate() const {
+	// Return the first host candidate with highest priority, favoring IPv4
+	std::optional<Candidate> result;
+	for(const auto &c : mCandidates) {
+		if(c.type() == Candidate::Type::Host) {
+			if(!result
+				|| (result->family() == Candidate::Family::Ipv6 && c.family() == Candidate::Family::Ipv4)
+				|| (result->family() == c.family() && result->priority() < c.priority()))
+				result.emplace(c);
+		}
+	}
+	return result;
+}
+
 shared_ptr<Description::Entry> Description::createEntry(string mline, string mid, Direction dir) {
 shared_ptr<Description::Entry> Description::createEntry(string mline, string mid, Direction dir) {
 	string type = mline.substr(0, mline.find(' '));
 	string type = mline.substr(0, mline.find(' '));
 	if (type == "application") {
 	if (type == "application") {
@@ -390,13 +420,12 @@ Description::Entry::Entry(const string &mline, string mid, Direction dir)
 
 
 void Description::Entry::setDirection(Direction dir) { mDirection = dir; }
 void Description::Entry::setDirection(Direction dir) { mDirection = dir; }
 
 
-Description::Entry::operator string() const { return generateSdp("\r\n"); }
+Description::Entry::operator string() const { return generateSdp("\r\n", "IP4 0.0.0.0", "9"); }
 
 
-string Description::Entry::generateSdp(string_view eol) const {
+string Description::Entry::generateSdp(string_view eol, string_view addr, string_view port) const {
 	std::ostringstream sdp;
 	std::ostringstream sdp;
-	// Port 9 is the discard protocol
-	sdp << "m=" << type() << ' ' << 9 << ' ' << description() << eol;
-	sdp << "c=IN IP4 0.0.0.0" << eol;
+	sdp << "m=" << type() << ' ' << port << ' ' << description() << eol;
+	sdp << "c=IN " << addr << eol;
 	sdp << generateSdpLines(eol);
 	sdp << generateSdpLines(eol);
 
 
 	return sdp.str();
 	return sdp.str();

+ 12 - 46
src/icetransport.cpp

@@ -716,56 +716,22 @@ void IceTransport::LogCallback(const gchar * /*logDomain*/, GLogLevelFlags logLe
 	PLOG(severity) << "nice: " << message;
 	PLOG(severity) << "nice: " << message;
 }
 }
 
 
-bool IceTransport::getSelectedCandidatePair(CandidateInfo *localInfo, CandidateInfo *remoteInfo) {
-	NiceCandidate *local, *remote;
-	gboolean result = nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &local, &remote);
-
-	if (!result)
+bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) {
+	NiceCandidate *niceLocal, *niceRemote;
+	if(!nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &niceLocal, &niceRemote))
 		return false;
 		return false;
 
 
-	char ipaddr[INET6_ADDRSTRLEN];
-	nice_address_to_string(&local->addr, ipaddr);
-	localInfo->address = std::string(ipaddr);
-	localInfo->port = nice_address_get_port(&local->addr);
-	localInfo->type = IceTransport::NiceTypeToCandidateType(local->type);
-	localInfo->transportType =
-	    IceTransport::NiceTransportTypeToCandidateTransportType(local->transport);
-
-	nice_address_to_string(&remote->addr, ipaddr);
-	remoteInfo->address = std::string(ipaddr);
-	remoteInfo->port = nice_address_get_port(&remote->addr);
-	remoteInfo->type = IceTransport::NiceTypeToCandidateType(remote->type);
-	remoteInfo->transportType =
-	    IceTransport::NiceTransportTypeToCandidateTransportType(remote->transport);
+	gchar *sdpLocal = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceLocal);
+	if(local) *local = Candidate(sdpLocal);
+	g_free(sdpLocal);
 
 
-	return true;
-}
-
-CandidateType IceTransport::NiceTypeToCandidateType(NiceCandidateType type) {
-	switch (type) {
-	case NiceCandidateType::NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
-		return CandidateType::PeerReflexive;
-	case NiceCandidateType::NICE_CANDIDATE_TYPE_RELAYED:
-		return CandidateType::Relayed;
-	case NiceCandidateType::NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
-		return CandidateType::ServerReflexive;
-	default:
-		return CandidateType::Host;
-	}
-}
+	gchar *sdpRemote = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceRemote);
+	if(remote) *remote = Candidate(sdpRemote);
+	g_free(sdpRemote);
 
 
-CandidateTransportType
-IceTransport::NiceTransportTypeToCandidateTransportType(NiceCandidateTransport type) {
-	switch (type) {
-	case NiceCandidateTransport::NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
-		return CandidateTransportType::TcpActive;
-	case NiceCandidateTransport::NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
-		return CandidateTransportType::TcpPassive;
-	case NiceCandidateTransport::NICE_CANDIDATE_TRANSPORT_TCP_SO:
-		return CandidateTransportType::TcpSo;
-	default:
-		return CandidateTransportType::Udp;
-	}
+	local->resolve(Candidate::ResolveMode::Simple);
+	remote->resolve(Candidate::ResolveMode::Simple);
+	return true;
 }
 }
 
 
 } // namespace rtc
 } // namespace rtc

+ 1 - 4
src/icetransport.hpp

@@ -64,7 +64,7 @@ public:
 	bool send(message_ptr message) override; // false if dropped
 	bool send(message_ptr message) override; // false if dropped
 
 
 #if USE_NICE
 #if USE_NICE
-	bool getSelectedCandidatePair(CandidateInfo *local, CandidateInfo *remote);
+	bool getSelectedCandidatePair(Candidate *local, Candidate *remote);
 #endif
 #endif
 
 
 private:
 private:
@@ -113,9 +113,6 @@ private:
 	static gboolean TimeoutCallback(gpointer userData);
 	static gboolean TimeoutCallback(gpointer userData);
 	static void LogCallback(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message,
 	static void LogCallback(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message,
 	                        gpointer user_data);
 	                        gpointer user_data);
-	static CandidateType NiceTypeToCandidateType(NiceCandidateType type);
-	static CandidateTransportType
-	NiceTransportTypeToCandidateTransportType(NiceCandidateTransport type);
 #endif
 #endif
 };
 };
 
 

+ 3 - 2
src/peerconnection.cpp

@@ -835,6 +835,7 @@ void PeerConnection::processLocalCandidate(Candidate candidate) {
 	if (!mLocalDescription)
 	if (!mLocalDescription)
 		throw std::logic_error("Got a local candidate without local description");
 		throw std::logic_error("Got a local candidate without local description");
 
 
+	candidate.resolve(Candidate::ResolveMode::Simple); // for proper SDP generation later
 	mLocalDescription->addCandidate(candidate);
 	mLocalDescription->addCandidate(candidate);
 
 
 	mProcessor->enqueue([this, candidate = std::move(candidate)]() {
 	mProcessor->enqueue([this, candidate = std::move(candidate)]() {
@@ -899,8 +900,8 @@ void PeerConnection::resetCallbacks() {
 	mGatheringStateChangeCallback = nullptr;
 	mGatheringStateChangeCallback = nullptr;
 }
 }
 
 
-bool PeerConnection::getSelectedCandidatePair([[maybe_unused]] CandidateInfo *local,
-                                              [[maybe_unused]] CandidateInfo *remote) {
+bool PeerConnection::getSelectedCandidatePair([[maybe_unused]] Candidate *local,
+                                              [[maybe_unused]] Candidate *remote) {
 #if USE_NICE
 #if USE_NICE
 	auto iceTransport = std::atomic_load(&mIceTransport);
 	auto iceTransport = std::atomic_load(&mIceTransport);
 	return iceTransport->getSelectedCandidatePair(local, remote);
 	return iceTransport->getSelectedCandidatePair(local, remote);