mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-22 23:25:33 +00:00
Changed interface to pass objects rather than strings
This commit is contained in:
@ -38,20 +38,20 @@ inline bool hasprefix(const string &str, const string &prefix) {
|
||||
|
||||
namespace rtc {
|
||||
|
||||
Candidate::Candidate(string candidate, string mid) {
|
||||
Candidate::Candidate(string candidate, std::optional<string> mid) {
|
||||
const string prefix{"candidate:"};
|
||||
mCandidate =
|
||||
hasprefix(candidate, prefix) ? candidate.substr(prefix.size()) : std::move(candidate);
|
||||
mMid = std::move(mid);
|
||||
|
||||
// See RFC 5245
|
||||
// See RFC 5245 for format
|
||||
std::stringstream ss(mCandidate);
|
||||
int component{0}, priority{0};
|
||||
string foundation, transport, node, service, typ_, type;
|
||||
if (ss >> foundation >> component >> transport >> priority &&
|
||||
ss >> node >> service >> typ_ >> type && typ_ == "typ") {
|
||||
|
||||
// Try to resolv the node
|
||||
// Try to resolve the node
|
||||
struct addrinfo hints = {};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
@ -88,9 +88,13 @@ Candidate::Candidate(string candidate, string mid) {
|
||||
|
||||
string Candidate::candidate() const { return mCandidate; }
|
||||
|
||||
string Candidate::mid() const { return mMid; }
|
||||
std::optional<string> Candidate::mid() const { return mMid; }
|
||||
|
||||
Candidate::operator string() const { return mCandidate; }
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate) {
|
||||
return out << std::string(candidate);
|
||||
}
|
||||
|
||||
|
@ -27,19 +27,21 @@ namespace rtc {
|
||||
|
||||
class Candidate {
|
||||
public:
|
||||
Candidate(string candidate, string mid);
|
||||
Candidate(string candidate, std::optional<string> mid = nullopt);
|
||||
|
||||
string candidate() const;
|
||||
string mid() const;
|
||||
std::optional<string> mid() const;
|
||||
|
||||
operator string() const;
|
||||
|
||||
private:
|
||||
string mCandidate;
|
||||
string mMid;
|
||||
std::optional<string> mMid;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const rtc::Candidate &candidate);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -44,7 +44,7 @@ inline void trim_end(string &str) {
|
||||
|
||||
namespace rtc {
|
||||
|
||||
Description::Description(Role role, const string &sdp)
|
||||
Description::Description(const string &sdp, Role role)
|
||||
: mRole(role), mMid("0"), mIceUfrag("0"), mIcePwd("0") {
|
||||
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
std::default_random_engine generator(seed);
|
||||
@ -138,3 +138,8 @@ Description::operator string() const {
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const rtc::Description &description) {
|
||||
return out << std::string(description);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "candidate.hpp"
|
||||
#include "include.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
@ -32,7 +33,7 @@ class Description {
|
||||
public:
|
||||
enum class Role { Passive, Active, ActPass };
|
||||
|
||||
Description(Role role, const string &sdp);
|
||||
Description(const string &sdp, Role role = Role::ActPass);
|
||||
|
||||
Role role() const;
|
||||
std::optional<string> fingerprint() const;
|
||||
@ -45,7 +46,7 @@ public:
|
||||
operator string() const;
|
||||
|
||||
private:
|
||||
Role mRole = Role::Passive;
|
||||
Role mRole;
|
||||
string mSessionId;
|
||||
string mMid;
|
||||
string mIceUfrag, mIcePwd;
|
||||
@ -57,4 +58,6 @@ private:
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const rtc::Description &description);
|
||||
|
||||
#endif
|
||||
|
@ -33,10 +33,11 @@ namespace rtc {
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
|
||||
IceTransport::IceTransport(const IceConfiguration &config, Description::Role role,
|
||||
candidate_callback candidateCallback, ready_callback ready)
|
||||
: mRole(role), mNiceAgent(nullptr, nullptr), mMainLoop(nullptr, nullptr),
|
||||
mCandidateCallback(std::move(candidateCallback)), mReadyCallback(ready) {
|
||||
IceTransport::IceTransport(const IceConfiguration &config, candidate_callback candidateCallback,
|
||||
ready_callback ready)
|
||||
: mRole(Description::Role::ActPass), mState(State::Disconnected), mNiceAgent(nullptr, nullptr),
|
||||
mMainLoop(nullptr, nullptr), mCandidateCallback(std::move(candidateCallback)),
|
||||
mReadyCallback(ready) {
|
||||
|
||||
auto logLevelFlags = GLogLevelFlags(G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION);
|
||||
g_log_set_handler(nullptr, logLevelFlags, LogCallback, this);
|
||||
@ -132,10 +133,13 @@ IceTransport::State IceTransport::state() const { return mState; }
|
||||
Description IceTransport::getLocalDescription() const {
|
||||
std::unique_ptr<gchar[], void (*)(void *)> sdp(nice_agent_generate_local_sdp(mNiceAgent.get()),
|
||||
g_free);
|
||||
return Description(mRole, string(sdp.get()));
|
||||
return Description(string(sdp.get()), mRole);
|
||||
}
|
||||
|
||||
void IceTransport::setRemoteDescription(const Description &description) {
|
||||
mRole = description.role() == Description::Role::Active ? Description::Role::Passive
|
||||
: Description::Role::Active;
|
||||
|
||||
if (nice_agent_parse_remote_sdp(mNiceAgent.get(), string(description).c_str()))
|
||||
throw std::runtime_error("Unable to parse remote SDP");
|
||||
}
|
||||
@ -185,7 +189,7 @@ void IceTransport::processGatheringDone() { mCandidateCallback(nullopt); }
|
||||
|
||||
void IceTransport::changeState(uint32_t state) {
|
||||
mState = static_cast<State>(state);
|
||||
if (mState == State::READY) {
|
||||
if (mState == State::Ready) {
|
||||
mReadyCallback();
|
||||
}
|
||||
}
|
||||
|
@ -39,19 +39,19 @@ namespace rtc {
|
||||
class IceTransport : public Transport {
|
||||
public:
|
||||
enum class State : uint32_t {
|
||||
DISCONNECTED = NICE_COMPONENT_STATE_DISCONNECTED,
|
||||
GATHERING = NICE_COMPONENT_STATE_GATHERING,
|
||||
CONNECTING = NICE_COMPONENT_STATE_CONNECTING,
|
||||
CONNECTED = NICE_COMPONENT_STATE_CONNECTED,
|
||||
READY = NICE_COMPONENT_STATE_READY,
|
||||
FAILED = NICE_COMPONENT_STATE_FAILED
|
||||
Disconnected = NICE_COMPONENT_STATE_DISCONNECTED,
|
||||
Gathering = NICE_COMPONENT_STATE_GATHERING,
|
||||
Connecting = NICE_COMPONENT_STATE_CONNECTING,
|
||||
Connected = NICE_COMPONENT_STATE_CONNECTED,
|
||||
Ready = NICE_COMPONENT_STATE_READY,
|
||||
Failed = NICE_COMPONENT_STATE_FAILED
|
||||
};
|
||||
|
||||
using candidate_callback = std::function<void(const std::optional<Candidate> &candidate)>;
|
||||
using ready_callback = std::function<void(void)>;
|
||||
|
||||
IceTransport(const IceConfiguration &config, Description::Role role,
|
||||
candidate_callback candidateCallback, ready_callback ready);
|
||||
IceTransport(const IceConfiguration &config, candidate_callback candidateCallback,
|
||||
ready_callback ready);
|
||||
~IceTransport();
|
||||
|
||||
Description::Role role() const;
|
||||
@ -74,8 +74,8 @@ private:
|
||||
void processCandidate(const string &candidate);
|
||||
void processGatheringDone();
|
||||
|
||||
const Description::Role mRole;
|
||||
State mState = State::DISCONNECTED;
|
||||
Description::Role mRole;
|
||||
State mState;
|
||||
|
||||
uint32_t mStreamId = 0;
|
||||
std::unique_ptr<NiceAgent, void (*)(gpointer)> mNiceAgent;
|
||||
|
@ -39,6 +39,8 @@ using std::uint8_t;
|
||||
|
||||
const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length
|
||||
const size_t MAX_NUMERICSERV_LEN = 6; // Max port string representation length
|
||||
|
||||
const uint16_t DEFAULT_SCTP_PORT = 5000; // SCTP port to use by default
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -29,8 +29,7 @@ using std::function;
|
||||
using std::shared_ptr;
|
||||
|
||||
PeerConnection::PeerConnection(const IceConfiguration &config)
|
||||
: mConfig(config), mCertificate(make_certificate("libdatachannel")), mMid("0"),
|
||||
mSctpPort(5000) {}
|
||||
: mConfig(config), mCertificate(make_certificate("libdatachannel")) {}
|
||||
|
||||
PeerConnection::~PeerConnection() {}
|
||||
|
||||
@ -38,31 +37,29 @@ const IceConfiguration *PeerConnection::config() const { return &mConfig; }
|
||||
|
||||
const Certificate *PeerConnection::certificate() const { return &mCertificate; }
|
||||
|
||||
void PeerConnection::setRemoteDescription(const string &description) {
|
||||
Description desc(Description::Role::ActPass, description);
|
||||
std::optional<Description> PeerConnection::localDescription() const { return mLocalDescription; }
|
||||
|
||||
if (auto fingerprint = desc.fingerprint())
|
||||
mRemoteFingerprint.emplace(*fingerprint);
|
||||
|
||||
if (auto sctpPort = desc.sctpPort()) {
|
||||
mSctpPort = *sctpPort;
|
||||
}
|
||||
std::optional<Description> PeerConnection::remoteDescription() const { return mRemoteDescription; }
|
||||
|
||||
void PeerConnection::setRemoteDescription(Description description) {
|
||||
if (!mIceTransport) {
|
||||
initIceTransport(Description::Role::ActPass);
|
||||
mIceTransport->setRemoteDescription(desc);
|
||||
triggerLocalDescription();
|
||||
initIceTransport();
|
||||
mIceTransport->setRemoteDescription(description);
|
||||
processLocalDescription(mIceTransport->getLocalDescription());
|
||||
mIceTransport->gatherLocalCandidates();
|
||||
} else {
|
||||
mIceTransport->setRemoteDescription(desc);
|
||||
mIceTransport->setRemoteDescription(description);
|
||||
}
|
||||
|
||||
mRemoteDescription.emplace(std::move(description));
|
||||
}
|
||||
|
||||
void PeerConnection::setRemoteCandidate(const string &candidate) {
|
||||
Candidate cand(candidate, mMid);
|
||||
if (mIceTransport) {
|
||||
mIceTransport->addRemoteCandidate(cand);
|
||||
}
|
||||
void PeerConnection::setRemoteCandidate(Candidate candidate) {
|
||||
if (!mRemoteDescription || !mIceTransport)
|
||||
throw std::logic_error("Remote candidate set without remote description");
|
||||
|
||||
mIceTransport->addRemoteCandidate(candidate);
|
||||
mRemoteDescription->addCandidate(std::move(candidate));
|
||||
}
|
||||
|
||||
shared_ptr<DataChannel> PeerConnection::createDataChannel(const string &label,
|
||||
@ -83,8 +80,8 @@ shared_ptr<DataChannel> PeerConnection::createDataChannel(const string &label,
|
||||
mDataChannels.insert(std::make_pair(stream, channel));
|
||||
|
||||
if (!mIceTransport) {
|
||||
initIceTransport(Description::Role::Active);
|
||||
triggerLocalDescription();
|
||||
initIceTransport();
|
||||
processLocalDescription(mIceTransport->getLocalDescription());
|
||||
mIceTransport->gatherLocalCandidates();
|
||||
} else if (mSctpTransport && mSctpTransport->isReady()) {
|
||||
channel->open(mSctpTransport);
|
||||
@ -97,18 +94,19 @@ void PeerConnection::onDataChannel(
|
||||
mDataChannelCallback = callback;
|
||||
}
|
||||
|
||||
void PeerConnection::onLocalDescription(std::function<void(const string &description)> callback) {
|
||||
void PeerConnection::onLocalDescription(
|
||||
std::function<void(const Description &description)> callback) {
|
||||
mLocalDescriptionCallback = callback;
|
||||
}
|
||||
|
||||
void PeerConnection::onLocalCandidate(
|
||||
std::function<void(const std::optional<string> &candidate)> callback) {
|
||||
std::function<void(const std::optional<Candidate> &candidate)> callback) {
|
||||
mLocalCandidateCallback = callback;
|
||||
}
|
||||
|
||||
void PeerConnection::initIceTransport(Description::Role role) {
|
||||
void PeerConnection::initIceTransport() {
|
||||
mIceTransport = std::make_shared<IceTransport>(
|
||||
mConfig, role, std::bind(&PeerConnection::triggerLocalCandidate, this, _1),
|
||||
mConfig, std::bind(&PeerConnection::processLocalCandidate, this, _1),
|
||||
std::bind(&PeerConnection::initDtlsTransport, this));
|
||||
}
|
||||
|
||||
@ -119,13 +117,18 @@ void PeerConnection::initDtlsTransport() {
|
||||
}
|
||||
|
||||
void PeerConnection::initSctpTransport() {
|
||||
uint16_t sctpPort = mRemoteDescription->sctpPort().value_or(DEFAULT_SCTP_PORT);
|
||||
mSctpTransport = std::make_shared<SctpTransport>(
|
||||
mDtlsTransport, mSctpPort, std::bind(&PeerConnection::openDataChannels, this),
|
||||
mDtlsTransport, sctpPort, std::bind(&PeerConnection::openDataChannels, this),
|
||||
std::bind(&PeerConnection::forwardMessage, this, _1));
|
||||
}
|
||||
|
||||
bool PeerConnection::checkFingerprint(const std::string &fingerprint) const {
|
||||
return mRemoteFingerprint && *mRemoteFingerprint == fingerprint;
|
||||
if (auto expectedFingerprint =
|
||||
mRemoteDescription ? mRemoteDescription->fingerprint() : nullopt) {
|
||||
return *expectedFingerprint == fingerprint;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PeerConnection::forwardMessage(message_ptr message) {
|
||||
@ -158,19 +161,26 @@ void PeerConnection::openDataChannels(void) {
|
||||
dataChannel->open(mSctpTransport);
|
||||
}
|
||||
|
||||
void PeerConnection::triggerLocalDescription() {
|
||||
if (mLocalDescriptionCallback && mIceTransport) {
|
||||
Description desc{mIceTransport->getLocalDescription()};
|
||||
desc.setFingerprint(mCertificate.fingerprint());
|
||||
desc.setSctpPort(mSctpPort);
|
||||
mLocalDescriptionCallback(string(desc));
|
||||
}
|
||||
void PeerConnection::processLocalDescription(Description description) {
|
||||
auto remoteSctpPort = mRemoteDescription ? mRemoteDescription->sctpPort() : nullopt;
|
||||
|
||||
description.setFingerprint(mCertificate.fingerprint());
|
||||
description.setSctpPort(remoteSctpPort.value_or(DEFAULT_SCTP_PORT));
|
||||
mLocalDescription.emplace(std::move(description));
|
||||
|
||||
if (mLocalDescriptionCallback)
|
||||
mLocalDescriptionCallback(*mLocalDescription);
|
||||
}
|
||||
|
||||
void PeerConnection::triggerLocalCandidate(const std::optional<Candidate> &candidate) {
|
||||
if (mLocalCandidateCallback) {
|
||||
mLocalCandidateCallback(candidate ? std::make_optional(string(*candidate)) : nullopt);
|
||||
}
|
||||
void PeerConnection::processLocalCandidate(std::optional<Candidate> candidate) {
|
||||
if (!mLocalDescription)
|
||||
throw std::logic_error("Got a local candidate without local description");
|
||||
|
||||
if (candidate)
|
||||
mLocalDescription->addCandidate(*candidate);
|
||||
|
||||
if (mLocalCandidateCallback)
|
||||
mLocalCandidateCallback(candidate);
|
||||
}
|
||||
|
||||
void PeerConnection::triggerDataChannel(std::shared_ptr<DataChannel> dataChannel) {
|
||||
|
@ -48,18 +48,21 @@ public:
|
||||
const IceConfiguration *config() const;
|
||||
const Certificate *certificate() const;
|
||||
|
||||
void setRemoteDescription(const string &description);
|
||||
void setRemoteCandidate(const string &candidate);
|
||||
std::optional<Description> localDescription() const;
|
||||
std::optional<Description> remoteDescription() const;
|
||||
|
||||
void setRemoteDescription(Description description);
|
||||
void setRemoteCandidate(Candidate candidate);
|
||||
|
||||
std::shared_ptr<DataChannel> createDataChannel(const string &label, const string &protocol = "",
|
||||
const Reliability &reliability = {});
|
||||
|
||||
void onDataChannel(std::function<void(std::shared_ptr<DataChannel> dataChannel)> callback);
|
||||
void onLocalDescription(std::function<void(const string &description)> callback);
|
||||
void onLocalCandidate(std::function<void(const std::optional<string> &candidate)> callback);
|
||||
void onLocalDescription(std::function<void(const Description &description)> callback);
|
||||
void onLocalCandidate(std::function<void(const std::optional<Candidate> &candidate)> callback);
|
||||
|
||||
private:
|
||||
void initIceTransport(Description::Role role);
|
||||
void initIceTransport();
|
||||
void initDtlsTransport();
|
||||
void initSctpTransport();
|
||||
|
||||
@ -67,15 +70,15 @@ private:
|
||||
void forwardMessage(message_ptr message);
|
||||
void openDataChannels(void);
|
||||
|
||||
void triggerLocalDescription();
|
||||
void triggerLocalCandidate(const std::optional<Candidate> &candidate);
|
||||
void processLocalDescription(Description description);
|
||||
void processLocalCandidate(std::optional<Candidate> candidate);
|
||||
void triggerDataChannel(std::shared_ptr<DataChannel> dataChannel);
|
||||
|
||||
const IceConfiguration mConfig;
|
||||
Certificate mCertificate;
|
||||
string mMid;
|
||||
std::optional<string> mRemoteFingerprint;
|
||||
uint16_t mSctpPort;
|
||||
const Certificate mCertificate;
|
||||
|
||||
std::optional<Description> mLocalDescription;
|
||||
std::optional<Description> mRemoteDescription;
|
||||
|
||||
std::shared_ptr<IceTransport> mIceTransport;
|
||||
std::shared_ptr<DtlsTransport> mDtlsTransport;
|
||||
@ -84,8 +87,8 @@ private:
|
||||
std::unordered_map<unsigned int, std::shared_ptr<DataChannel>> mDataChannels;
|
||||
|
||||
std::function<void(std::shared_ptr<DataChannel> dataChannel)> mDataChannelCallback;
|
||||
std::function<void(const string &description)> mLocalDescriptionCallback;
|
||||
std::function<void(const std::optional<string> &candidate)> mLocalCandidateCallback;
|
||||
std::function<void(const Description &description)> mLocalDescriptionCallback;
|
||||
std::function<void(const std::optional<Candidate> &candidate)> mLocalCandidateCallback;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
@ -32,24 +32,24 @@ int main(int argc, char **argv) {
|
||||
auto pc1 = std::make_shared<PeerConnection>(config);
|
||||
auto pc2 = std::make_shared<PeerConnection>(config);
|
||||
|
||||
pc1->onLocalDescription([pc2](const string &sdp) {
|
||||
pc1->onLocalDescription([pc2](const Description &sdp) {
|
||||
cout << "Description 1: " << sdp << endl;
|
||||
pc2->setRemoteDescription(sdp);
|
||||
});
|
||||
|
||||
pc1->onLocalCandidate([pc2](const optional<string> &candidate) {
|
||||
pc1->onLocalCandidate([pc2](const optional<Candidate> &candidate) {
|
||||
if (candidate) {
|
||||
cout << "Candidate 1: " << *candidate << endl;
|
||||
pc2->setRemoteCandidate(*candidate);
|
||||
}
|
||||
});
|
||||
|
||||
pc2->onLocalDescription([pc1](const string &sdp) {
|
||||
pc2->onLocalDescription([pc1](const Description &sdp) {
|
||||
cout << "Description 2: " << sdp << endl;
|
||||
pc1->setRemoteDescription(sdp);
|
||||
});
|
||||
|
||||
pc2->onLocalCandidate([pc1](const optional<string> &candidate) {
|
||||
pc2->onLocalCandidate([pc1](const optional<Candidate> &candidate) {
|
||||
if (candidate) {
|
||||
cout << "Candidate 2: " << *candidate << endl;
|
||||
pc1->setRemoteCandidate(*candidate);
|
||||
|
Reference in New Issue
Block a user