[feat] support multiple streams in sdp

This commit is contained in:
dijunkun
2024-09-19 16:18:14 +08:00
parent e48b29a2c8
commit f4cf4d826b
4 changed files with 150 additions and 37 deletions

View File

@@ -89,7 +89,9 @@ int IceAgent::CreateIceAgent(nice_cb_state_changed_t on_state_changed,
LOG_ERROR("Failed to add stream"); LOG_ERROR("Failed to add stream");
} }
nice_agent_set_stream_name(agent_, stream_id_, "video"); if (has_video_stream_) {
nice_agent_set_stream_name(agent_, stream_id_, "video");
}
if (enable_turn_) { if (enable_turn_) {
nice_agent_set_relay_info(agent_, stream_id_, n_components_, nice_agent_set_relay_info(agent_, stream_id_, n_components_,
@@ -147,11 +149,6 @@ int IceAgent::DestroyIceAgent() {
return 0; return 0;
} }
const char *IceAgent::GetLocalStreamSdp() {
local_sdp_ = nice_agent_generate_local_stream_sdp(agent_, stream_id_, true);
return local_sdp_.c_str();
}
const char *IceAgent::GenerateLocalSdp() { const char *IceAgent::GenerateLocalSdp() {
if (!nice_inited_) { if (!nice_inited_) {
LOG_ERROR("Nice agent has not been initialized"); LOG_ERROR("Nice agent has not been initialized");
@@ -168,12 +165,60 @@ const char *IceAgent::GenerateLocalSdp() {
return nullptr; return nullptr;
} }
local_sdp_ = nice_agent_generate_local_sdp(agent_); video_stream_sdp_ = nice_agent_generate_local_sdp(agent_);
audio_stream_sdp_ = video_stream_sdp_;
data_stream_sdp_ = video_stream_sdp_;
local_sdp_ = video_stream_sdp_;
if (has_audio_stream_) {
std::string to_replace = "video";
std::string replacement = "audio";
size_t pos = 0;
while ((pos = audio_stream_sdp_.find(to_replace, pos)) !=
std::string::npos) {
audio_stream_sdp_.replace(pos, to_replace.length(), replacement);
pos += replacement.length();
}
local_sdp_ += audio_stream_sdp_;
}
if (has_data_stream_) {
std::string to_replace = "video";
std::string replacement = "data";
size_t pos = 0;
while ((pos = data_stream_sdp_.find(to_replace, pos)) !=
std::string::npos) {
data_stream_sdp_.replace(pos, to_replace.length(), replacement);
pos += replacement.length();
}
local_sdp_ += data_stream_sdp_;
}
LOG_INFO("Generate local sdp:[\n{}]", local_sdp_.c_str()); LOG_INFO("Generate local sdp:[\n{}]", local_sdp_.c_str());
return local_sdp_.c_str(); return local_sdp_.c_str();
} }
const char *IceAgent::GetLocalStreamSdp(uint32_t stream_id) {
if (!nice_inited_) {
LOG_ERROR("Nice agent has not been initialized");
return nullptr;
}
if (nullptr == agent_) {
LOG_ERROR("Nice agent is nullptr");
return nullptr;
}
if (destroyed_) {
LOG_ERROR("Nice agent is destroyed");
return nullptr;
}
local_sdp_ = nice_agent_generate_local_stream_sdp(agent_, stream_id, true);
return local_sdp_.c_str();
}
int IceAgent::SetRemoteSdp(const char *remote_sdp) { int IceAgent::SetRemoteSdp(const char *remote_sdp) {
if (!nice_inited_) { if (!nice_inited_) {
LOG_ERROR("Nice agent has not been initialized"); LOG_ERROR("Nice agent has not been initialized");

View File

@@ -43,10 +43,10 @@ class IceAgent {
int DestroyIceAgent(); int DestroyIceAgent();
const char* GetLocalStreamSdp();
const char* GenerateLocalSdp(); const char* GenerateLocalSdp();
const char* GetLocalStreamSdp(uint32_t stream_id);
int SetRemoteSdp(const char* remote_sdp); int SetRemoteSdp(const char* remote_sdp);
int GatherCandidates(); int GatherCandidates();
@@ -70,6 +70,17 @@ class IceAgent {
std::string turn_username_ = ""; std::string turn_username_ = "";
std::string turn_password_ = ""; std::string turn_password_ = "";
bool has_video_stream_ = true;
uint32_t n_video_streams_ = 1;
std::string video_stream_sdp_;
bool has_audio_stream_ = true;
uint32_t n_audio_streams_ = 1;
std::string audio_stream_sdp_;
bool has_data_stream_ = true;
uint32_t n_data_streams_ = 1;
std::string data_stream_sdp_;
public:
std::thread nice_thread_; std::thread nice_thread_;
std::atomic<NiceAgent*> agent_{nullptr}; std::atomic<NiceAgent*> agent_{nullptr};
std::atomic<GMainLoop*> gloop_{nullptr}; std::atomic<GMainLoop*> gloop_{nullptr};

View File

@@ -380,35 +380,30 @@ int IceTransmission::GatherCandidates() {
} }
int IceTransmission::SetRemoteSdp(const std::string &remote_sdp) { 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); // GetAceptedVideoPayloadType(remote_sdp);
// GetAceptedAudioPayloadType(remote_sdp); // GetAceptedAudioPayloadType(remote_sdp);
remote_ice_username_ = GetIceUsername(remote_sdp); std::string media_stream_sdp = GetLocalCapabilitiesToSdp(remote_sdp);
LOG_ERROR("media_stream_sdp: [{}] [{}]", media_stream_sdp, remote_sdp);
ice_agent_->SetRemoteSdp(media_stream_sdp.c_str());
// LOG_INFO("[{}] set remote sdp", user_id_);
remote_ice_username_ = GetIceUsername(media_stream_sdp);
return 0; return 0;
} }
int IceTransmission::SendOffer() { int IceTransmission::SendOffer() {
local_sdp_ = use_trickle_ice_ ? ice_agent_->GetLocalStreamSdp() local_sdp_ = ice_agent_->GenerateLocalSdp();
: ice_agent_->GenerateLocalSdp();
std::string toReplace = "ICE/SDP"; AppendLocalCapabilitiesToSdp(local_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"}, json message = {{"type", "offer"},
{"transmission_id", transmission_id_}, {"transmission_id", transmission_id_},
{"user_id", user_id_}, {"user_id", user_id_},
{"remote_user_id", remote_user_id_}, {"remote_user_id", remote_user_id_},
{"sdp", local_sdp_.c_str()}}; {"sdp", local_sdp_.c_str()}};
LOG_INFO("Send offer with sdp:\n[\n{}]", local_sdp_.c_str()); // LOG_INFO("Send offer with sdp:\n[\n{}]", local_sdp_.c_str());
if (ice_ws_transport_) { if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump()); ice_ws_transport_->Send(message.dump());
LOG_INFO("[{}->{}] send offer", user_id_, remote_user_id_); LOG_INFO("[{}->{}] send offer", user_id_, remote_user_id_);
@@ -417,14 +412,13 @@ int IceTransmission::SendOffer() {
} }
int IceTransmission::SendAnswer() { int IceTransmission::SendAnswer() {
local_sdp_ = use_trickle_ice_ ? ice_agent_->GetLocalStreamSdp() local_sdp_ = ice_agent_->GenerateLocalSdp();
: ice_agent_->GenerateLocalSdp();
json message = {{"type", "answer"}, json message = {{"type", "answer"},
{"transmission_id", transmission_id_}, {"transmission_id", transmission_id_},
{"user_id", user_id_}, {"user_id", user_id_},
{"remote_user_id", remote_user_id_}, {"remote_user_id", remote_user_id_},
{"sdp", local_sdp_.c_str()}}; {"sdp", local_sdp_.c_str()}};
LOG_INFO("Send answer with sdp:\n[\n{}]", local_sdp_.c_str()); // LOG_INFO("Send answer with sdp:\n[\n{}]", local_sdp_.c_str());
if (ice_ws_transport_) { if (ice_ws_transport_) {
ice_ws_transport_->Send(message.dump()); ice_ws_transport_->Send(message.dump());
LOG_INFO("[{}->{}] send answer", user_id_, remote_user_id_); LOG_INFO("[{}->{}] send answer", user_id_, remote_user_id_);
@@ -433,18 +427,78 @@ int IceTransmission::SendAnswer() {
return 0; return 0;
} }
// int IceTransmission::AppendLocalCapabilitiesToSdp() { int IceTransmission::AppendLocalCapabilitiesToSdp(std::string &remote_sdp) {
// std::string toReplace = "ICE/SDP"; std::string to_replace = "ICE/SDP";
// std::string replacement = "UDP/TLS/RTP/SAVPF 111 114 115 116 123 124 125"; std::string video_capabilities = "UDP/TLS/RTP/SAVPF 96 97 98 99";
std::string audio_capabilities = "UDP/TLS/RTP/SAVPF 111";
std::string data_capabilities = "UDP/TLS/RTP/SAVPF 127";
// size_t pos = 0; std::size_t video_start = remote_sdp.find("m=video");
// while ((pos = local_sdp_.find(toReplace, pos)) != std::string::npos) { std::size_t video_end = remote_sdp.find("\n", video_start);
// local_sdp_.replace(pos, toReplace.length(), replacement); std::size_t audio_start = remote_sdp.find("m=audio");
// pos += replacement.length(); std::size_t audio_end = remote_sdp.find("\n", audio_start);
// } std::size_t data_start = remote_sdp.find("m=data");
std::size_t data_end = remote_sdp.find("\n", data_start);
// return 0; 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(), video_capabilities);
pos += video_capabilities.length();
}
}
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(), audio_capabilities);
pos += audio_capabilities.length();
}
}
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(), data_capabilities);
pos += data_capabilities.length();
}
}
return 0;
}
std::string IceTransmission::GetLocalCapabilitiesToSdp(
const std::string &remote_sdp) {
std::string media_stream_sdp;
std::size_t video_start = remote_sdp.find("m=video");
std::size_t video_end = remote_sdp.find("m=audio");
std::size_t audio_start = video_end;
std::size_t audio_end = remote_sdp.find("m=data");
std::size_t data_start = audio_end;
std::size_t data_end = remote_sdp.find("a=candidate");
std::size_t candidate_start = data_end;
if ((video_start != std::string::npos && video_end != std::string::npos) ||
(audio_start != std::string::npos && audio_end != std::string::npos) ||
(data_start != std::string::npos && data_end != std::string::npos)) {
if (video_start != std::string::npos && video_end != std::string::npos) {
media_stream_sdp =
remote_sdp.substr(video_start, video_end - video_start);
} else if (audio_start != std::string::npos &&
audio_end != std::string::npos) {
media_stream_sdp =
remote_sdp.substr(audio_start, audio_end - audio_start);
} else {
media_stream_sdp = remote_sdp.substr(data_start, data_end - data_start);
}
if (candidate_start != std::string::npos) {
media_stream_sdp += remote_sdp.substr(candidate_start);
}
} else {
return remote_sdp;
}
return media_stream_sdp;
}
RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedVideoPayloadType( RtpPacket::PAYLOAD_TYPE IceTransmission::GetAceptedVideoPayloadType(
const std::string &remote_sdp) { const std::string &remote_sdp) {

View File

@@ -104,6 +104,9 @@ class IceTransmission {
int SendAnswer(); int SendAnswer();
private: private:
int AppendLocalCapabilitiesToSdp(std::string &remote_sdp);
std::string GetLocalCapabilitiesToSdp(const std::string &remote_sdp);
RtpPacket::PAYLOAD_TYPE GetAceptedVideoPayloadType( RtpPacket::PAYLOAD_TYPE GetAceptedVideoPayloadType(
const std::string &remote_sdp); const std::string &remote_sdp);
RtpPacket::PAYLOAD_TYPE GetAceptedAudioPayloadType( RtpPacket::PAYLOAD_TYPE GetAceptedAudioPayloadType(