diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp index c5b1f174..4ce1c489 100644 --- a/webrtc/Sdp.cpp +++ b/webrtc/Sdp.cpp @@ -1521,15 +1521,17 @@ void RtcConfigure::enableREMB(bool enable, TrackType type){ } } -shared_ptr RtcConfigure::createAnswer(const RtcSession &offer){ +shared_ptr RtcConfigure::createAnswer(const RtcSession &offer) const { shared_ptr ret = std::make_shared(); 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 @@ static DtlsRole mathDtlsRole(DtlsRole role){ } } -void RtcConfigure::matchMedia(const shared_ptr &ret, TrackType type, const vector &medias, const RtcTrackConfigure &configure){ +void RtcConfigure::matchMedia(const std::shared_ptr &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) { + 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; +#else + 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; } - if (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; -#else - answer_media.direction = RtpDirection::inactive; -#endif - ret->media.emplace_back(answer_media); - return; + 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; } - 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; + 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); + + //如果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); + + set 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 (check_codec && getCodecId(plan.codec) != codec) { + 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 (check_profile && !onCheckCodecProfile(plan, codec)) { + if (!strcasecmp(plan.codec.data(), "red")) { + if (configure.support_red) { + answer_media.plan.emplace_back(plan); + pt_selected.emplace(plan.pt); + } 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); - - //如果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); - - set 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; + 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; } +#endif + ret->media.emplace_back(answer_media); + return; } if (check_profile) { @@ -1765,7 +1771,7 @@ void RtcConfigure::setPlayRtspInfo(const string &sdp){ 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 @@ bool RtcConfigure::onCheckCodecProfile(const RtcCodecPlan &plan, CodecId codec){ 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]; diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h index 90746260..df6ae557 100644 --- a/webrtc/Sdp.h +++ b/webrtc/Sdp.h @@ -720,7 +720,7 @@ public: 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 createAnswer(const RtcSession &offer); + std::shared_ptr createAnswer(const RtcSession &offer) const; void setPlayRtspInfo(const std::string &sdp); @@ -728,9 +728,9 @@ public: void enableREMB(bool enable = true, mediakit::TrackType type = mediakit::TrackInvalid); private: - void matchMedia(const std::shared_ptr &ret, mediakit::TrackType type, const std::vector &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 &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;