Support multiple ice connections

This commit is contained in:
dijunkun
2023-08-17 17:31:08 +08:00
parent a9db3d290b
commit 3a55dd0938
16 changed files with 335 additions and 232 deletions

33
src/common/common.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#include <iostream>
constexpr size_t HASH_STRING_PIECE(const char *string_piece) {
std::size_t result = 0;
while (*string_piece) {
result = (result * 131) + *string_piece++;
}
return result;
}
constexpr size_t operator"" _H(const char *string_piece, size_t) {
return HASH_STRING_PIECE(string_piece);
}
inline const std::string GetIceUsername(const std::string &sdp) {
std::string result = "";
std::string start = "ice-ufrag:";
std::string end = "\r\n";
size_t startPos = sdp.find(start);
size_t endPos = sdp.find(end);
if (startPos != std::string::npos && endPos != std::string::npos) {
result = sdp.substr(startPos + start.length(),
endPos - startPos - start.length());
}
return result;
}
#endif

View File

@@ -4,31 +4,21 @@
#include <nlohmann/json.hpp>
#include <thread>
#include "common.h"
#include "log.h"
using nlohmann::json;
constexpr size_t HASH_STRING_PIECE(const char *string_piece) {
std::size_t result = 0;
while (*string_piece) {
result = (result * 131) + *string_piece++;
}
return result;
}
constexpr size_t operator"" _H(const char *string_piece, size_t) {
return HASH_STRING_PIECE(string_piece);
}
const std::vector<std::string> ice_status = {
"JUICE_STATE_DISCONNECTED", "JUICE_STATE_GATHERING",
"JUICE_STATE_CONNECTING", "JUICE_STATE_CONNECTED",
"JUICE_STATE_COMPLETED", "JUICE_STATE_FAILED"};
IceTransmission::IceTransmission(
WsTransmission *ice_ws_transmission,
bool offer_peer, WsTransmission *ice_ws_transmission,
std::function<void(const char *, size_t)> on_receive_ice_msg)
: ice_ws_transport_(ice_ws_transmission),
: offer_peer_(offer_peer),
ice_ws_transport_(ice_ws_transmission),
on_receive_ice_msg_cb_(on_receive_ice_msg) {}
IceTransmission::~IceTransmission() {}
@@ -50,43 +40,15 @@ int IceTransmission::InitIceTransmission(std::string &ip, int port) {
LOG_INFO("gather_done");
// non-trickle
if (user_ptr) {
static_cast<IceTransmission *>(user_ptr)->GetLocalSdp();
static_cast<IceTransmission *>(user_ptr)->SendOffer();
}
},
[](juice_agent_t *agent, const char *data, size_t size, void *user_ptr) {
if (user_ptr &&
static_cast<IceTransmission *>(user_ptr)->on_receive_ice_msg_cb_) {
static_cast<IceTransmission *>(user_ptr)->on_receive_ice_msg_cb_(
data, size);
}
},
this);
return 0;
}
int IceTransmission::InitIceTransmission(std::string &ip, int port,
std::string const &id) {
transmission_id_ = id;
ice_agent_ = new IceAgent(ip, port);
ice_agent_->CreateIceAgent(
[](juice_agent_t *agent, juice_state_t state, void *user_ptr) {
LOG_INFO("state_change: {}", ice_status[state]);
},
[](juice_agent_t *agent, const char *sdp, void *user_ptr) {
LOG_INFO("candadite: {}", sdp);
// trickle
// static_cast<PeerConnection
// *>(user_ptr)->SendAnswerLocalCandidate(sdp);
},
[](juice_agent_t *agent, void *user_ptr) {
LOG_INFO("gather_done");
// non-trickle
if (user_ptr) {
static_cast<IceTransmission *>(user_ptr)->CreateAnswer();
static_cast<IceTransmission *>(user_ptr)->SendAnswer();
IceTransmission *ice_transmission_obj =
static_cast<IceTransmission *>(user_ptr);
if (ice_transmission_obj->offer_peer_) {
ice_transmission_obj->GetLocalSdp();
ice_transmission_obj->SendOffer();
} else {
ice_transmission_obj->CreateAnswer();
ice_transmission_obj->SendAnswer();
}
}
},
[](juice_agent_t *agent, const char *data, size_t size, void *user_ptr) {
@@ -109,7 +71,8 @@ int IceTransmission::DestroyIceTransmission() {
int IceTransmission::CreateTransmission(const std::string &transmission_id) {
LOG_INFO("Create transport");
offer_peer_ = true;
offer_peer_ = false;
transmission_id_ = transmission_id;
// if (SignalStatus::Connected != signal_status_) {
// LOG_ERROR("Not connect to signalserver");
@@ -129,7 +92,7 @@ int IceTransmission::CreateTransmission(const std::string &transmission_id) {
int IceTransmission::JoinTransmission(const std::string &transmission_id) {
LOG_INFO("Join transport");
offer_peer_ = false;
offer_peer_ = true;
transmission_id_ = transmission_id;
// if (SignalStatus::Connected != signal_status_) {
@@ -154,6 +117,7 @@ int IceTransmission::GetLocalSdp() {
int IceTransmission::SetRemoteSdp(const std::string &remote_sdp) {
ice_agent_->SetRemoteSdp(remote_sdp.c_str());
remote_ice_username_ = GetIceUsername(remote_sdp);
return 0;
}
@@ -199,7 +163,8 @@ int IceTransmission::CreateAnswer() {
int IceTransmission::SendAnswer() {
json message = {{"type", "answer"},
{"transmission_id", transmission_id_},
{"sdp", local_sdp_}};
{"sdp", local_sdp_},
{"guest", remote_ice_username_}};
LOG_INFO("Send answer:\n{}", message.dump().c_str());
if (ice_ws_transport_) {
@@ -247,6 +212,16 @@ void IceTransmission::OnReceiveMessage(const std::string &msg) {
switch (HASH_STRING_PIECE(type.c_str())) {
case "offer"_H: {
remote_sdp_ = j["sdp"].get<std::string>();
if (remote_sdp_.empty()) {
LOG_INFO("Invalid remote sdp");
} else {
LOG_INFO("Receive remote sdp [{}]", remote_sdp_);
SetRemoteSdp(remote_sdp_);
GatherCandidates();
}
break;
}
case "transmission_id"_H: {

View File

@@ -8,13 +8,12 @@
class IceTransmission {
public:
IceTransmission(WsTransmission *ice_ws_transmission,
IceTransmission(bool offer_peer, WsTransmission *ice_ws_transmission,
std::function<void(const char *, size_t)> on_receive_ice_msg);
~IceTransmission();
int InitIceTransmission(std::string &ip, int port);
int InitIceTransmission(std::string &ip, int port, std::string const &id);
int DestroyIceTransmission();
@@ -27,7 +26,7 @@ class IceTransmission {
void OnReceiveMessage(const std::string &msg);
private:
public:
int GatherCandidates();
int GetLocalSdp();
@@ -56,6 +55,7 @@ class IceTransmission {
std::function<void(const char *, size_t)> on_receive_ice_msg_cb_ = nullptr;
std::string local_sdp_;
std::string remote_sdp_;
std::string remote_ice_username_;
std::string local_candidates_;
std::string remote_candidates_;
unsigned int connection_id_ = 0;

View File

@@ -3,6 +3,7 @@
#include <regex>
#include "INIReader.h"
#include "common.h"
#include "log.h"
#include "nlohmann/json.hpp"
@@ -19,40 +20,69 @@ PeerConnection::PeerConnection() {}
PeerConnection::~PeerConnection() {}
int PeerConnection::Create(PeerConnectionParams params, const std::string &id) {
int PeerConnection::Create(PeerConnectionParams params,
const std::string &transmission_id) {
INIReader reader(params.cfg_path);
std::string cfg_signal_server_ip = reader.Get("signal server", "ip", "-1");
std::string cfg_signal_server_port =
reader.Get("signal server", "port", "-1");
std::string cfg_stun_server_ip = reader.Get("stun server", "ip", "-1");
std::string cfg_stun_server_port = reader.Get("stun server", "port", "-1");
cfg_signal_server_ip_ = reader.Get("signal server", "ip", "-1");
cfg_signal_server_port_ = reader.Get("signal server", "port", "-1");
cfg_stun_server_ip_ = reader.Get("stun server", "ip", "-1");
cfg_stun_server_port_ = reader.Get("stun server", "port", "-1");
std::regex regex("\n");
LOG_INFO("Read config success");
int signal_server_port = stoi(cfg_signal_server_port);
int stun_server_port = stoi(cfg_stun_server_port);
signal_server_port_ = stoi(cfg_signal_server_port_);
stun_server_port_ = stoi(cfg_stun_server_port_);
on_receive_ws_msg_ = [this](const std::string &msg) {
do {
} while (!ice_transmission_);
auto j = json::parse(msg);
std::string type = j["type"];
auto itr = siganl_types.find(type);
if (itr != siganl_types.end()) {
LOG_INFO("msg type :{}", itr->first);
switch (itr->second) {
case 1: {
ws_connection_id_ = j["ws_connection_id"].get<unsigned int>();
LOG_INFO("Receive local peer websocket connection id [{}]",
ws_connection_id_);
signal_status_ = SignalStatus::Connected;
break;
LOG_INFO("msg type :{}", type.c_str());
switch (HASH_STRING_PIECE(type.c_str())) {
case "ws_connection_id"_H: {
ws_connection_id_ = j["ws_connection_id"].get<unsigned int>();
LOG_INFO("Receive local peer websocket connection id [{}]",
ws_connection_id_);
signal_status_ = SignalStatus::Connected;
break;
}
case "transmission_id"_H: {
if (j["status"].get<std::string>() == "success") {
transmission_id_ = j["transmission_id"].get<std::string>();
LOG_INFO("Create transmission success with id [{}]",
transmission_id_);
} else if (j["status"].get<std::string>() == "fail") {
LOG_WARN("Create transmission failed with id [{}], due to [{}]",
transmission_id_, j["reason"].get<std::string>().c_str());
}
default: {
ice_transmission_->OnReceiveMessage(msg);
break;
break;
}
case "offer"_H: {
std::string remote_sdp = j["sdp"].get<std::string>();
if (remote_sdp.empty()) {
LOG_INFO("Invalid remote sdp");
} else {
LOG_INFO("Receive remote sdp [{}]", remote_sdp);
ice_transmission_ =
new IceTransmission(false, ws_transport_, on_receive_ice_msg_);
std::string ice_username = GetIceUsername(remote_sdp);
ice_transmission_list_[ice_username] = ice_transmission_;
ice_transmission_->InitIceTransmission(cfg_stun_server_ip_,
stun_server_port_);
ice_transmission_->SetRemoteSdp(remote_sdp);
ice_transmission_->GatherCandidates();
}
break;
}
default: {
ice_transmission_->OnReceiveMessage(msg);
break;
}
}
};
@@ -63,23 +93,28 @@ int PeerConnection::Create(PeerConnectionParams params, const std::string &id) {
};
ws_transport_ = new WsTransmission(on_receive_ws_msg_);
uri_ = "ws://" + cfg_signal_server_ip + ":" + cfg_signal_server_port;
uri_ = "ws://" + cfg_signal_server_ip_ + ":" + cfg_signal_server_port_;
if (ws_transport_) {
ws_transport_->Connect(uri_);
}
ice_transmission_ = new IceTransmission(ws_transport_, on_receive_ice_msg_);
ice_transmission_->InitIceTransmission(cfg_stun_server_ip, stun_server_port);
do {
LOG_INFO("GetSignalStatus = {}", GetSignalStatus());
} while (SignalStatus::Connected != GetSignalStatus());
ice_transmission_->CreateTransmission(id);
// ice_transmission_->CreateTransmission(transmission_id);
json message = {{"type", "create_transmission"},
{"transmission_id", transmission_id}};
if (ws_transport_) {
ws_transport_->Send(message.dump());
LOG_INFO("Send create transmission request: {}", message.dump().c_str());
}
return 0;
}
int PeerConnection::Join(PeerConnectionParams params, const std::string &id) {
int PeerConnection::Join(PeerConnectionParams params,
const std::string &transmission_id) {
INIReader reader(params.cfg_path);
std::string cfg_signal_server_ip = reader.Get("signal server", "ip", "-1");
std::string cfg_signal_server_port =
@@ -120,7 +155,7 @@ int PeerConnection::Join(PeerConnectionParams params, const std::string &id) {
LOG_INFO("Receive data: [{}]", msg.c_str());
};
transmission_id_ = id;
transmission_id_ = transmission_id;
ws_transport_ = new WsTransmission(on_receive_ws_msg_);
uri_ = "ws://" + cfg_signal_server_ip + ":" + cfg_signal_server_port;
@@ -128,9 +163,9 @@ int PeerConnection::Join(PeerConnectionParams params, const std::string &id) {
ws_transport_->Connect(uri_);
}
ice_transmission_ = new IceTransmission(ws_transport_, on_receive_ice_msg_);
ice_transmission_->InitIceTransmission(cfg_stun_server_ip, stun_server_port,
id);
ice_transmission_ =
new IceTransmission(true, ws_transport_, on_receive_ice_msg_);
ice_transmission_->InitIceTransmission(cfg_stun_server_ip, stun_server_port);
do {
LOG_INFO("GetSignalStatus = {}", GetSignalStatus());

View File

@@ -2,6 +2,7 @@
#define _PEER_CONNECTION_H_
#include <iostream>
#include <map>
#include "ice_transmission.h"
#include "ws_transmission.h"
@@ -35,8 +36,15 @@ class PeerConnection {
private:
std::string uri_ = "";
std::string cfg_signal_server_ip_;
std::string cfg_signal_server_port_;
std::string cfg_stun_server_ip_;
std::string cfg_stun_server_port_;
int signal_server_port_ = 0;
int stun_server_port_ = 0;
WsTransmission *ws_transport_ = nullptr;
IceTransmission *ice_transmission_ = nullptr;
std::map<std::string, IceTransmission *> ice_transmission_list_;
std::function<void(const std::string &)> on_receive_ws_msg_ = nullptr;
std::function<void(const char *, size_t)> on_receive_ice_msg_ = nullptr;
unsigned int ws_connection_id_ = 0;