初步实现webrtc datachannel sdp握手

This commit is contained in:
xiongziliang 2022-04-03 17:12:23 +08:00
parent 03dfcbad36
commit 1ed793fe97
3 changed files with 54 additions and 44 deletions

View File

@ -372,9 +372,7 @@ void SdpMedia::parse(const string &str) {
port = atoi(vec[1].data());
proto = vec[2];
for (size_t i = 3; i < vec.size(); ++i) {
auto pt = atoi(vec[i].data());
CHECK_SDP(type == TrackApplication || pt <= 0xFF);
fmts.emplace_back(pt);
fmts.emplace_back(vec[i]);
}
}
@ -383,7 +381,7 @@ string SdpMedia::toString() const {
value = string(getTrackString(type)) + " " + to_string(port) + " " + proto;
for (auto fmt : fmts) {
value += ' ';
value += to_string(fmt);
value += fmt;
}
}
return SdpItem::toString();
@ -921,7 +919,9 @@ void RtcSession::loadFrom(const string &str) {
//添加失败,有多条
CHECK(fmtp_map.emplace(fmtp.pt, fmtp).second, "该pt存在多条a=fmtp:", (int)fmtp.pt);
}
for (auto &pt : mline.fmts) {
for (auto &item : mline.fmts) {
auto pt = atoi(item.c_str());
CHECK(pt < 0xFF, "invalid payload type: ", item);
//遍历所有编码方案的pt
rtc_media.plan.emplace_back();
auto &plan = rtc_media.plan.back();
@ -1078,10 +1078,10 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{
mline->port = m.port;
mline->proto = m.proto;
for (auto &p : m.plan) {
mline->fmts.emplace_back(p.pt);
mline->fmts.emplace_back(to_string(p.pt));
}
if (m.type == TrackApplication) {
mline->fmts.emplace_back(m.sctp_port);
mline->fmts.emplace_back("webrtc-datachannel");
}
sdp_media.items.emplace_back(std::move(mline));
sdp_media.items.emplace_back(std::make_shared<SdpConnection>(m.addr));
@ -1201,7 +1201,9 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{
}
} else {
if (!m.sctpmap.empty()) {
sdp_media.items.emplace_back(wrapSdpAttr(std::make_shared<SdpAttrSctpMap>(m.sctpmap)));
}
sdp_media.items.emplace_back(wrapSdpAttr(std::make_shared<SdpCommon>("sctp-port", to_string(m.sctp_port))));
}
@ -1567,6 +1569,15 @@ static RtpDirection matchDirection(RtpDirection offer_direction, RtpDirection su
}
}
static DtlsRole mathDtlsRole(DtlsRole role){
switch (role) {
case DtlsRole::actpass:
case DtlsRole::active: return DtlsRole::passive;
case DtlsRole::passive: return DtlsRole::active;
default: CHECK(0, "invalid role:", getDtlsRoleString(role)); return DtlsRole::passive;
}
}
void RtcConfigure::matchMedia(const shared_ptr<RtcSession> &ret, TrackType type, const vector<RtcMedia> &medias, const RtcTrackConfigure &configure){
bool check_profile = true;
bool check_codec = true;
@ -1577,6 +1588,14 @@ RETRY:
if (offer_media.type != type) {
continue;
}
if (type == TrackApplication) {
RtcMedia answer_media = offer_media;
answer_media.role = mathDtlsRole(offer_media.role);
answer_media.direction = matchDirection(offer_media.direction, configure.direction);
answer_media.candidate = configure.candidate;
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模式冲突";
@ -1617,18 +1636,7 @@ RETRY:
answer_media.ice_lite = configure.ice_lite;
answer_media.candidate = configure.candidate;
answer_media.rtp_rids = offer_media.rtp_rids;
switch (offer_media.role) {
case DtlsRole::actpass :
case DtlsRole::active : {
answer_media.role = DtlsRole::passive;
break;
}
case DtlsRole::passive : {
answer_media.role = DtlsRole::active;
break;
}
default: continue;
}
answer_media.role = mathDtlsRole(offer_media.role);
//如果codec匹配失败那么禁用该track
answer_media.direction = check_codec ? matchDirection(offer_media.direction, configure.direction)

View File

@ -196,7 +196,7 @@ public:
//RTP/AVPF: 应用场景为视频/音频的 RTP 协议,支持 RTCP-based Feedback。参考 RFC 4585
//RTP/SAVPF: 应用场景为视频/音频的 SRTP 协议,支持 RTCP-based Feedback。参考 RFC 5124
std::string proto;
std::vector<uint32_t> fmts;
std::vector<std::string> fmts;
void parse(const std::string &str) override;
std::string toString() const override;
@ -426,12 +426,13 @@ public:
//https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-05
//a=sctpmap:5000 webrtc-datachannel 1024
//a=sctpmap: sctpmap-number media-subtypes [streams]
uint16_t port;
uint16_t port = 0;
std::string subtypes;
uint32_t streams;
uint32_t streams = 0;
void parse(const std::string &str) override;
std::string toString() const override;
const char* getKey() const override { return "sctpmap";}
bool empty() const { return port == 0 && subtypes.empty() && streams == 0; }
};
class SdpAttrCandidate : public SdpItem {

View File

@ -368,6 +368,9 @@ bool WebRtcTransportImp::canRecvRtp() const{
void WebRtcTransportImp::onStartWebRTC() {
//获取ssrc和pt相关信息,届时收到rtp和rtcp时分别可以根据pt和ssrc找到相关的信息
for (auto &m_answer : _answer_sdp->media) {
if (m_answer.type == TrackApplication) {
continue;
}
auto m_offer = _offer_sdp->getMedia(m_answer.type);
auto track = std::make_shared<MediaTrack>();
@ -376,7 +379,7 @@ void WebRtcTransportImp::onStartWebRTC() {
track->answer_ssrc_rtx = m_answer.getRtxSSRC();
track->offer_ssrc_rtp = m_offer->getRtpSSRC();
track->offer_ssrc_rtx = m_offer->getRtxSSRC();
track->plan_rtp = &m_answer.plan[0];;
track->plan_rtp = &m_answer.plan[0];
track->plan_rtx = m_answer.getRelatedRtxPlan(track->plan_rtp->pt);
track->rtcp_context_send = std::make_shared<RtcpContextForSend>();
@ -399,7 +402,6 @@ void WebRtcTransportImp::onStartWebRTC() {
//rtx pt --> MediaTrack
_pt_to_track.emplace(track->plan_rtx->pt, std::unique_ptr<WrappedMediaTrack>(new WrappedRtxTrack(track)));
}
if (m_offer->type != TrackApplication) {
//记录rtp ext类型与id的关系方便接收或发送rtp时修改rtp ext id
track->rtp_ext_ctx = std::make_shared<RtpExtContext>(*m_offer);
weak_ptr<MediaTrack> weak_track = track;
@ -423,7 +425,6 @@ void WebRtcTransportImp::onStartWebRTC() {
}
}
}
}
void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
//修改answer sdp的ip、端口信息