Changed interface to pass objects rather than strings

This commit is contained in:
Paul-Louis Ageneau
2019-09-01 13:51:07 +02:00
parent 247c48b8a6
commit 47b918d4a1
10 changed files with 114 additions and 81 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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);