mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 20:27:34 +08:00
完善ssrc相关处理
This commit is contained in:
parent
f6eb84b413
commit
d4ff84e447
@ -395,51 +395,45 @@ bool WebRtcTransportImp::canRecvRtp() const{
|
|||||||
return _push_src && (sdp.media[0].direction == RtpDirection::sendrecv || sdp.media[0].direction == RtpDirection::recvonly);
|
return _push_src && (sdp.media[0].direction == RtpDirection::sendrecv || sdp.media[0].direction == RtpDirection::recvonly);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RtcSession& WebRtcTransportImp::getSdpWithSSRC() const{
|
|
||||||
auto &offer = getSdp(SdpType::answer);
|
|
||||||
if (offer.haveSSRC()) {
|
|
||||||
return offer;
|
|
||||||
}
|
|
||||||
auto &answer = getSdp(SdpType::offer);
|
|
||||||
CHECK(answer.haveSSRC());
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebRtcTransportImp::onStartWebRTC() {
|
void WebRtcTransportImp::onStartWebRTC() {
|
||||||
//获取ssrc和pt相关信息,届时收到rtp和rtcp时分别可以根据pt和ssrc找到相关的信息
|
//获取ssrc和pt相关信息,届时收到rtp和rtcp时分别可以根据pt和ssrc找到相关的信息
|
||||||
for (auto &m_answer : getSdp(SdpType::answer).media) {
|
for (auto &m_answer : getSdp(SdpType::answer).media) {
|
||||||
auto m_with_ssrc = getSdpWithSSRC().getMedia(m_answer.type);
|
auto m_offer = getSdp(SdpType::offer).getMedia(m_answer.type);
|
||||||
for (auto &plan_answer : m_answer.plan) {
|
auto info = std::make_shared<RtpPayloadInfo>();
|
||||||
//获取offer端rtp的ssrc和pt相关信息
|
|
||||||
auto info = std::make_shared<RtpPayloadInfo>();
|
info->media = &m_answer;
|
||||||
_rtp_info_pt.emplace(plan_answer.pt, info);
|
info->answer_ssrc_rtp = m_answer.getRtpSSRC();
|
||||||
info->media = m_with_ssrc;
|
info->answer_ssrc_rtx = m_answer.getRtxSSRC();
|
||||||
info->is_common_rtp = getCodecId(plan_answer.codec) != CodecInvalid;
|
info->offer_ssrc_rtp = m_offer->getRtpSSRC();
|
||||||
if (info->is_common_rtp) {
|
info->offer_ssrc_rtx = m_offer->getRtxSSRC();
|
||||||
//rtp
|
info->plan_rtp = &m_answer.plan[0];;
|
||||||
_rtp_info_ssrc[info->media->rtp_rtx_ssrc[0].ssrc] = info;
|
info->plan_rtx = m_answer.getRelatedRtxPlan(info->plan_rtp->pt);
|
||||||
info->plan_rtp = &plan_answer;
|
info->rtcp_context_recv = std::make_shared<RtcpContext>(info->plan_rtp->sample_rate, true);
|
||||||
info->plan_rtx = m_answer.getRelatedRtxPlan(plan_answer.pt);
|
info->rtcp_context_send = std::make_shared<RtcpContext>(info->plan_rtp->sample_rate, false);
|
||||||
} else {
|
info->receiver = std::make_shared<RtpReceiverImp>([info, this](RtpPacket::Ptr rtp) mutable {
|
||||||
//rtx
|
onSortedRtp(*info, std::move(rtp));
|
||||||
if (info->media->rtp_rtx_ssrc.size() > 1) {
|
});
|
||||||
_rtp_info_ssrc[info->media->rtp_rtx_ssrc[1].ssrc] = info;
|
info->nack_ctx.setOnNack([info, this](const FCI_NACK &nack) mutable {
|
||||||
}
|
onSendNack(*info, nack);
|
||||||
info->plan_rtp = m_answer.getPlan(atoi(plan_answer.getFmtp("apt").data()));
|
});
|
||||||
info->plan_rtx = &plan_answer;
|
|
||||||
}
|
//send ssrc --> RtpPayloadInfo
|
||||||
info->rtcp_context_recv = std::make_shared<RtcpContext>(info->plan_rtp->sample_rate, true);
|
_rtp_info_ssrc[info->answer_ssrc_rtp] = std::make_pair(false, info);
|
||||||
info->rtcp_context_send = std::make_shared<RtcpContext>(info->plan_rtp->sample_rate, false);
|
_rtp_info_ssrc[info->answer_ssrc_rtx] = std::make_pair(true, info);
|
||||||
info->receiver = std::make_shared<RtpReceiverImp>([info, this](RtpPacket::Ptr rtp) mutable {
|
|
||||||
onSortedRtp(*info, std::move(rtp));
|
//recv ssrc --> RtpPayloadInfo
|
||||||
});
|
_rtp_info_ssrc[info->offer_ssrc_rtp] = std::make_pair(false, info);;
|
||||||
info->nack_ctx.setOnNack([info, this](const FCI_NACK &nack) mutable {
|
_rtp_info_ssrc[info->offer_ssrc_rtx] = std::make_pair(true, info);;
|
||||||
onNack(*info, nack);
|
|
||||||
});
|
//rtp pt --> RtpPayloadInfo
|
||||||
|
_rtp_info_pt.emplace(info->plan_rtp->pt, std::make_pair(false, info));
|
||||||
|
if (info->plan_rtx) {
|
||||||
|
//rtx pt --> RtpPayloadInfo
|
||||||
|
_rtp_info_pt.emplace(info->plan_rtx->pt, std::make_pair(true, info));
|
||||||
}
|
}
|
||||||
if (m_answer.type != TrackApplication) {
|
if (m_offer->type != TrackApplication) {
|
||||||
//记录rtp ext类型与id的关系,方便接收或发送rtp时修改rtp ext id
|
//记录rtp ext类型与id的关系,方便接收或发送rtp时修改rtp ext id
|
||||||
for (auto &ext : m_answer.extmap) {
|
for (auto &ext : m_offer->extmap) {
|
||||||
auto ext_type = RtpExt::getExtType(ext.ext);
|
auto ext_type = RtpExt::getExtType(ext.ext);
|
||||||
_rtp_ext_id_to_type.emplace(ext.id, ext_type);
|
_rtp_ext_id_to_type.emplace(ext.id, ext_type);
|
||||||
_rtp_ext_type_to_id.emplace(ext_type, ext.id);
|
_rtp_ext_type_to_id.emplace(ext_type, ext.id);
|
||||||
@ -475,7 +469,7 @@ void WebRtcTransportImp::onStartWebRTC() {
|
|||||||
auto it = _rtp_info_pt.find(m.plan[0].pt);
|
auto it = _rtp_info_pt.find(m.plan[0].pt);
|
||||||
CHECK(it != _rtp_info_pt.end());
|
CHECK(it != _rtp_info_pt.end());
|
||||||
//记录发送rtp时约定的信息,届时发送rtp时需要修改pt和ssrc
|
//记录发送rtp时约定的信息,届时发送rtp时需要修改pt和ssrc
|
||||||
_send_rtp_info[m.type] = it->second;
|
_send_rtp_info[m.type] = it->second.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,9 +587,13 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
RtcpSR *sr = (RtcpSR *) rtcp;
|
RtcpSR *sr = (RtcpSR *) rtcp;
|
||||||
auto it = _rtp_info_ssrc.find(sr->ssrc);
|
auto it = _rtp_info_ssrc.find(sr->ssrc);
|
||||||
if (it != _rtp_info_ssrc.end()) {
|
if (it != _rtp_info_ssrc.end()) {
|
||||||
it->second->rtcp_context_recv->onRtcp(sr);
|
auto rtx = it->second.first;
|
||||||
auto rr = it->second->rtcp_context_recv->createRtcpRR(sr->items.ssrc, sr->ssrc);
|
if (!rtx) {
|
||||||
sendRtcpPacket(rr->data(), rr->size(), true);
|
auto &info = it->second.second;
|
||||||
|
info->rtcp_context_recv->onRtcp(sr);
|
||||||
|
auto rr = info->rtcp_context_recv->createRtcpRR(info->answer_ssrc_rtp, info->offer_ssrc_rtp);
|
||||||
|
sendRtcpPacket(rr->data(), rr->size(), true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
WarnL << "未识别的sr rtcp包:" << rtcp->dumpString();
|
WarnL << "未识别的sr rtcp包:" << rtcp->dumpString();
|
||||||
}
|
}
|
||||||
@ -608,8 +606,12 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
for (auto item : rr->getItemList()) {
|
for (auto item : rr->getItemList()) {
|
||||||
auto it = _rtp_info_ssrc.find(item->ssrc);
|
auto it = _rtp_info_ssrc.find(item->ssrc);
|
||||||
if (it != _rtp_info_ssrc.end()) {
|
if (it != _rtp_info_ssrc.end()) {
|
||||||
auto sr = it->second->rtcp_context_send->createRtcpSR(item->ssrc);
|
auto rtx = it->second.first;
|
||||||
sendRtcpPacket(sr->data(), sr->size(), true);
|
if (!rtx) {
|
||||||
|
auto &info = it->second.second;
|
||||||
|
auto sr = info->rtcp_context_send->createRtcpSR(info->answer_ssrc_rtp);
|
||||||
|
sendRtcpPacket(sr->data(), sr->size(), true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
WarnL << "未识别的rr rtcp包:" << rtcp->dumpString();
|
WarnL << "未识别的rr rtcp包:" << rtcp->dumpString();
|
||||||
}
|
}
|
||||||
@ -625,10 +627,6 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
WarnL << "未识别的bye rtcp包:" << rtcp->dumpString();
|
WarnL << "未识别的bye rtcp包:" << rtcp->dumpString();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_rtp_info_pt.erase(it->second->plan_rtp->pt);
|
|
||||||
if (it->second->plan_rtx) {
|
|
||||||
_rtp_info_pt.erase(it->second->plan_rtx->pt);
|
|
||||||
}
|
|
||||||
_rtp_info_ssrc.erase(it);
|
_rtp_info_ssrc.erase(it);
|
||||||
}
|
}
|
||||||
onShutdown(SockException(Err_eof, "rtcp bye message received"));
|
onShutdown(SockException(Err_eof, "rtcp bye message received"));
|
||||||
@ -648,11 +646,15 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
WarnL << "未识别的 rtcp包:" << rtcp->dumpString();
|
WarnL << "未识别的 rtcp包:" << rtcp->dumpString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &fci = fb->getFci<FCI_NACK>();
|
auto rtx = it->second.first;
|
||||||
it->second->nack_list.for_each_nack(fci, [&](const RtpPacket::Ptr &rtp) {
|
if (!rtx) {
|
||||||
//rtp重传
|
auto &info = it->second.second;
|
||||||
onSendRtp(rtp, true, true);
|
auto &fci = fb->getFci<FCI_NACK>();
|
||||||
});
|
info->nack_list.for_each_nack(fci, [&](const RtpPacket::Ptr &rtp) {
|
||||||
|
//rtp重传
|
||||||
|
onSendRtp(rtp, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
@ -704,8 +706,8 @@ void WebRtcTransportImp::onRtp_l(const char *buf, size_t len, bool rtx) {
|
|||||||
WarnL;
|
WarnL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &info = it->second;
|
auto &info = it->second.second;
|
||||||
if (info->is_common_rtp) {
|
if (!it->second.first) {
|
||||||
//这是普通的rtp数据
|
//这是普通的rtp数据
|
||||||
auto seq = ntohs(rtp->seq);
|
auto seq = ntohs(rtp->seq);
|
||||||
#if 0
|
#if 0
|
||||||
@ -741,7 +743,7 @@ void WebRtcTransportImp::onRtp_l(const char *buf, size_t len, bool rtx) {
|
|||||||
auto origin_seq = payload[0] << 8 | payload[1];
|
auto origin_seq = payload[0] << 8 | payload[1];
|
||||||
InfoL << "received rtx rtp: " << origin_seq;
|
InfoL << "received rtx rtp: " << origin_seq;
|
||||||
rtp->seq = htons(origin_seq);
|
rtp->seq = htons(origin_seq);
|
||||||
rtp->ssrc = htonl(info->media->rtp_rtx_ssrc[0].ssrc);
|
rtp->ssrc = htonl(info->offer_ssrc_rtp);
|
||||||
rtp->pt = info->plan_rtp->pt;
|
rtp->pt = info->plan_rtp->pt;
|
||||||
memmove((uint8_t *) buf + 2, buf, payload - (uint8_t *) buf);
|
memmove((uint8_t *) buf + 2, buf, payload - (uint8_t *) buf);
|
||||||
buf += 2;
|
buf += 2;
|
||||||
@ -749,10 +751,10 @@ void WebRtcTransportImp::onRtp_l(const char *buf, size_t len, bool rtx) {
|
|||||||
onRtp_l(buf, len, true);
|
onRtp_l(buf, len, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcTransportImp::onNack(RtpPayloadInfo &info, const FCI_NACK &nack) {
|
void WebRtcTransportImp::onSendNack(RtpPayloadInfo &info, const FCI_NACK &nack) {
|
||||||
auto rtcp = RtcpFB::create(RTPFBType::RTCP_RTPFB_NACK, &nack, FCI_NACK::kSize);
|
auto rtcp = RtcpFB::create(RTPFBType::RTCP_RTPFB_NACK, &nack, FCI_NACK::kSize);
|
||||||
rtcp->ssrc = htons(0);
|
rtcp->ssrc = htons(info.answer_ssrc_rtp);
|
||||||
rtcp->ssrc_media = htonl(info.media->rtp_rtx_ssrc[0].ssrc);
|
rtcp->ssrc_media = htonl(info.offer_ssrc_rtp);
|
||||||
sendRtcpPacket((char *) rtcp.get(), rtcp->getSize(), true);
|
sendRtcpPacket((char *) rtcp.get(), rtcp->getSize(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,7 +792,7 @@ void WebRtcTransportImp::onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool r
|
|||||||
info->nack_list.push_back(rtp);
|
info->nack_list.push_back(rtp);
|
||||||
#if 0
|
#if 0
|
||||||
//此处模拟发送丢包
|
//此处模拟发送丢包
|
||||||
if(rtp->getSeq() % 100 == 0){
|
if (rtp->type == TrackVideo && rtp->getSeq() % 100 == 0) {
|
||||||
DebugL << "send dropped:" << rtp->getSeq();
|
DebugL << "send dropped:" << rtp->getSeq();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -811,13 +813,13 @@ void WebRtcTransportImp::onBeforeEncryptRtp(const char *buf, size_t &len, void *
|
|||||||
if (!pr->first || !pr->second->plan_rtx) {
|
if (!pr->first || !pr->second->plan_rtx) {
|
||||||
//普通的rtp,或者不支持rtx, 修改目标pt和ssrc
|
//普通的rtp,或者不支持rtx, 修改目标pt和ssrc
|
||||||
header->pt = pr->second->plan_rtp->pt;
|
header->pt = pr->second->plan_rtp->pt;
|
||||||
header->ssrc = htonl(pr->second->media->rtp_rtx_ssrc[0].ssrc);
|
header->ssrc = htonl(pr->second->answer_ssrc_rtp);
|
||||||
} else {
|
} else {
|
||||||
//重传的rtp, rtx
|
//重传的rtp, rtx
|
||||||
header->pt = pr->second->plan_rtx->pt;
|
header->pt = pr->second->plan_rtx->pt;
|
||||||
if (pr->second->media->rtp_rtx_ssrc.size() > 1) {
|
if (pr->second->answer_ssrc_rtx) {
|
||||||
//有rtx单独的ssrc
|
//有rtx单独的ssrc,有些情况下,浏览器支持rtx,但是未指定rtx单独的ssrc
|
||||||
header->ssrc = htonl(pr->second->media->rtp_rtx_ssrc[1].ssrc);
|
header->ssrc = htonl(pr->second->answer_ssrc_rtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto origin_seq = ntohs(header->seq);
|
auto origin_seq = ntohs(header->seq);
|
||||||
|
@ -338,25 +338,26 @@ private:
|
|||||||
SdpAttrCandidate::Ptr getIceCandidate() const;
|
SdpAttrCandidate::Ptr getIceCandidate() const;
|
||||||
bool canSendRtp() const;
|
bool canSendRtp() const;
|
||||||
bool canRecvRtp() const;
|
bool canRecvRtp() const;
|
||||||
const RtcSession& getSdpWithSSRC() const;
|
|
||||||
|
|
||||||
class RtpPayloadInfo {
|
class RtpPayloadInfo {
|
||||||
public:
|
public:
|
||||||
using Ptr = std::shared_ptr<RtpPayloadInfo>;
|
using Ptr = std::shared_ptr<RtpPayloadInfo>;
|
||||||
|
|
||||||
bool is_common_rtp;
|
|
||||||
const RtcCodecPlan *plan_rtp;
|
const RtcCodecPlan *plan_rtp;
|
||||||
const RtcCodecPlan *plan_rtx;
|
const RtcCodecPlan *plan_rtx;
|
||||||
|
uint32_t offer_ssrc_rtp = 0;
|
||||||
|
uint32_t offer_ssrc_rtx = 0;
|
||||||
|
uint32_t answer_ssrc_rtp = 0;
|
||||||
|
uint32_t answer_ssrc_rtx = 0;
|
||||||
const RtcMedia *media;
|
const RtcMedia *media;
|
||||||
std::shared_ptr<RtpReceiverImp> receiver;
|
|
||||||
RtcpContext::Ptr rtcp_context_recv;
|
|
||||||
RtcpContext::Ptr rtcp_context_send;
|
|
||||||
NackList nack_list;
|
NackList nack_list;
|
||||||
NackContext nack_ctx;
|
NackContext nack_ctx;
|
||||||
|
RtcpContext::Ptr rtcp_context_recv;
|
||||||
|
RtcpContext::Ptr rtcp_context_send;
|
||||||
|
std::shared_ptr<RtpReceiverImp> receiver;
|
||||||
};
|
};
|
||||||
|
|
||||||
void onSortedRtp(RtpPayloadInfo &info, RtpPacket::Ptr rtp);
|
void onSortedRtp(RtpPayloadInfo &info, RtpPacket::Ptr rtp);
|
||||||
void onNack(RtpPayloadInfo &info, const FCI_NACK &nack);
|
void onSendNack(RtpPayloadInfo &info, const FCI_NACK &nack);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//用掉的总流量
|
//用掉的总流量
|
||||||
@ -371,8 +372,6 @@ private:
|
|||||||
Ticker _alive_ticker;
|
Ticker _alive_ticker;
|
||||||
//pli rtcp计时器
|
//pli rtcp计时器
|
||||||
Ticker _pli_ticker;
|
Ticker _pli_ticker;
|
||||||
//记录协商的发送rtp的pt和ssrc
|
|
||||||
RtpPayloadInfo::Ptr _send_rtp_info[2];
|
|
||||||
//复合udp端口,接收一切rtp与rtcp
|
//复合udp端口,接收一切rtp与rtcp
|
||||||
Socket::Ptr _socket;
|
Socket::Ptr _socket;
|
||||||
//推流的rtsp源
|
//推流的rtsp源
|
||||||
@ -381,30 +380,14 @@ private:
|
|||||||
RtspMediaSource::Ptr _play_src;
|
RtspMediaSource::Ptr _play_src;
|
||||||
//播放rtsp源的reader对象
|
//播放rtsp源的reader对象
|
||||||
RtspMediaSource::RingType::RingReader::Ptr _reader;
|
RtspMediaSource::RingType::RingReader::Ptr _reader;
|
||||||
//根据rtp的pt获取相关信息
|
//根据发送rtp的track类型获取相关信息
|
||||||
unordered_map<uint8_t/*pt*/, RtpPayloadInfo::Ptr> _rtp_info_pt;
|
RtpPayloadInfo::Ptr _send_rtp_info[2];
|
||||||
|
//根据接收rtp的pt获取相关信息
|
||||||
|
unordered_map<uint8_t/*pt*/, std::pair<bool/*is rtx*/,RtpPayloadInfo::Ptr> > _rtp_info_pt;
|
||||||
//根据rtcp的ssrc获取相关信息
|
//根据rtcp的ssrc获取相关信息
|
||||||
unordered_map<uint32_t/*ssrc*/, RtpPayloadInfo::Ptr> _rtp_info_ssrc;
|
unordered_map<uint32_t/*ssrc*/, std::pair<bool/*is rtx*/,RtpPayloadInfo::Ptr> > _rtp_info_ssrc;
|
||||||
//发送rtp时需要修改rtp ext id
|
//发送rtp时需要修改rtp ext id
|
||||||
map<RtpExtType, uint8_t> _rtp_ext_type_to_id;
|
map<RtpExtType, uint8_t> _rtp_ext_type_to_id;
|
||||||
//接收rtp时需要修改rtp ext id
|
//接收rtp时需要修改rtp ext id
|
||||||
unordered_map<uint8_t, RtpExtType> _rtp_ext_id_to_type;
|
unordered_map<uint8_t, RtpExtType> _rtp_ext_id_to_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user