diff --git a/src/rtp/rtp_packet.h b/src/rtp/rtp_packet.h index 7b25037..6274f09 100644 --- a/src/rtp/rtp_packet.h +++ b/src/rtp/rtp_packet.h @@ -160,6 +160,7 @@ class RtpPacket { public: typedef enum { + UNDEFINED = 0, H264 = 96, H264_FEC_SOURCE = 97, H264_FEC_REPAIR = 98, diff --git a/src/transmission/ice_transmission.cpp b/src/transmission/ice_transmission.cpp index 90db5df..bc8c94a 100644 --- a/src/transmission/ice_transmission.cpp +++ b/src/transmission/ice_transmission.cpp @@ -44,8 +44,9 @@ int IceTransmission::SetLocalCapabilities( 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; + support_video_payload_types_ = video_payload_types; + support_audio_payload_types_ = audio_payload_types; + support_data_payload_types_ = {RtpPacket::PAYLOAD_TYPE::DATA}; return 0; } @@ -382,6 +383,11 @@ int IceTransmission::GatherCandidates() { int IceTransmission::SetRemoteSdp(const std::string &remote_sdp) { std::string media_stream_sdp = GetRemoteCapabilities(remote_sdp); + if (media_stream_sdp.empty()) { + LOG_ERROR("Set remote sdp failed due to negotiation failed"); + return -1; + } + ice_agent_->SetRemoteSdp(media_stream_sdp.c_str()); // LOG_INFO("[{}] set remote sdp", user_id_); @@ -391,7 +397,7 @@ int IceTransmission::SetRemoteSdp(const std::string &remote_sdp) { int IceTransmission::SendOffer() { local_sdp_ = ice_agent_->GenerateLocalSdp(); - AppendLocalCapabilities(local_sdp_); + AppendLocalCapabilitiesToOffer(local_sdp_); json message = {{"type", "offer"}, {"transmission_id", transmission_id_}, {"user_id", user_id_}, @@ -407,7 +413,7 @@ int IceTransmission::SendOffer() { int IceTransmission::SendAnswer() { local_sdp_ = ice_agent_->GenerateLocalSdp(); - AppendLocalCapabilities(local_sdp_); + AppendLocalCapabilitiesToAnswer(local_sdp_); json message = {{"type", "answer"}, {"transmission_id", transmission_id_}, {"user_id", user_id_}, @@ -422,10 +428,11 @@ int IceTransmission::SendAnswer() { return 0; } -int IceTransmission::AppendLocalCapabilities(std::string &remote_sdp) { +int IceTransmission::AppendLocalCapabilitiesToOffer( + const std::string &remote_sdp) { std::string preferred_video_pt; std::string to_replace = "ICE/SDP"; - std::string video_capabilities; + std::string video_capabilities = "UDP/TLS/RTP/SAVPF"; std::string audio_capabilities = "UDP/TLS/RTP/SAVPF 111"; std::string data_capabilities = "UDP/TLS/RTP/SAVPF 127"; @@ -479,6 +486,51 @@ int IceTransmission::AppendLocalCapabilities(std::string &remote_sdp) { return 0; } +int IceTransmission::AppendLocalCapabilitiesToAnswer( + const std::string &remote_sdp) { + std::string negotiated_video_pt; + std::string negotiated_audio_pt; + std::string negotiated_data_pt; + std::string to_replace = "ICE/SDP"; + std::string protocol = "UDP/TLS/RTP/SAVPF "; + negotiated_video_pt = protocol + std::to_string(negotiated_video_pt_); + negotiated_audio_pt = protocol + std::to_string(negotiated_audio_pt_); + negotiated_data_pt = protocol + std::to_string(negotiated_data_pt_); + + std::size_t video_start = remote_sdp.find("m=video"); + std::size_t video_end = remote_sdp.find("\n", video_start); + + size_t pos = 0; + if (video_start != std::string::npos && video_end != std::string::npos) { + if ((pos = local_sdp_.find(to_replace, video_start)) != std::string::npos) { + local_sdp_.replace(pos, to_replace.length(), negotiated_video_pt); + pos += negotiated_video_pt.length(); + } + } + + std::size_t audio_start = remote_sdp.find("m=audio"); + std::size_t audio_end = remote_sdp.find("\n", audio_start); + + if (audio_start != std::string::npos && audio_end != std::string::npos) { + if ((pos = local_sdp_.find(to_replace, audio_start)) != std::string::npos) { + local_sdp_.replace(pos, to_replace.length(), negotiated_audio_pt); + pos += negotiated_audio_pt.length(); + } + } + + std::size_t data_start = remote_sdp.find("m=data"); + std::size_t data_end = remote_sdp.find("\n", data_start); + + if (data_start != std::string::npos && data_end != std::string::npos) { + if ((pos = local_sdp_.find(to_replace, data_start)) != std::string::npos) { + local_sdp_.replace(pos, to_replace.length(), negotiated_data_pt); + pos += negotiated_data_pt.length(); + } + } + + return 0; +} + std::string IceTransmission::GetRemoteCapabilities( const std::string &remote_sdp) { std::string media_stream_sdp; @@ -491,9 +543,18 @@ std::string IceTransmission::GetRemoteCapabilities( std::size_t candidate_start = data_end; if (!remote_capabilities_got_) { - GetAceptedVideoPayloadType(remote_sdp); - GetAceptedAudioPayloadType(remote_sdp); - GetAceptedDataPayloadType(remote_sdp); + if (NegotiateVideoPayloadType(remote_sdp)) { + remote_capabilities_got_ = true; + return std::string(); + } + if (NegotiateAudioPayloadType(remote_sdp)) { + remote_capabilities_got_ = true; + return std::string(); + } + if (NegotiateDataPayloadType(remote_sdp)) { + remote_capabilities_got_ = true; + return std::string(); + } remote_capabilities_got_ = true; } @@ -521,12 +582,7 @@ std::string IceTransmission::GetRemoteCapabilities( return media_stream_sdp; } -RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedVideoPayloadType( - const std::string &remote_sdp) { - if (!video_pt_.empty()) { - return RtpPacket::PAYLOAD_TYPE::H264; - } - +bool IceTransmission::NegotiateVideoPayloadType(const std::string &remote_sdp) { std::string remote_video_capabilities; std::string remote_prefered_video_pt; @@ -544,24 +600,49 @@ RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedVideoPayloadType( } LOG_INFO("remote video capabilities [{}]", remote_video_capabilities.c_str()); - std::size_t prefered_pt_end = remote_video_capabilities.find(' '); - if (prefered_pt_end != std::string::npos) { - remote_prefered_video_pt = - remote_video_capabilities.substr(0, prefered_pt_end); - } else { - remote_prefered_video_pt = remote_video_capabilities; - } - LOG_INFO("remote prefered video pt [{}]", remote_prefered_video_pt.c_str()); + std::size_t prefered_pt_start = 0; - return RtpPacket::PAYLOAD_TYPE::H264; + while (prefered_pt_start <= remote_video_capabilities.length()) { + std::size_t prefered_pt_end = + remote_video_capabilities.find(' ', prefered_pt_start); + if (prefered_pt_end != std::string::npos) { + remote_prefered_video_pt = + remote_video_capabilities.substr(0, prefered_pt_end); + } else { + remote_prefered_video_pt = remote_video_capabilities; + } + + remote_prefered_video_pt_ = + (RtpPacket::PAYLOAD_TYPE)(atoi(remote_prefered_video_pt.c_str())); + + bool is_support_this_video_pt = + std::find(support_video_payload_types_.begin(), + support_video_payload_types_.end(), + remote_prefered_video_pt_) != + support_video_payload_types_.end(); + + if (is_support_this_video_pt) { + negotiated_video_pt_ = (RtpPacket::PAYLOAD_TYPE)remote_prefered_video_pt_; + break; + } else { + if (prefered_pt_end != std::string::npos) { + prefered_pt_start = prefered_pt_end + 1; + } else { + break; + } + } + } + + if (negotiated_video_pt_ == RtpPacket::PAYLOAD_TYPE::UNDEFINED) { + LOG_ERROR("Negotiate video pt failed"); + return false; + } else { + LOG_INFO("negotiated video pt [{}]", (int)negotiated_video_pt_); + return true; + } } -RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedAudioPayloadType( - const std::string &remote_sdp) { - if (!audio_pt_.empty()) { - return RtpPacket::PAYLOAD_TYPE::H264; - } - +bool IceTransmission::NegotiateAudioPayloadType(const std::string &remote_sdp) { std::string remote_audio_capabilities; std::string remote_prefered_audio_pt; @@ -579,23 +660,52 @@ RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedAudioPayloadType( } LOG_INFO("remote audio capabilities [{}]", remote_audio_capabilities.c_str()); - std::size_t prefered_pt_end = remote_audio_capabilities.find(' '); - if (prefered_pt_end != std::string::npos) { - remote_prefered_audio_pt = - remote_audio_capabilities.substr(0, prefered_pt_end); - } else { - remote_prefered_audio_pt = remote_audio_capabilities; - } - LOG_INFO("remote prefered audio pt [{}]", remote_prefered_audio_pt.c_str()); + std::size_t prefered_pt_start = 0; - return RtpPacket::PAYLOAD_TYPE::OPUS; + while (prefered_pt_start <= remote_audio_capabilities.length()) { + std::size_t prefered_pt_end = + remote_audio_capabilities.find(' ', prefered_pt_start); + if (prefered_pt_end != std::string::npos) { + remote_prefered_audio_pt = + remote_audio_capabilities.substr(0, prefered_pt_end); + } else { + remote_prefered_audio_pt = remote_audio_capabilities; + } + + remote_prefered_audio_pt_ = + (RtpPacket::PAYLOAD_TYPE)(atoi(remote_prefered_audio_pt.c_str())); + + bool is_support_this_audio_pt = + std::find(support_audio_payload_types_.begin(), + support_audio_payload_types_.end(), + remote_prefered_audio_pt_) != + support_audio_payload_types_.end(); + + if (is_support_this_audio_pt) { + negotiated_audio_pt_ = (RtpPacket::PAYLOAD_TYPE)remote_prefered_audio_pt_; + break; + } else { + if (prefered_pt_end != std::string::npos) { + prefered_pt_start = prefered_pt_end + 1; + } else { + break; + } + } + } + + if (negotiated_audio_pt_ == RtpPacket::PAYLOAD_TYPE::UNDEFINED) { + LOG_ERROR("Negotiate audio pt failed"); + return false; + } else { + LOG_INFO("negotiated audio pt [{}]", (int)negotiated_audio_pt_); + return true; + } } -RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedDataPayloadType( - const std::string &remote_sdp) { - if (!data_pt_.empty()) { - return RtpPacket::PAYLOAD_TYPE::H264; - } +bool IceTransmission::NegotiateDataPayloadType(const std::string &remote_sdp) { + std::string remote_data_capabilities; + std::string remote_prefered_data_pt; + std::size_t start = remote_sdp.find("m=data") + std::string("m=data").length(); if (start != std::string::npos) { @@ -605,11 +715,51 @@ RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedDataPayloadType( 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) { - data_pt_ = remote_sdp.substr(pos3 + 1, end - pos3 - 1); + remote_data_capabilities = remote_sdp.substr(pos3 + 1, end - pos3 - 1); } } - LOG_INFO("data pt [{}]", data_pt_.c_str()); - return RtpPacket::PAYLOAD_TYPE::DATA; + LOG_INFO("remote data capabilities [{}]", remote_data_capabilities.c_str()); + + std::size_t prefered_pt_start = 0; + + while (prefered_pt_start <= remote_data_capabilities.length()) { + std::size_t prefered_pt_end = + remote_data_capabilities.find(' ', prefered_pt_start); + if (prefered_pt_end != std::string::npos) { + remote_prefered_data_pt = + remote_data_capabilities.substr(0, prefered_pt_end); + } else { + remote_prefered_data_pt = remote_data_capabilities; + } + + remote_prefered_data_pt_ = + (RtpPacket::PAYLOAD_TYPE)(atoi(remote_prefered_data_pt.c_str())); + + bool is_support_this_data_pt = + std::find(support_data_payload_types_.begin(), + support_data_payload_types_.end(), + remote_prefered_data_pt_) != + support_data_payload_types_.end(); + + if (is_support_this_data_pt) { + negotiated_data_pt_ = (RtpPacket::PAYLOAD_TYPE)remote_prefered_data_pt_; + break; + } else { + if (prefered_pt_end != std::string::npos) { + prefered_pt_start = prefered_pt_end + 1; + } else { + break; + } + } + } + + if (negotiated_data_pt_ == RtpPacket::PAYLOAD_TYPE::UNDEFINED) { + LOG_ERROR("Negotiate data pt failed"); + return false; + } else { + LOG_INFO("negotiated data pt [{}]", (int)negotiated_data_pt_); + return true; + } } int IceTransmission::SendData(DATA_TYPE type, const char *data, size_t size) { diff --git a/src/transmission/ice_transmission.h b/src/transmission/ice_transmission.h index 0124c3b..c638470 100644 --- a/src/transmission/ice_transmission.h +++ b/src/transmission/ice_transmission.h @@ -104,15 +104,13 @@ class IceTransmission { int SendAnswer(); private: - int AppendLocalCapabilities(std::string &remote_sdp); + int AppendLocalCapabilitiesToOffer(const std::string &remote_sdp); + int AppendLocalCapabilitiesToAnswer(const std::string &remote_sdp); std::string GetRemoteCapabilities(const std::string &remote_sdp); - RtpPacket::PAYLOAD_TYPE GetAceptedVideoPayloadType( - const std::string &remote_sdp); - RtpPacket::PAYLOAD_TYPE GetAceptedAudioPayloadType( - const std::string &remote_sdp); - RtpPacket::PAYLOAD_TYPE GetAceptedDataPayloadType( - const std::string &remote_sdp); + bool NegotiateVideoPayloadType(const std::string &remote_sdp); + bool NegotiateAudioPayloadType(const std::string &remote_sdp); + bool NegotiateDataPayloadType(const std::string &remote_sdp); private: uint8_t CheckIsRtcpPacket(const char *buffer, size_t size); @@ -125,8 +123,9 @@ class IceTransmission { bool enable_turn_ = false; bool use_reliable_ice_ = false; bool force_turn_ = false; - std::vector video_payload_types_; - std::vector audio_payload_types_; + std::vector support_video_payload_types_; + std::vector support_audio_payload_types_; + std::vector support_data_payload_types_; std::string local_sdp_; std::string remote_sdp_; @@ -176,12 +175,20 @@ class IceTransmission { std::unique_ptr ice_io_statistics_ = nullptr; private: - std::string video_pt_; - std::string audio_pt_; - std::string data_pt_; - RtpPacket::PAYLOAD_TYPE video_codec_payload_type_; bool remote_capabilities_got_ = false; + RtpPacket::PAYLOAD_TYPE remote_prefered_video_pt_ = + RtpPacket::PAYLOAD_TYPE::UNDEFINED; + RtpPacket::PAYLOAD_TYPE remote_prefered_audio_pt_ = + RtpPacket::PAYLOAD_TYPE::UNDEFINED; + RtpPacket::PAYLOAD_TYPE remote_prefered_data_pt_ = + RtpPacket::PAYLOAD_TYPE::UNDEFINED; + RtpPacket::PAYLOAD_TYPE negotiated_video_pt_ = + RtpPacket::PAYLOAD_TYPE::UNDEFINED; + RtpPacket::PAYLOAD_TYPE negotiated_audio_pt_ = + RtpPacket::PAYLOAD_TYPE::UNDEFINED; + RtpPacket::PAYLOAD_TYPE negotiated_data_pt_ = + RtpPacket::PAYLOAD_TYPE::UNDEFINED; }; #endif \ No newline at end of file