diff --git a/src/ice/ice_agent.cpp b/src/ice/ice_agent.cpp index 51a3d3e..296a154 100644 --- a/src/ice/ice_agent.cpp +++ b/src/ice/ice_agent.cpp @@ -1,17 +1,21 @@ #include "ice_agent.h" +#include + #include #include #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) { diff --git a/src/ice/ice_agent.h b/src/ice/ice_agent.h index 60fa921..20cf5ac 100644 --- a/src/ice/ice_agent.h +++ b/src/ice/ice_agent.h @@ -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 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; diff --git a/src/pc/peer_connection.cpp b/src/pc/peer_connection.cpp index 499a334..be5bd5f 100644 --- a/src/pc/peer_connection.cpp +++ b/src/pc/peer_connection.cpp @@ -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( - enable_turn_, trickle_ice_, true, transmission_id, user_id_, - remote_user_id, ws_transport_, on_ice_status_change_); + std::make_unique(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( - true, trickle_ice_, false, transmission_id, user_id_, - remote_user_id, ws_transport_, on_ice_status_change_); + std::make_unique(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(), + std::vector()); ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc( on_receive_video_); diff --git a/src/pc/peer_connection.h b/src/pc/peer_connection.h index f1d368f..7e4c145 100644 --- a/src/pc/peer_connection.h +++ b/src/pc/peer_connection.h @@ -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 video_payload_types_ = {RtpPacket::PAYLOAD_TYPE::H264, + RtpPacket::PAYLOAD_TYPE::AV1}; + std::vector audio_payload_types_ = {RtpPacket::PAYLOAD_TYPE::OPUS}; private: std::shared_ptr ws_transport_ = nullptr; diff --git a/src/transmission/ice_transmission.cpp b/src/transmission/ice_transmission.cpp index 9b40a55..2b4ca1f 100644 --- a/src/transmission/ice_transmission.cpp +++ b/src/transmission/ice_transmission.cpp @@ -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 ice_ws_transmission, std::function 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 &video_payload_types, + std::vector &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( - 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(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) { diff --git a/src/transmission/ice_transmission.h b/src/transmission/ice_transmission.h index 150514e..9da6156 100644 --- a/src/transmission/ice_transmission.h +++ b/src/transmission/ice_transmission.h @@ -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 ice_ws_transmission, std::function on_ice_status_change); ~IceTransmission(); public: + int SetLocalCapabilities(bool use_trickle_ice, bool use_reliable_ice, + bool enable_turn, bool force_turn, + std::vector &video_payload_types, + std::vector &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 video_payload_types_; + std::vector 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 ice_io_statistics_ = nullptr; + + private: + std::string video_pt_; + std::string audio_pt_; }; #endif \ No newline at end of file