8 peerId(id), network_manager(parent)
12 auto config = nm->getRTCConfig();
13 config.iceServers.push_back({
"stun:stun.l.google.com:19302"});
14 config.iceServers.push_back({
"stun:stun1.l.google.com:19302"});
15 config.iceServers.push_back({
"stun:stun.stunprotocol.org:3478"});
16 pc = std::make_shared<rtc::PeerConnection>(config);
21 throw std::runtime_error(
"NetworkManager expired");
55 rtc::DataChannelInit init;
56 rtc::DataChannelInit markerMoveInit;
57 auto reliability = rtc::Reliability{};
58 reliability.unordered =
true;
59 reliability.maxPacketLifeTime = std::chrono::milliseconds(500);
61 markerMoveInit.reliability = reliability;
83 auto offer =
pc->createOffer();
84 rtc::LocalDescriptionInit init;
85 init.icePwd = offer.icePwd();
86 init.iceUfrag = offer.iceUfrag();
87 pc->setLocalDescription(offer.type(), init);
93 auto answer =
pc->createAnswer();
94 rtc::LocalDescriptionInit init;
95 init.icePwd = answer.icePwd();
96 init.iceUfrag = answer.iceUfrag();
97 pc->setLocalDescription(answer.type(), init);
103 pc->setRemoteDescription(desc);
105 std::lock_guard<std::mutex> lk(
candMx_);
109 pc->addRemoteCandidate(c);
117 std::lock_guard<std::mutex> lk(
candMx_);
124 pc->addRemoteCandidate(candidate);
130 pc->onStateChange([
this](rtc::PeerConnection::State s)
134 std::cout <<
"[PeerLink] State(" <<
peerId <<
"): " << (int)s <<
"at " <<
lastStateAt_ <<
"\n";
136 if (s == rtc::PeerConnection::State::Closed || s == rtc::PeerConnection::State::Failed) {
139 nm->events_.push(std::move(ev));
142 if (s == rtc::PeerConnection::State::Connected) {
145 nm->events_.push(std::move(ev));
151 if (
auto nm = wk.lock()) nm->onPeerLocalDescription(
id, desc); });
155 if (
auto nm = wk.lock()) nm->onPeerLocalCandidate(
id, cand); });
157 pc->onDataChannel([
this](std::shared_ptr<rtc::DataChannel> ch)
159 const std::string label = ch->label();
162 std::cout <<
"[PeerLink] Received DC \"" << label <<
"\" from " <<
peerId <<
"\n"; });
173 auto it =
dcs_.find(label);
174 if (it ==
dcs_.end() || !it->second)
176 auto& ch = it->second;
183 ch->send(std::string(text));
189 auto it =
dcs_.find(label);
190 if (it ==
dcs_.end() || !it->second)
192 auto& ch = it->second;
203 b.resize(bytes.size());
206 std::memcpy(b.data(), bytes.data(), bytes.size());
239 return it !=
dcOpen_.end() && it->second;
247 dc->onOpen([
this,
id =
peerId, label]()
249 std::cout <<
"[PeerLink] DC open \"" << label <<
"\" to " <<
id <<
"\n";
252 msg::NetEvent ev{msg::NetEvent::Type::DcOpen, id, label};
253 nm->events_.push(std::move(ev));
257 dc->onClosed([
this,
id = peerId, label]()
259 std::cout <<
"[PeerLink] DC closed \"" << label <<
"\" to " <<
id <<
"\n";
260 dcOpen_[label] =
false;
261 bootstrapSent_ =
false;
262 if (
auto nm = network_manager.lock()) {
264 nm->events_.push(std::move(ev));
267 dc->onMessage([
this,
id = peerId, label](rtc::message_variant m)
270 if (
auto nm = network_manager.lock())
272 if (std::holds_alternative<std::string>(m))
274 const auto& s = std::get<std::string>(m);
275 std::vector<uint8_t> bytes(s.begin(), s.end());
276 nm->inboundRaw_.push(
msg::InboundRaw{peerId, label, std::move(bytes)});
280 const auto& bin = std::get<rtc::binary>(m);
281 std::vector<uint8_t> bytes(bin.size());
282 std::memcpy(bytes.data(), bin.data(), bin.size());
283 nm->inboundRaw_.push(
msg::InboundRaw{peerId, label, std::move(bytes)});
297 for (
auto& [label, ch] :
dcs_)
299 if (ch && ch->isOpen())
307 return pc &&
pc->state() == rtc::PeerConnection::State::Connected;
344 static std::atomic<uint64_t> guardSeq{0};
345 const uint64_t seq = ++guardSeq;
357 for (
auto& [label, ch] :
dcs_)
362 ch->onMessage(
nullptr);
363 ch->onBufferedAmountLow(
nullptr);
364 ch->onClosed(
nullptr);
365 ch->onError(
nullptr);
369 pc->onStateChange(
nullptr);
370 pc->onGatheringStateChange(
nullptr);
371 pc->onLocalDescription(
nullptr);
372 pc->onDataChannel(
nullptr);
373 pc->onTrack(
nullptr);
381 std::unordered_map<std::string, std::shared_ptr<rtc::DataChannel>> movedDcs;
384 for (
auto& kv : movedDcs)
398 return rtc::PeerConnection::State::Closed;
406 auto s =
pc->state();
407 return s == rtc::PeerConnection::State::Closed ||
408 s == rtc::PeerConnection::State::Failed;
414 using S = rtc::PeerConnection::State;
423 case S::Disconnected:
424 return "Disconnected";
static Logger & instance()
static void safeCloseDataChannel(std::shared_ptr< rtc::DataChannel > &dc)
static void safeClosePeerConnection(std::shared_ptr< rtc::PeerConnection > &pc)
std::atomic< bool > remoteDescSet_
bool isDataChannelOpen() const
std::atomic< rtc::PeerConnection::State > lastState_
bool allRequiredOpen() const
const char * pcStateString() const
bool isPcConnectedOnly() const
const std::string & displayName() const
void sendChatJson(const std::string &jsonText)
std::shared_ptr< rtc::PeerConnection > pc
rtc::PeerConnection::State pcState() const
rtc::Description createOffer()
std::vector< rtc::Candidate > pendingRemoteCandidates_
void addIceCandidate(const rtc::Candidate &candidate)
std::unordered_map< std::string, bool > dcOpen_
std::weak_ptr< NetworkManager > network_manager
bool isClosedOrFailed() const
bool sendOn(const std::string &label, const std::vector< uint8_t > &bytes)
void setDisplayName(std::string n)
bool sendGame(const std::vector< uint8_t > &bytes)
bool sendNote(const std::vector< uint8_t > &bytes)
bool sendMarkerMove(const std::vector< uint8_t > &bytes)
void setRemoteDescription(const rtc::Description &desc)
rtc::Description createAnswer()
std::atomic< double > lastStateAt_
std::unordered_map< std::string, std::shared_ptr< rtc::DataChannel > > dcs_
std::atomic< bool > closing_
bool sendChat(const std::vector< uint8_t > &bytes)
void attachChannelHandlers(const std::shared_ptr< rtc::DataChannel > &ch, const std::string &label)
constexpr std::string Chat
constexpr std::string Game
constexpr std::string Notes
constexpr std::string MarkerMove