Closed sha-long-ba-si closed 2 years ago
这个问题 我待会修复下
你打个补丁试试,如果测试通过了,麻烦提个pr
Index: webrtc/Sdp.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h
--- a/webrtc/Sdp.h (revision 8553502b7cb8dc7f1b3e55dbd6ad49121c6501a8)
+++ b/webrtc/Sdp.h (date 1654588253730)
@@ -720,7 +720,7 @@
void setDefaultSetting(std::string ice_ufrag, std::string ice_pwd, RtpDirection direction, const SdpAttrFingerprint &fingerprint);
void addCandidate(const SdpAttrCandidate &candidate, mediakit::TrackType type = mediakit::TrackInvalid);
- std::shared_ptr<RtcSession> createAnswer(const RtcSession &offer);
+ std::shared_ptr<RtcSession> createAnswer(const RtcSession &offer) const;
void setPlayRtspInfo(const std::string &sdp);
@@ -728,9 +728,9 @@
void enableREMB(bool enable = true, mediakit::TrackType type = mediakit::TrackInvalid);
private:
- void matchMedia(const std::shared_ptr<RtcSession> &ret, mediakit::TrackType type, const std::vector<RtcMedia> &medias, const RtcTrackConfigure &configure);
- bool onCheckCodecProfile(const RtcCodecPlan &plan, mediakit::CodecId codec);
- void onSelectPlan(RtcCodecPlan &plan, mediakit::CodecId codec);
+ void matchMedia(const std::shared_ptr<RtcSession> &ret, const RtcMedia &media) const;
+ bool onCheckCodecProfile(const RtcCodecPlan &plan, mediakit::CodecId codec) const;
+ void onSelectPlan(RtcCodecPlan &plan, mediakit::CodecId codec) const;
private:
RtcCodecPlan::Ptr _rtsp_video_plan;
Index: webrtc/Sdp.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp
--- a/webrtc/Sdp.cpp (revision 8553502b7cb8dc7f1b3e55dbd6ad49121c6501a8)
+++ b/webrtc/Sdp.cpp (date 1654588224206)
@@ -1521,15 +1521,17 @@
}
}
-shared_ptr<RtcSession> RtcConfigure::createAnswer(const RtcSession &offer){
+shared_ptr<RtcSession> RtcConfigure::createAnswer(const RtcSession &offer) const {
shared_ptr<RtcSession> ret = std::make_shared<RtcSession>();
ret->version = offer.version;
ret->origin = offer.origin;
ret->session_name = offer.session_name;
ret->msid_semantic = offer.msid_semantic;
- matchMedia(ret, TrackAudio, offer.media, audio);
- matchMedia(ret, TrackVideo, offer.media, video);
- matchMedia(ret, TrackApplication, offer.media, application);
+
+ for (auto &m : offer.media) {
+ matchMedia(ret, m);
+ }
+
//设置音视频端口复用
if (!offer.group.mids.empty()) {
for (auto &m : ret->media) {
@@ -1573,153 +1575,157 @@
}
}
-void RtcConfigure::matchMedia(const shared_ptr<RtcSession> &ret, TrackType type, const vector<RtcMedia> &medias, const RtcTrackConfigure &configure){
+void RtcConfigure::matchMedia(const std::shared_ptr<RtcSession> &ret,const RtcMedia &offer_media) const {
bool check_profile = true;
bool check_codec = true;
+ const RtcTrackConfigure *cfg_ptr = nullptr;
+
+ switch (offer_media.type) {
+ case TrackAudio: cfg_ptr = &audio; break;
+ case TrackVideo: cfg_ptr = &video; break;
+ case TrackApplication: cfg_ptr = &application; break;
+ default: return;
+ }
+ auto &configure = *cfg_ptr;
RETRY:
- for (auto &offer_media : medias) {
- if (offer_media.type != type) {
- continue;
- }
- if (type == TrackApplication) {
- RtcMedia answer_media = offer_media;
- answer_media.role = mathDtlsRole(offer_media.role);
+ if (offer_media.type == TrackApplication) {
+ RtcMedia answer_media = offer_media;
+ answer_media.role = mathDtlsRole(offer_media.role);
#ifdef ENABLE_SCTP
- answer_media.direction = matchDirection(offer_media.direction, configure.direction);
- answer_media.candidate = configure.candidate;
+ answer_media.direction = matchDirection(offer_media.direction, configure.direction);
+ answer_media.candidate = configure.candidate;
#else
- answer_media.direction = RtpDirection::inactive;
+ answer_media.direction = RtpDirection::inactive;
#endif
- ret->media.emplace_back(answer_media);
- return;
- }
- for (auto &codec : configure.preferred_codec) {
- if (offer_media.ice_lite && configure.ice_lite) {
- WarnL << "answer sdp配置为ice_lite模式,与offer sdp中的ice_lite模式冲突";
- continue;
- }
- const RtcCodecPlan *selected_plan = nullptr;
- for (auto &plan : offer_media.plan) {
- //先检查编码格式是否为偏好
- if (check_codec && getCodecId(plan.codec) != codec) {
- continue;
- }
- //命中偏好的编码格式,然后检查规格
- if (check_profile && !onCheckCodecProfile(plan, codec)) {
- continue;
- }
- //找到中意的codec
- selected_plan = &plan;
- break;
- }
- if (!selected_plan) {
- //offer中该媒体的所有的codec都不支持
- continue;
- }
- RtcMedia answer_media;
- answer_media.type = offer_media.type;
- answer_media.mid = offer_media.mid;
- answer_media.proto = offer_media.proto;
- answer_media.port = offer_media.port;
- answer_media.addr = offer_media.addr;
- answer_media.rtcp_addr = offer_media.rtcp_addr;
- answer_media.rtcp_mux = offer_media.rtcp_mux && configure.rtcp_mux;
- answer_media.rtcp_rsize = offer_media.rtcp_rsize && configure.rtcp_rsize;
- answer_media.ice_trickle = offer_media.ice_trickle && configure.ice_trickle;
- answer_media.ice_renomination = offer_media.ice_renomination && configure.ice_renomination;
- answer_media.ice_ufrag = configure.ice_ufrag;
- answer_media.ice_pwd = configure.ice_pwd;
- answer_media.fingerprint = configure.fingerprint;
- answer_media.ice_lite = configure.ice_lite;
- answer_media.candidate = configure.candidate;
- // copy simulicast setting
- answer_media.rtp_rids = offer_media.rtp_rids;
- answer_media.rtp_ssrc_sim = offer_media.rtp_ssrc_sim;
+ ret->media.emplace_back(answer_media);
+ return;
+ }
+ for (auto &codec : configure.preferred_codec) {
+ if (offer_media.ice_lite && configure.ice_lite) {
+ WarnL << "answer sdp配置为ice_lite模式,与offer sdp中的ice_lite模式冲突";
+ continue;
+ }
+ const RtcCodecPlan *selected_plan = nullptr;
+ for (auto &plan : offer_media.plan) {
+ //先检查编码格式是否为偏好
+ if (check_codec && getCodecId(plan.codec) != codec) {
+ continue;
+ }
+ //命中偏好的编码格式,然后检查规格
+ if (check_profile && !onCheckCodecProfile(plan, codec)) {
+ continue;
+ }
+ //找到中意的codec
+ selected_plan = &plan;
+ break;
+ }
+ if (!selected_plan) {
+ //offer中该媒体的所有的codec都不支持
+ continue;
+ }
+ RtcMedia answer_media;
+ answer_media.type = offer_media.type;
+ answer_media.mid = offer_media.mid;
+ answer_media.proto = offer_media.proto;
+ answer_media.port = offer_media.port;
+ answer_media.addr = offer_media.addr;
+ answer_media.rtcp_addr = offer_media.rtcp_addr;
+ answer_media.rtcp_mux = offer_media.rtcp_mux && configure.rtcp_mux;
+ answer_media.rtcp_rsize = offer_media.rtcp_rsize && configure.rtcp_rsize;
+ answer_media.ice_trickle = offer_media.ice_trickle && configure.ice_trickle;
+ answer_media.ice_renomination = offer_media.ice_renomination && configure.ice_renomination;
+ answer_media.ice_ufrag = configure.ice_ufrag;
+ answer_media.ice_pwd = configure.ice_pwd;
+ answer_media.fingerprint = configure.fingerprint;
+ answer_media.ice_lite = configure.ice_lite;
+ answer_media.candidate = configure.candidate;
+ // copy simulicast setting
+ answer_media.rtp_rids = offer_media.rtp_rids;
+ answer_media.rtp_ssrc_sim = offer_media.rtp_ssrc_sim;
- answer_media.role = mathDtlsRole(offer_media.role);
+ answer_media.role = mathDtlsRole(offer_media.role);
- //如果codec匹配失败,那么禁用该track
- answer_media.direction = check_codec ? matchDirection(offer_media.direction, configure.direction)
- : RtpDirection::inactive;
- if (answer_media.direction == RtpDirection::invalid) {
- continue;
- }
- if (answer_media.direction == RtpDirection::sendrecv) {
- //如果是收发双向,那么我们拷贝offer sdp的ssrc,确保ssrc一致
- answer_media.rtp_rtx_ssrc = offer_media.rtp_rtx_ssrc;
- }
+ //如果codec匹配失败,那么禁用该track
+ answer_media.direction = check_codec ? matchDirection(offer_media.direction, configure.direction)
+ : RtpDirection::inactive;
+ if (answer_media.direction == RtpDirection::invalid) {
+ continue;
+ }
+ if (answer_media.direction == RtpDirection::sendrecv) {
+ //如果是收发双向,那么我们拷贝offer sdp的ssrc,确保ssrc一致
+ answer_media.rtp_rtx_ssrc = offer_media.rtp_rtx_ssrc;
+ }
- //添加媒体plan
- answer_media.plan.emplace_back(*selected_plan);
- onSelectPlan(answer_media.plan.back(), codec);
+ //添加媒体plan
+ answer_media.plan.emplace_back(*selected_plan);
+ onSelectPlan(answer_media.plan.back(), codec);
- set<uint8_t> pt_selected = {selected_plan->pt};
+ set<uint8_t> pt_selected = {selected_plan->pt};
- //添加rtx,red,ulpfec plan
- if (configure.support_red || configure.support_rtx || configure.support_ulpfec) {
- for (auto &plan : offer_media.plan) {
- if (!strcasecmp(plan.codec.data(), "rtx")) {
- if (configure.support_rtx && atoi(plan.getFmtp("apt").data()) == selected_plan->pt) {
- answer_media.plan.emplace_back(plan);
- pt_selected.emplace(plan.pt);
- }
- continue;
- }
- if (!strcasecmp(plan.codec.data(), "red")) {
- if (configure.support_red) {
- answer_media.plan.emplace_back(plan);
- pt_selected.emplace(plan.pt);
- }
- continue;
- }
- if (!strcasecmp(plan.codec.data(), "ulpfec")) {
- if (configure.support_ulpfec) {
- answer_media.plan.emplace_back(plan);
- pt_selected.emplace(plan.pt);
- }
- continue;
- }
- }
- }
+ //添加rtx,red,ulpfec plan
+ if (configure.support_red || configure.support_rtx || configure.support_ulpfec) {
+ for (auto &plan : offer_media.plan) {
+ if (!strcasecmp(plan.codec.data(), "rtx")) {
+ if (configure.support_rtx && atoi(plan.getFmtp("apt").data()) == selected_plan->pt) {
+ answer_media.plan.emplace_back(plan);
+ pt_selected.emplace(plan.pt);
+ }
+ continue;
+ }
+ if (!strcasecmp(plan.codec.data(), "red")) {
+ if (configure.support_red) {
+ answer_media.plan.emplace_back(plan);
+ pt_selected.emplace(plan.pt);
+ }
+ continue;
+ }
+ if (!strcasecmp(plan.codec.data(), "ulpfec")) {
+ if (configure.support_ulpfec) {
+ answer_media.plan.emplace_back(plan);
+ pt_selected.emplace(plan.pt);
+ }
+ continue;
+ }
+ }
+ }
- //对方和我方都支持的扩展,那么我们才支持
- for (auto &ext : offer_media.extmap) {
- auto it = configure.extmap.find(RtpExt::getExtType(ext.ext));
- if (it != configure.extmap.end()) {
- auto new_dir = matchDirection(ext.direction, it->second);
- switch (new_dir) {
- case RtpDirection::invalid:
- case RtpDirection::inactive: continue;
- default: break;
- }
- answer_media.extmap.emplace_back(ext);
- answer_media.extmap.back().direction = new_dir;
- }
- }
+ //对方和我方都支持的扩展,那么我们才支持
+ for (auto &ext : offer_media.extmap) {
+ auto it = configure.extmap.find(RtpExt::getExtType(ext.ext));
+ if (it != configure.extmap.end()) {
+ auto new_dir = matchDirection(ext.direction, it->second);
+ switch (new_dir) {
+ case RtpDirection::invalid:
+ case RtpDirection::inactive: continue;
+ default: break;
+ }
+ answer_media.extmap.emplace_back(ext);
+ answer_media.extmap.back().direction = new_dir;
+ }
+ }
- auto &rtcp_fb_ref = answer_media.plan[0].rtcp_fb;
- rtcp_fb_ref.clear();
- //对方和我方都支持的rtcpfb,那么我们才支持
- for (auto &fp : selected_plan->rtcp_fb) {
- if (configure.rtcp_fb.find(fp) != configure.rtcp_fb.end()) {
- //对方该rtcp被我们支持
- rtcp_fb_ref.emplace(fp);
- }
- }
+ auto &rtcp_fb_ref = answer_media.plan[0].rtcp_fb;
+ rtcp_fb_ref.clear();
+ //对方和我方都支持的rtcpfb,那么我们才支持
+ for (auto &fp : selected_plan->rtcp_fb) {
+ if (configure.rtcp_fb.find(fp) != configure.rtcp_fb.end()) {
+ //对方该rtcp被我们支持
+ rtcp_fb_ref.emplace(fp);
+ }
+ }
#if 0
- //todo 此处为添加无效的plan,webrtc sdp通过调节plan pt顺序选择匹配的codec,意味着后面的codec其实放在sdp中是无意义的
- for (auto &plan : offer_media.plan) {
- if (pt_selected.find(plan.pt) == pt_selected.end()) {
- answer_media.plan.emplace_back(plan);
- }
- }
+ //todo 此处为添加无效的plan,webrtc sdp通过调节plan pt顺序选择匹配的codec,意味着后面的codec其实放在sdp中是无意义的
+ for (auto &plan : offer_media.plan) {
+ if (pt_selected.find(plan.pt) == pt_selected.end()) {
+ answer_media.plan.emplace_back(plan);
+ }
+ }
#endif
- ret->media.emplace_back(answer_media);
- return;
- }
+ ret->media.emplace_back(answer_media);
+ return;
}
if (check_profile) {
@@ -1765,7 +1771,7 @@
static const string kProfile{"profile-level-id"};
static const string kMode{"packetization-mode"};
-bool RtcConfigure::onCheckCodecProfile(const RtcCodecPlan &plan, CodecId codec){
+bool RtcConfigure::onCheckCodecProfile(const RtcCodecPlan &plan, CodecId codec) const {
if (_rtsp_audio_plan && codec == getCodecId(_rtsp_audio_plan->codec)) {
if (plan.sample_rate != _rtsp_audio_plan->sample_rate || plan.channel != _rtsp_audio_plan->channel) {
//音频采样率和通道数必须相同
@@ -1785,7 +1791,7 @@
return true;
}
-void RtcConfigure::onSelectPlan(RtcCodecPlan &plan, CodecId codec){
+void RtcConfigure::onSelectPlan(RtcCodecPlan &plan, CodecId codec) const {
if (_rtsp_video_plan && codec == CodecH264 && getCodecId(_rtsp_video_plan->codec) == CodecH264) {
//h264时,设置packetization-mod为一致
auto mode = _rtsp_video_plan->fmtp[kMode];
好的,我试试
现象描述
提交offer后,生成的answer的 m-lines次序不正确,导致setRemoteDescription失败 setRemoteDescription: onSetFailure == Failed to set remote answer sdp: The order of m-lines in answer doesn't match order in offer. Rejecting answer.
相关日志或截图
展开查看详细日志
offer: answer:各种环境信息
android系统,使用 org.webrtc:google-webrtc:1.0.32006