[feat] implentation for negotiation module

This commit is contained in:
dijunkun
2024-09-18 17:29:30 +08:00
parent 0e3da6daf8
commit e48b29a2c8
6 changed files with 180 additions and 58 deletions

View File

@@ -1,17 +1,21 @@
#include "ice_agent.h"
#include <glib.h>
#include <cstring>
#include <iostream>
#include "log.h"
IceAgent::IceAgent(bool enable_turn, bool trickle_ice, bool offer_peer,
std::string &stun_ip, uint16_t stun_port,
std::string &turn_ip, uint16_t turn_port,
IceAgent::IceAgent(bool offer_peer, bool use_trickle_ice, bool use_reliable_ice,
bool enable_turn, bool force_turn, std::string &stun_ip,
uint16_t stun_port, std::string &turn_ip, uint16_t turn_port,
std::string &turn_username, std::string &turn_password)
: enable_turn_(enable_turn),
trickle_ice_(trickle_ice),
stun_ip_(stun_ip),
: stun_ip_(stun_ip),
use_trickle_ice_(use_trickle_ice),
use_reliable_ice_(use_reliable_ice),
enable_turn_(enable_turn),
force_turn_(force_turn),
stun_port_(stun_port),
turn_ip_(turn_ip),
turn_port_(turn_port),
@@ -26,7 +30,6 @@ IceAgent::~IceAgent() {
g_object_unref(agent_);
g_free(ice_ufrag_);
g_free(ice_password_);
g_free(stream_sdp_);
}
int IceAgent::CreateIceAgent(nice_cb_state_changed_t on_state_changed,
@@ -52,17 +55,17 @@ int IceAgent::CreateIceAgent(nice_cb_state_changed_t on_state_changed,
agent_ = nice_agent_new_full(
g_main_loop_get_context(gloop_), NICE_COMPATIBILITY_RFC5245,
(NiceAgentOption)(trickle_ice_
? NICE_AGENT_OPTION_ICE_TRICKLE |
(enable_turn_ ? NICE_AGENT_OPTION_NONE
: NICE_AGENT_OPTION_RELIABLE)
: (enable_turn_ ? NICE_AGENT_OPTION_NONE
: NICE_AGENT_OPTION_RELIABLE)));
(NiceAgentOption)(use_trickle_ice_
? (NICE_AGENT_OPTION_ICE_TRICKLE |
(use_reliable_ice_ ? NICE_AGENT_OPTION_RELIABLE
: NICE_AGENT_OPTION_NONE))
: (use_reliable_ice_ ? NICE_AGENT_OPTION_RELIABLE
: NICE_AGENT_OPTION_NONE)));
LOG_INFO(
"Nice agent init with [trickle ice|{}], [reliable mode|{}], [turn "
"support|{}]]",
trickle_ice_, !enable_turn_, enable_turn_);
"support|{}], [force turn|{}]]",
use_trickle_ice_, use_reliable_ice_, enable_turn_, force_turn_);
if (agent_ == nullptr) {
LOG_ERROR("Failed to create agent_");
@@ -95,7 +98,9 @@ int IceAgent::CreateIceAgent(nice_cb_state_changed_t on_state_changed,
NICE_RELAY_TYPE_TURN_TCP);
}
// g_object_set(agent_, "force-relay", true, NULL);
if (force_turn_) {
g_object_set(agent_, "force-relay", true, NULL);
}
nice_agent_attach_recv(agent_, stream_id_, NICE_COMPONENT_TYPE_RTP,
g_main_loop_get_context(gloop_), on_recv_,
@@ -142,12 +147,12 @@ int IceAgent::DestroyIceAgent() {
return 0;
}
char *IceAgent::GetLocalStreamSdp() {
stream_sdp_ = nice_agent_generate_local_stream_sdp(agent_, stream_id_, true);
return stream_sdp_;
const char *IceAgent::GetLocalStreamSdp() {
local_sdp_ = nice_agent_generate_local_stream_sdp(agent_, stream_id_, true);
return local_sdp_.c_str();
}
char *IceAgent::GenerateLocalSdp() {
const char *IceAgent::GenerateLocalSdp() {
if (!nice_inited_) {
LOG_ERROR("Nice agent has not been initialized");
return nullptr;
@@ -164,9 +169,9 @@ char *IceAgent::GenerateLocalSdp() {
}
local_sdp_ = nice_agent_generate_local_sdp(agent_);
LOG_INFO("Generate local sdp:[\n{}]", local_sdp_);
LOG_INFO("Generate local sdp:[\n{}]", local_sdp_.c_str());
return local_sdp_;
return local_sdp_.c_str();
}
int IceAgent::SetRemoteSdp(const char *remote_sdp) {

View File

@@ -29,10 +29,10 @@ typedef void (*nice_cb_recv_t)(NiceAgent* agent, guint stream_id,
class IceAgent {
public:
IceAgent(bool enable_turn, bool trickle_ice, bool offer_peer,
std::string& stun_ip, uint16_t stun_port, std::string& turn_ip,
uint16_t turn_port, std::string& turn_username,
std::string& turn_password);
IceAgent(bool offer_peer, bool use_trickle_ice, bool use_reliable_ice,
bool enable_turn, bool force_turn, std::string& stun_ip,
uint16_t stun_port, std::string& turn_ip, uint16_t turn_port,
std::string& turn_username, std::string& turn_password);
~IceAgent();
int CreateIceAgent(nice_cb_state_changed_t on_state_changed,
@@ -43,9 +43,9 @@ class IceAgent {
int DestroyIceAgent();
char* GetLocalStreamSdp();
const char* GetLocalStreamSdp();
char* GenerateLocalSdp();
const char* GenerateLocalSdp();
int SetRemoteSdp(const char* remote_sdp);
@@ -58,7 +58,11 @@ class IceAgent {
int Send(const char* data, size_t size);
public:
bool use_trickle_ice_ = true;
bool use_reliable_ice_ = false;
bool enable_turn_ = false;
bool force_turn_ = false;
std::string stun_ip_ = "";
uint16_t stun_port_ = 0;
std::string turn_ip_ = "";
@@ -72,14 +76,13 @@ class IceAgent {
std::atomic<bool> nice_inited_{false};
gboolean exit_nice_thread_ = false;
bool trickle_ice_ = true;
bool controlling_ = false;
gchar* ice_ufrag_ = nullptr;
gchar* ice_password_ = nullptr;
gchar* stream_sdp_ = nullptr;
uint32_t stream_id_ = 0;
uint32_t n_components_ = 1;
char* local_sdp_ = nullptr;
// char* local_sdp_ = nullptr;
std::string local_sdp_ = "";
NiceComponentState state_ = NiceComponentState::NICE_COMPONENT_STATE_LAST;
bool destroyed_ = false;
gboolean agent_closed_ = false;

View File

@@ -51,6 +51,7 @@ int PeerConnection::Init(PeerConnectionParams params,
cfg_hardware_acceleration_ =
reader.Get("hardware acceleration", "turn_on", "false");
cfg_av1_encoding_ = reader.Get("av1 encoding", "turn_on", "false");
cfg_enable_turn_ = reader.Get("enable turn", "turn_on", "false");
std::regex regex("\n");
@@ -61,6 +62,7 @@ int PeerConnection::Init(PeerConnectionParams params,
hardware_acceleration_ =
cfg_hardware_acceleration_ == "true" ? true : false;
av1_encoding_ = cfg_av1_encoding_ == "true" ? true : false;
enable_turn_ = cfg_enable_turn_ == "true" ? true : false;
} else {
cfg_signal_server_ip_ = params.signal_server_ip;
@@ -777,9 +779,13 @@ void PeerConnection::ProcessIceWorkMsg(const IceWorkMsg &msg) {
for (auto &remote_user_id : user_id_list) {
ice_transmission_list_[remote_user_id] =
std::make_unique<IceTransmission>(
enable_turn_, trickle_ice_, true, transmission_id, user_id_,
remote_user_id, ws_transport_, on_ice_status_change_);
std::make_unique<IceTransmission>(true, transmission_id, user_id_,
remote_user_id, ws_transport_,
on_ice_status_change_);
ice_transmission_list_[remote_user_id]->SetLocalCapabilities(
trickle_ice_, false, enable_turn_, false, video_payload_types_,
audio_payload_types_);
ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc(
on_receive_video_);
@@ -820,9 +826,13 @@ void PeerConnection::ProcessIceWorkMsg(const IceWorkMsg &msg) {
ice_transmission_list_.find(remote_user_id)) {
// Enable TURN for answer peer by default
ice_transmission_list_[remote_user_id] =
std::make_unique<IceTransmission>(
true, trickle_ice_, false, transmission_id, user_id_,
remote_user_id, ws_transport_, on_ice_status_change_);
std::make_unique<IceTransmission>(false, transmission_id, user_id_,
remote_user_id, ws_transport_,
on_ice_status_change_);
ice_transmission_list_[remote_user_id]->SetLocalCapabilities(
trickle_ice_, false, enable_turn_, false, std::vector<int>(),
std::vector<int>());
ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc(
on_receive_video_);

View File

@@ -129,6 +129,7 @@ class PeerConnection {
std::string cfg_turn_server_password_;
std::string cfg_hardware_acceleration_;
std::string cfg_av1_encoding_;
std::string cfg_enable_turn_;
int signal_server_port_ = 0;
int stun_server_port_ = 0;
int turn_server_port_ = 0;
@@ -138,6 +139,9 @@ class PeerConnection {
bool trickle_ice_ = true;
TraversalMode mode_ = TraversalMode::P2P;
bool try_rejoin_with_turn_ = true;
std::vector<int> video_payload_types_ = {RtpPacket::PAYLOAD_TYPE::H264,
RtpPacket::PAYLOAD_TYPE::AV1};
std::vector<int> audio_payload_types_ = {RtpPacket::PAYLOAD_TYPE::OPUS};
private:
std::shared_ptr<WsClient> ws_transport_ = nullptr;

View File

@@ -12,13 +12,10 @@
using nlohmann::json;
IceTransmission::IceTransmission(
bool enable_turn, bool trickle_ice, bool offer_peer,
std::string &transmission_id, std::string &user_id,
bool offer_peer, std::string &transmission_id, std::string &user_id,
std::string &remote_user_id, std::shared_ptr<WsClient> ice_ws_transmission,
std::function<void(std::string)> on_ice_status_change)
: enable_turn_(enable_turn),
trickle_ice_(trickle_ice),
offer_peer_(offer_peer),
: offer_peer_(offer_peer),
transmission_id_(transmission_id),
user_id_(user_id),
remote_user_id_(remote_user_id),
@@ -39,6 +36,19 @@ IceTransmission::~IceTransmission() {
}
}
int IceTransmission::SetLocalCapabilities(
bool use_trickle_ice, bool use_reliable_ice, bool enable_turn,
bool force_turn, std::vector<int> &video_payload_types,
std::vector<int> &audio_payload_types) {
use_trickle_ice_ = use_trickle_ice;
use_reliable_ice_ = use_reliable_ice;
enable_turn_ = force_turn;
force_turn_ = force_turn;
video_payload_types_ = video_payload_types;
audio_payload_types_ = audio_payload_types;
return 0;
}
int IceTransmission::InitIceTransmission(
std::string &stun_ip, int stun_port, std::string &turn_ip, int turn_port,
std::string &turn_username, std::string &turn_password,
@@ -204,8 +214,9 @@ int IceTransmission::InitIceTransmission(
rtp_data_sender_->Start();
ice_agent_ = std::make_unique<IceAgent>(
enable_turn_, trickle_ice_, offer_peer_, stun_ip, stun_port, turn_ip,
turn_port, turn_username, turn_password);
offer_peer_, use_trickle_ice_, use_reliable_ice_, enable_turn_,
force_turn_, stun_ip, stun_port, turn_ip, turn_port, turn_username,
turn_password);
ice_agent_->CreateIceAgent(
[](NiceAgent *agent, guint stream_id, guint component_id,
@@ -235,7 +246,7 @@ int IceTransmission::InitIceTransmission(
IceTransmission *ice_transmission_obj =
static_cast<IceTransmission *>(user_ptr);
if (ice_transmission_obj->trickle_ice_) {
if (ice_transmission_obj->use_trickle_ice_) {
GSList *cands =
nice_agent_get_local_candidates(agent, stream_id, component_id);
NiceCandidate *cand;
@@ -274,7 +285,7 @@ int IceTransmission::InitIceTransmission(
LOG_INFO("[{}->{}] gather_done", ice_transmission_obj->user_id_,
ice_transmission_obj->remote_user_id_);
if (!ice_transmission_obj->trickle_ice_) {
if (!ice_transmission_obj->use_trickle_ice_) {
if (ice_transmission_obj->offer_peer_) {
ice_transmission_obj->SendOffer();
} else {
@@ -352,7 +363,7 @@ int IceTransmission::SetTransmissionId(const std::string &transmission_id) {
int IceTransmission::JoinTransmission() {
LOG_INFO("[{}] Join transmission", user_id_);
if (trickle_ice_) {
if (use_trickle_ice_) {
SendOffer();
} else {
GatherCandidates();
@@ -371,19 +382,33 @@ int IceTransmission::GatherCandidates() {
int IceTransmission::SetRemoteSdp(const std::string &remote_sdp) {
ice_agent_->SetRemoteSdp(remote_sdp.c_str());
// LOG_INFO("[{}] set remote sdp", user_id_);
// GetAceptedVideoPayloadType(remote_sdp);
// GetAceptedAudioPayloadType(remote_sdp);
remote_ice_username_ = GetIceUsername(remote_sdp);
return 0;
}
int IceTransmission::SendOffer() {
local_sdp_ = use_trickle_ice_ ? ice_agent_->GetLocalStreamSdp()
: ice_agent_->GenerateLocalSdp();
std::string toReplace = "ICE/SDP";
std::string replacement = "UDP/TLS/RTP/SAVPF 111 114 115 116 123 124 125";
size_t pos = 0;
while ((pos = local_sdp_.find(toReplace, pos)) != std::string::npos) {
local_sdp_.replace(pos, toReplace.length(), replacement);
pos += replacement.length();
}
json message = {{"type", "offer"},
{"transmission_id", transmission_id_},
{"user_id", user_id_},
{"remote_user_id", remote_user_id_},
{"sdp", trickle_ice_ ? ice_agent_->GetLocalStreamSdp()
: ice_agent_->GenerateLocalSdp()}};
// LOG_INFO("Send offer with sdp:[{}]", message.dump());
{"sdp", local_sdp_.c_str()}};
LOG_INFO("Send offer with sdp:\n[\n{}]", local_sdp_.c_str());
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
LOG_INFO("[{}->{}] send offer", user_id_, remote_user_id_);
@@ -392,13 +417,14 @@ int IceTransmission::SendOffer() {
}
int IceTransmission::SendAnswer() {
local_sdp_ = use_trickle_ice_ ? ice_agent_->GetLocalStreamSdp()
: ice_agent_->GenerateLocalSdp();
json message = {{"type", "answer"},
{"transmission_id", transmission_id_},
{"user_id", user_id_},
{"remote_user_id", remote_user_id_},
{"sdp", trickle_ice_ ? ice_agent_->GetLocalStreamSdp()
: ice_agent_->GenerateLocalSdp()}};
// LOG_INFO("Send answer with sdp:[{}]", message.dump());
{"sdp", local_sdp_.c_str()}};
LOG_INFO("Send answer with sdp:\n[\n{}]", local_sdp_.c_str());
if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump());
LOG_INFO("[{}->{}] send answer", user_id_, remote_user_id_);
@@ -407,6 +433,61 @@ int IceTransmission::SendAnswer() {
return 0;
}
// int IceTransmission::AppendLocalCapabilitiesToSdp() {
// std::string toReplace = "ICE/SDP";
// std::string replacement = "UDP/TLS/RTP/SAVPF 111 114 115 116 123 124 125";
// size_t pos = 0;
// while ((pos = local_sdp_.find(toReplace, pos)) != std::string::npos) {
// local_sdp_.replace(pos, toReplace.length(), replacement);
// pos += replacement.length();
// }
// return 0;
// }
RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedVideoPayloadType(
const std::string &remote_sdp) {
if (!video_pt_.empty()) {
return RtpPacket::PAYLOAD_TYPE::H264;
}
std::size_t start =
remote_sdp.find("m=video ") + std::string("m=video ").length();
if (start != std::string::npos) {
std::size_t end = remote_sdp.find("\n", start);
std::string::size_type pos1 = remote_sdp.find(' ', start);
std::string::size_type pos2 = remote_sdp.find(' ', pos1 + 1);
std::string::size_type pos3 = remote_sdp.find(' ', pos2 + 1);
if (end != std::string::npos && pos1 != std::string::npos &&
pos2 != std::string::npos && pos3 != std::string::npos) {
video_pt_ = remote_sdp.substr(pos3 + 1, end - pos3 - 1);
}
}
LOG_INFO("video pt [{}]", video_pt_.c_str());
return RtpPacket::PAYLOAD_TYPE::H264;
}
RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedAudioPayloadType(
const std::string &remote_sdp) {
if (!audio_pt_.empty()) {
return RtpPacket::PAYLOAD_TYPE::H264;
}
std::size_t start =
remote_sdp.find("m=audio ") + std::string("m=audio ").length();
if (start != std::string::npos) {
std::size_t end = remote_sdp.find("\n", start);
std::string::size_type pos1 = remote_sdp.find(' ', start);
std::string::size_type pos2 = remote_sdp.find(' ', pos1 + 1);
std::string::size_type pos3 = remote_sdp.find(' ', pos2 + 1);
if (end != std::string::npos && pos1 != std::string::npos &&
pos2 != std::string::npos && pos3 != std::string::npos) {
audio_pt_ = remote_sdp.substr(pos3 + 1, end - pos3 - 1);
}
}
LOG_INFO("audio pt [{}]", audio_pt_.c_str());
return RtpPacket::PAYLOAD_TYPE::OPUS;
}
int IceTransmission::SendData(DATA_TYPE type, const char *data, size_t size) {
if (state_ != NICE_COMPONENT_STATE_CONNECTED &&
state_ != NICE_COMPONENT_STATE_READY) {

View File

@@ -35,14 +35,18 @@ class IceTransmission {
enum TraversalType { TP2P = 0, TRelay = 1, TUnknown = 2 };
public:
IceTransmission(bool enable_turn, bool trickle_ice, bool offer_peer,
std::string &transmission_id, std::string &user_id,
std::string &remote_user_id,
IceTransmission(bool offer_peer, std::string &transmission_id,
std::string &user_id, std::string &remote_user_id,
std::shared_ptr<WsClient> ice_ws_transmission,
std::function<void(std::string)> on_ice_status_change);
~IceTransmission();
public:
int SetLocalCapabilities(bool use_trickle_ice, bool use_reliable_ice,
bool enable_turn, bool force_turn,
std::vector<int> &video_payload_types,
std::vector<int> &audio_payload_types);
int InitIceTransmission(std::string &stun_ip, int stun_port,
std::string &turn_ip, int turn_port,
std::string &turn_username,
@@ -99,6 +103,12 @@ class IceTransmission {
int SendAnswer();
private:
RtpPacket::PAYLOAD_TYPE GetAceptedVideoPayloadType(
const std::string &remote_sdp);
RtpPacket::PAYLOAD_TYPE GetAceptedAudioPayloadType(
const std::string &remote_sdp);
private:
uint8_t CheckIsRtcpPacket(const char *buffer, size_t size);
uint8_t CheckIsVideoPacket(const char *buffer, size_t size);
@@ -106,8 +116,13 @@ class IceTransmission {
uint8_t CheckIsDataPacket(const char *buffer, size_t size);
private:
bool use_trickle_ice_ = true;
bool enable_turn_ = false;
bool trickle_ice_ = true;
bool use_reliable_ice_ = false;
bool force_turn_ = false;
std::vector<int> video_payload_types_;
std::vector<int> audio_payload_types_;
std::string local_sdp_;
std::string remote_sdp_;
std::string new_local_candidate_;
@@ -154,6 +169,10 @@ class IceTransmission {
private:
std::unique_ptr<IOStatistics> ice_io_statistics_ = nullptr;
private:
std::string video_pt_;
std::string audio_pt_;
};
#endif