upgrade safe version 3

This commit is contained in:
phamvannhat 2025-12-29 15:37:15 +07:00
parent 72c09ad308
commit cacb3dd569
3 changed files with 99 additions and 67 deletions

View File

@ -39,7 +39,7 @@ PeerServer::PeerServer(SignalingManager& sig,
sig_.sendSdp(sdp);
sdpDone_ = true;
// std::cout << "[Server] Sent ANSWER\n";
std::cout << "[Server] Sent ANSWER\n";
});
/* ===== LOCAL ICE ===== */

View File

@ -1,10 +1,13 @@
#include "WebRTCTransport.hpp"
#include <iostream>
#include <utility>
/* ================================
* Constructor
* ================================ */
WebRTCTransport::WebRTCTransport()
: dcOpen_(false),
haveRemoteOffer_(false),
answerCreated_(false),
localAnswerSent_(false)
{
rtc::Configuration cfg;
@ -12,71 +15,103 @@ WebRTCTransport::WebRTCTransport()
pc_ = std::make_shared<rtc::PeerConnection>(cfg);
/* ===== LOCAL ICE ===== */
pc_->onLocalCandidate([this](rtc::Candidate c){
/* =====================================================
* LOCAL SDP REGISTER ONCE (CRITICAL FIX)
* ===================================================== */
pc_->onLocalDescription([this](rtc::Description d) {
if (d.type() != rtc::Description::Type::Answer)
return;
if (localAnswerSent_) {
std::cout << "[Transport] Duplicate local ANSWER ignored\n";
return;
}
localAnswerSent_ = true;
std::string sdp = std::string(d);
if (onLocalSdpCb_) {
onLocalSdpCb_(sdp);
} else {
/* ultra-safe: cache if callback registered late */
cachedAnswer_ = sdp;
std::cout << "[Transport] ANSWER cached (no callback yet)\n";
}
});
/* =====================================================
* LOCAL ICE
* ===================================================== */
pc_->onLocalCandidate([this](rtc::Candidate c) {
if (onLocalIceCb_) {
onLocalIceCb_(c.candidate(), c.mid());
}
});
/* ===== DATA CHANNEL ===== */
pc_->onDataChannel([this](std::shared_ptr<rtc::DataChannel> dc){
/* =====================================================
* DATA CHANNEL
* ===================================================== */
pc_->onDataChannel([this](std::shared_ptr<rtc::DataChannel> dc) {
dc_ = dc;
dc_->onOpen([this]{
dc_->onOpen([this] {
dcOpen_ = true;
if (onDcOpenCb_) onDcOpenCb_();
if (onDcOpenCb_)
onDcOpenCb_();
});
dc_->onMessage([this](rtc::message_variant msg){
dc_->onClosed([this] {
dcOpen_ = false;
std::cout << "[Transport] DataChannel closed\n";
});
dc_->onMessage([this](rtc::message_variant msg) {
if (const auto* s = std::get_if<std::string>(&msg)) {
if (onDcMessageCb_) onDcMessageCb_(*s);
if (onDcMessageCb_)
onDcMessageCb_(*s);
}
});
});
}
/* ===== CALLBACK REG ===== */
/* ================================
* CALLBACK REGISTRATION
* ================================ */
void WebRTCTransport::onLocalSdp(
std::function<void(std::string)> cb)
{
onLocalSdpCb_ = cb;
onLocalSdpCb_ = std::move(cb);
pc_->onLocalDescription([this](rtc::Description d){
if (!onLocalSdpCb_) return;
if (d.type() != rtc::Description::Type::Answer)
return;
if (localAnswerSent_) {
std::cout << "[Transport] Ignore duplicate local ANSWER\n";
return;
}
localAnswerSent_ = true;
onLocalSdpCb_(std::string(d));
});
/* flush cached ANSWER if any */
if (cachedAnswer_) {
onLocalSdpCb_(*cachedAnswer_);
cachedAnswer_.reset();
}
}
void WebRTCTransport::onLocalIce(
std::function<void(std::string,std::string)> cb)
std::function<void(std::string, std::string)> cb)
{
onLocalIceCb_ = cb;
onLocalIceCb_ = std::move(cb);
}
void WebRTCTransport::onDcOpen(std::function<void()> cb)
void WebRTCTransport::onDcOpen(
std::function<void()> cb)
{
onDcOpenCb_ = cb;
onDcOpenCb_ = std::move(cb);
}
void WebRTCTransport::onDcMessage(
std::function<void(const std::string&)> cb)
{
onDcMessageCb_ = cb;
onDcMessageCb_ = std::move(cb);
}
/* ===== SDP ===== */
/* ================================
* SDP
* ================================ */
void WebRTCTransport::setRemoteOffer(const std::string& sdp)
{
@ -85,30 +120,25 @@ void WebRTCTransport::setRemoteOffer(const std::string& sdp)
return;
}
std::cout << "[Transport] Set remote OFFER\n";
pc_->setRemoteDescription(
rtc::Description(sdp,
rtc::Description::Type::Offer));
haveRemoteOffer_ = true;
/* ===== FLUSH ICE BUFFER ===== */
/* ===== Flush ICE buffer ===== */
if (!iceBuffer_.empty()) {
std::cout << "[Transport] Flush ICE buffer: "
<< iceBuffer_.size()
<< " candidate(s)\n";
for (auto& c : iceBuffer_) {
std::cout << "[Transport] + "
<< c.candidate()
<< "\n";
pc_->addRemoteCandidate(c);
}
iceBuffer_.clear();
} else {
std::cout << "[Transport] ICE buffer empty\n";
}
}
void WebRTCTransport::createAnswer()
@ -125,16 +155,18 @@ void WebRTCTransport::createAnswer()
pc_->setLocalDescription(rtc::Description::Type::Answer);
}
void WebRTCTransport::setRemoteAnswer(const std::string& sdp)
{
std::cout << "[Transport] Set remote ANSWER\n";
pc_->setRemoteDescription(
rtc::Description(sdp,
rtc::Description::Type::Answer));
}
/* ===== ICE ===== */
/* ================================
* ICE
* ================================ */
void WebRTCTransport::addRemoteIce(
const std::string& cand,
@ -149,7 +181,9 @@ void WebRTCTransport::addRemoteIce(
}
}
/* ===== DATA ===== */
/* ================================
* DATA
* ================================ */
void WebRTCTransport::sendMessage(const std::string& msg)
{

View File

@ -1,12 +1,13 @@
#pragma once
#include <rtc/rtc.hpp>
#include <string>
#include <functional>
#include <memory>
#include <vector>
#include <optional>
#include <string>
class WebRTCTransport
{
class WebRTCTransport {
public:
WebRTCTransport();
@ -15,37 +16,34 @@ public:
void onDcOpen(std::function<void()> cb);
void onDcMessage(std::function<void(const std::string&)> cb);
void createOffer();
void createAnswer();
void setRemoteOffer(const std::string& sdp);
void createAnswer();
void setRemoteAnswer(const std::string& sdp);
void addRemoteIce(const std::string& cand, const std::string& mid);
void addRemoteIce(const std::string& cand,
const std::string& mid);
void sendMessage(const std::string& msg);
private:
/* WebRTC core */
std::shared_ptr<rtc::PeerConnection> pc_;
std::shared_ptr<rtc::DataChannel> dc_;
// ===== state =====
bool dcOpen_ = false;
// SDP state
bool haveRemoteOffer_ = false; // set sau setRemoteOffer()
bool answerCreated_ = false; // set sau createAnswer()
bool localAnswerSent_ = false;
// ===== ICE buffer =====
std::vector<rtc::Candidate> iceBuffer_;
// ===== callbacks =====
/* Callbacks */
std::function<void(std::string)> onLocalSdpCb_;
std::function<void(std::string,std::string)> onLocalIceCb_;
std::function<void()> onDcOpenCb_;
std::function<void(const std::string&)> onDcMessageCb_;
/* State */
bool dcOpen_{false};
bool haveRemoteOffer_{false};
bool localAnswerSent_{false};
/* ICE buffer */
std::vector<rtc::Candidate> iceBuffer_;
/*FIX: cache SDP if callback registered late */
std::optional<std::string> cachedAnswer_;
};