Commit 5c6560f5 by xiongziliang

重写rtcp框架

parent 629c3968
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_MACROS_H
#define ZLMEDIAKIT_MACROS_H
#if defined(__MACH__)
#include <arpa/inet.h>
#include <machine/endian.h>
#define __BYTE_ORDER BYTE_ORDER
#define __BIG_ENDIAN BIG_ENDIAN
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#elif defined(__linux__)
#include <endian.h>
#include <arpa/inet.h>
#elif defined(_WIN32)
#define BIG_ENDIAN 1
#define LITTLE_ENDIAN 0
#define BYTE_ORDER LITTLE_ENDIAN
#define __BYTE_ORDER BYTE_ORDER
#define __BIG_ENDIAN BIG_ENDIAN
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#endif
#ifndef PACKED
#if !defined(_WIN32)
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif //!defined(_WIN32)
#endif
#endif //ZLMEDIAKIT_MACROS_H
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "RtcpContext.h"
using namespace toolkit;
namespace mediakit {
void RtcpContext::clear(){
memset(this, 0, sizeof(RtcpContext));
}
RtcpContext::RtcpContext(uint32_t sample_rate){
_sample_rate = sample_rate;
}
void RtcpContext::onRtp(uint16_t seq, uint32_t stamp, size_t bytes) {
_bytes += bytes;
++_packets;
auto sys_stamp = getCurrentMillisecond();
if (_last_rtp_sys_stamp) {
//计算时间戳抖动值
double diff = double(int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp) - int64_t(stamp) + int64_t(_last_rtp_stamp));
if (diff < 0) {
diff = -diff;
}
//抖动单位为采样次数
diff *= (_sample_rate / 1000.0);
_jitter += (diff - _jitter) / 16.0;
} else {
_jitter = 0;
}
if (_last_rtp_seq > 0xFF00 && seq < 0xFF && (!_seq_cycles || _packets - _last_cycle_packets > 0x1FFF)) {
//上次seq大于0xFF00且本次seq小于0xFF,
//且未发生回环或者距离上次回环间隔超过0x1FFF个包,则认为回环
++_seq_cycles;
_last_cycle_packets = _packets;
_seq_max = seq;
} else if (seq > _seq_max) {
//本次回环前最大seq
_seq_max = seq;
}
if (!_seq_base) {
//记录第一个rtp的seq
_seq_base = seq;
} else if (!_seq_cycles && seq < _seq_base) {
//未发生回环,那么取最新的seq为基准seq
_seq_base = seq;
}
_last_rtp_stamp = stamp;
_last_rtp_sys_stamp = sys_stamp;
_last_rtp_seq = seq;
}
void RtcpContext::onRtcp(RtcpHeader *rtcp){
if ((RtcpType) rtcp->pt != RtcpType::RTCP_SR) {
return;
}
auto rtcp_sr = (RtcpSR *)(rtcp);
/**
last SR timestamp (LSR): 32 bits
The middle 32 bits out of 64 in the NTP timestamp (as explained in
Section 4) received as part of the most recent RTCP sender report
(SR) packet from source SSRC_n. If no SR has been received yet,
the field is set to zero.
*/
_last_sr_lsr = ((rtcp_sr->ntpmsw & 0xFFFF) << 16) | ((rtcp_sr->ntplsw >> 16) & 0xFFFF);
_last_sr_ntp_sys = getCurrentMillisecond();
}
size_t RtcpContext::getExpectedPackets() const{
return (_seq_cycles << 16) + _seq_max - _seq_base + 1;
}
size_t RtcpContext::getExpectedPacketsInterval(){
auto expected = getExpectedPackets();
auto ret = expected - _last_expected;
_last_expected = expected;
return ret;
}
size_t RtcpContext::getLost(){
return getExpectedPackets() - _packets;
}
size_t RtcpContext::geLostInterval(){
auto lost = getLost();
auto ret = lost - _last_lost;
_last_lost = lost;
return ret;
}
Buffer::Ptr RtcpContext::createRtcpSR(uint32_t rtcp_ssrc){
auto rtcp = RtcpSR::create(0);
rtcp->ssrc = htonl(rtcp_ssrc);
struct timeval tv;
gettimeofday(&tv, NULL);
rtcp->setNtpStamp(tv);
//转换成rtp时间戳
rtcp->rtpts = htonl(uint32_t(_last_rtp_stamp * (_sample_rate / 1000.0)));
rtcp->packet_count = htonl((uint32_t)_packets);
rtcp->octet_count = htonl((uint32_t)_bytes);
return RtcpHeader::toBuffer(std::move(rtcp));
}
Buffer::Ptr RtcpContext::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc){
auto rtcp = RtcpRR::create(1);
rtcp->ssrc = htonl(rtcp_ssrc);
ReportItem *item = (ReportItem *) &rtcp->items;
item->ssrc = htonl(rtp_ssrc);
uint8_t fraction = 0;
auto expected_interval = getExpectedPacketsInterval();
if (expected_interval) {
fraction = uint8_t(geLostInterval() << 8 / expected_interval);
}
item->fraction = fraction;
item->cumulative = htonl(uint32_t(getLost())) >> 8;
item->seq_cycles = htons(_seq_cycles);
item->seq_max = htons(_seq_max);
item->jitter = htonl(uint32_t(_jitter));
item->last_sr_stamp = htonl(_last_sr_lsr);
// now - Last SR time,单位毫秒
auto delay = getCurrentMillisecond() - _last_sr_ntp_sys;
// in units of 1/65536 seconds
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
item->delay_since_last_sr = htonl(_last_sr_lsr ? dlsr : 0);
return RtcpHeader::toBuffer(rtcp);
}
}//namespace mediakit
\ No newline at end of file
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_RTCPCONTEXT_H
#define ZLMEDIAKIT_RTCPCONTEXT_H
#include <stdint.h>
#include <stddef.h>
#include "Rtcp.h"
namespace mediakit {
class RtcpContext {
public:
using Ptr = std::shared_ptr<RtcpContext>;
/**
* 创建rtcp上下文
* @param sample_rate 音频采用率,视频一般为90000
*/
RtcpContext(uint32_t sample_rate);
/**
* 输出或输入rtp时调用
* @param seq rtp的seq
* @param stamp rtp的时间戳,单位毫秒
* @param bytes rtp数据长度
*/
void onRtp(uint16_t seq, uint32_t stamp, size_t bytes);
/**
* 输入sr rtcp包
* @param rtcp 输入一个rtcp
*/
void onRtcp(RtcpHeader *rtcp);
/**
* 计算总丢包数
*/
size_t getLost();
/**
* 返回理应收到的rtp数
*/
size_t getExpectedPackets() const;
/**
* 创建SR rtcp包
* @param rtcp_ssrc rtcp的ssrc
* @return rtcp包
*/
Buffer::Ptr createRtcpSR(uint32_t rtcp_ssrc);
/**
* 创建RR rtcp包
* @param rtcp_ssrc rtcp的ssrc
* @param rtp_ssrc rtp的ssrc
* @return rtcp包
*/
Buffer::Ptr createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc);
/**
* 清空状态
*/
void clear();
private:
/**
* 上次结果与本次结果间应收包数
*/
size_t getExpectedPacketsInterval();
/**
* 上次结果与本次结果间丢包个数
*/
size_t geLostInterval();
private:
//时间戳抖动值
double _jitter = 0;
//视频默认90000,音频为采样率
uint32_t _sample_rate;
//收到或发送的rtp的字节数
size_t _bytes = 0;
//收到或发送的rtp的个数
size_t _packets = 0;
//第一个seq的值
uint16_t _seq_base = 0;
//rtp最大seq
uint16_t _seq_max = 0;
//rtp回环次数
uint16_t _seq_cycles = 0;
//上次回环发生时,记录的rtp包数
size_t _last_cycle_packets = 0;
//上次的seq
uint16_t _last_rtp_seq = 0;
//上次的rtp时间戳,毫秒
uint32_t _last_rtp_stamp = 0;
//上次的rtp的系统时间戳(毫秒)用于统计抖动
uint64_t _last_rtp_sys_stamp = 0;
//上次统计的丢包总数
size_t _last_lost = 0;
//上次统计应收rtp包总数
size_t _last_expected = 0;
//上次收到sr包时计算出的Last SR timestamp
uint32_t _last_sr_lsr = 0;
//上次收到sr时的系统时间戳,单位毫秒
uint64_t _last_sr_ntp_sys = 0;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_RTCPCONTEXT_H
......@@ -30,7 +30,7 @@ RtpReceiver::RtpReceiver() {
}
RtpReceiver::~RtpReceiver() {}
bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate, unsigned char *rtp_raw_ptr, size_t rtp_raw_len) {
bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate, uint8_t *rtp_raw_ptr, size_t rtp_raw_len) {
if (rtp_raw_len < 12) {
WarnL << "rtp包太小:" << rtp_raw_len;
return false;
......@@ -136,6 +136,7 @@ bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate,
memcpy(payload_ptr + 4, rtp_raw_ptr, rtp_raw_len);
//排序rtp
auto seq = rtp_ptr->sequence;
onBeforeRtpSorted(rtp_ptr, track_index);
_rtp_sortor[track_index].sortPacket(seq, std::move(rtp_ptr));
return true;
}
......
......@@ -175,7 +175,7 @@ protected:
* @param rtp_raw_len rtp数据指针长度
* @return 解析成功返回true
*/
bool handleOneRtp(int track_index, TrackType type, int samplerate, unsigned char *rtp_raw_ptr, size_t rtp_raw_len);
bool handleOneRtp(int track_index, TrackType type, int samplerate, uint8_t *rtp_raw_ptr, size_t rtp_raw_len);
/**
* rtp数据包排序后输出
......@@ -184,6 +184,13 @@ protected:
*/
virtual void onRtpSorted(const RtpPacket::Ptr &rtp, int track_index) {}
/**
* 解析出rtp但还未排序
* @param rtp rtp数据包
* @param track_index track索引
*/
virtual void onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index) {}
void clear();
void setPoolSize(size_t size);
size_t getJitterSize(int track_index) const;
......
......@@ -414,4 +414,15 @@ string printSSRC(uint32_t ui32Ssrc) {
return tmp;
}
Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved){
auto rtp_tcp = std::make_shared<BufferRaw>(4);
auto ptr = rtp_tcp->data();
ptr[0] = '$';
ptr[1] = interleaved;
ptr[2] = (size >> 8) & 0xFF;
ptr[3] = size & 0xFF;
rtp_tcp->setSize(4);
return rtp_tcp;
}
}//namespace mediakit
\ No newline at end of file
......@@ -82,6 +82,8 @@ public:
size_t offset;
};
Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved);
class RtpPayload{
public:
static int getClockRate(int pt);
......
......@@ -25,6 +25,7 @@
#include "RtspSplitter.h"
#include "RtpReceiver.h"
#include "Common/Stamp.h"
#include "Rtcp/RtcpContext.h"
using namespace std;
using namespace toolkit;
......@@ -72,13 +73,20 @@ protected:
void onRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) override;
/**
* 解析出rtp但还未排序
* @param rtp rtp数据包
* @param track_index track索引
*/
void onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index) override;
/**
* 收到RTCP包回调
* @param track_idx track索引
* @param track sdp相关信息
* @param data rtcp内容
* @param len rtcp内容长度
*/
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, unsigned char *data, size_t len);
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, uint8_t *data, size_t len);
/////////////TcpClient override/////////////
void onConnect(const SockException &err) override;
......@@ -86,7 +94,6 @@ protected:
void onErr(const SockException &ex) override;
private:
void onRecvRTP_l(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track);
void onPlayResult_l(const SockException &ex , bool handshake_done);
int getTrackIndexByInterleaved(int interleaved) const;
......@@ -106,14 +113,13 @@ private:
void sendKeepAlive();
void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap());
void sendRtspRequest(const string &cmd, const string &url ,const std::initializer_list<string> &header);
void sendReceiverReport(bool over_tcp, int track_idx);
void createUdpSockIfNecessary(int track_idx);
private:
//是否为性能测试模式
bool _benchmark_mode = false;
//轮流发送rtcp与GET_PARAMETER保活
bool _send_rtcp = true;
bool _send_rtcp[2] = {true, true};
string _play_url;
vector<SdpTrack::Ptr> _sdp_track;
......@@ -132,10 +138,6 @@ private:
string _content_base;
Rtsp::eRtpType _rtp_type = Rtsp::RTP_TCP;
/* 丢包率统计需要用到的参数 */
uint16_t _rtp_seq_start[2] = {0, 0};
uint16_t _rtp_seq_now[2] = {0, 0};
uint64_t _rtp_recv_count[2] = {0, 0};
//当前rtp时间戳
uint32_t _stamp[2] = {0, 0};
......@@ -143,14 +145,13 @@ private:
Ticker _rtp_recv_ticker;
std::shared_ptr<Timer> _play_check_timer;
std::shared_ptr<Timer> _rtp_check_timer;
//rtcp统计,trackid idx 为数组下标
RtcpCounter _rtcp_counter[2];
//rtcp发送时间,trackid idx 为数组下标
Ticker _rtcp_send_ticker[2];
//服务器支持的命令
set<string> _supported_cmd;
////////// rtcp ////////////////
//rtcp发送时间,trackid idx 为数组下标
Ticker _rtcp_send_ticker[2];
//统计rtp并发送rtcp
vector<RtcpContext::Ptr> _rtcp_context;
};
} /* namespace mediakit */
......
......@@ -38,7 +38,8 @@ void RtspPusher::sendTeardown(){
void RtspPusher::teardown() {
sendTeardown();
reset();
CLEAR_ARR(_udp_socks);
CLEAR_ARR(_rtp_sock);
CLEAR_ARR(_rtcp_sock);
_nonce.clear();
_realm.clear();
_track_vec.clear();
......@@ -148,6 +149,22 @@ void RtspPusher::onWholeRtspPacket(Parser &parser) {
parser.Clear();
}
void RtspPusher::onRtpPacket(const char *data, size_t len) {
int trackIdx = -1;
uint8_t interleaved = data[1];
if (interleaved % 2 != 0) {
trackIdx = getTrackIndexByInterleaved(interleaved - 1);
onRtcpPacket(trackIdx, _track_vec[trackIdx], (uint8_t *) data + 4, len - 4);
}
}
void RtspPusher::onRtcpPacket(int track_idx, SdpTrack::Ptr &track, uint8_t *data, size_t len){
auto rtcp_arr = RtcpHeader::loadFromBytes((char *) data, len);
for (auto &rtcp : rtcp_arr) {
_rtcp_context[track_idx]->onRtcp(rtcp);
}
}
void RtspPusher::sendAnnounce() {
auto src = _push_src.lock();
if (!src) {
......@@ -156,11 +173,12 @@ void RtspPusher::sendAnnounce() {
//解析sdp
_sdp_parser.load(src->getSdp());
_track_vec = _sdp_parser.getAvailableTrack();
if (_track_vec.empty()) {
throw std::runtime_error("无有效的Sdp Track");
}
for (auto &track : _track_vec) {
_rtcp_context.emplace_back(std::make_shared<RtcpContext>(track->_samplerate));
}
_on_res_func = std::bind(&RtspPusher::handleResAnnounce, this, placeholders::_1);
sendRtspRequest("ANNOUNCE", _url, {}, src->getSdp());
}
......@@ -229,14 +247,13 @@ bool RtspPusher::handleAuthenticationFailure(const string &params_str) {
//有必要的情况下创建udp端口
void RtspPusher::createUdpSockIfNecessary(int track_idx){
auto &rtp_sock = _udp_socks[track_idx];
if (!rtp_sock) {
rtp_sock = createSocket();
//rtp随机端口
if (!rtp_sock->bindUdpSock(0, get_local_ip().data())) {
rtp_sock.reset();
throw std::runtime_error("open rtp sock failed");
}
auto &rtpSockRef = _rtp_sock[track_idx];
auto &rtcpSockRef = _rtcp_sock[track_idx];
if (!rtpSockRef || !rtcpSockRef) {
std::pair<Socket::Ptr, Socket::Ptr> pr = std::make_pair(createSocket(), createSocket());
makeSockPair(pr, get_local_ip());
rtpSockRef = pr.first;
rtcpSockRef = pr.second;
}
}
......@@ -256,7 +273,7 @@ void RtspPusher::sendSetup(unsigned int track_idx) {
break;
case Rtsp::RTP_UDP: {
createUdpSockIfNecessary(track_idx);
int port = _udp_socks[track_idx]->get_local_port();
int port = _rtp_sock[track_idx]->get_local_port();
sendRtspRequest("SETUP", base_url,
{"Transport", StrPrinter << "RTP/AVP;unicast;client_port=" << port << "-" << port + 1});
}
......@@ -266,7 +283,6 @@ void RtspPusher::sendSetup(unsigned int track_idx) {
}
}
void RtspPusher::handleResSetup(const Parser &parser, unsigned int track_idx) {
if (parser.Url() != "200") {
throw std::runtime_error(StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
......@@ -289,12 +305,40 @@ void RtspPusher::handleResSetup(const Parser &parser, unsigned int track_idx) {
createUdpSockIfNecessary(track_idx);
const char *strPos = "server_port=";
auto port_str = FindField((transport + ";").data(), strPos, ";");
uint16_t port = atoi(FindField(port_str.data(), NULL, "-").data());
uint16_t rtp_port = atoi(FindField(port_str.data(), NULL, "-").data());
uint16_t rtcp_port = atoi(FindField(port_str.data(), "-", NULL).data());
auto &rtp_sock = _rtp_sock[track_idx];
auto &rtcp_sock = _rtcp_sock[track_idx];
struct sockaddr_in rtpto;
rtpto.sin_port = ntohs(port);
//设置rtp发送目标,为后续发送rtp做准备
rtpto.sin_port = ntohs(rtp_port);
rtpto.sin_family = AF_INET;
rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
rtp_sock->setSendPeerAddr((struct sockaddr *) &(rtpto));
//设置rtcp发送目标,为后续发送rtcp做准备
rtpto.sin_port = ntohs(rtcp_port);
rtpto.sin_family = AF_INET;
rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
_udp_socks[track_idx]->setSendPeerAddr((struct sockaddr *) &(rtpto));
rtcp_sock->setSendPeerAddr((struct sockaddr *)&(rtpto));
auto srcIP = inet_addr(get_peer_ip().data());
weak_ptr<RtspPusher> weakSelf = dynamic_pointer_cast<RtspPusher>(shared_from_this());
if(rtcp_sock) {
//设置rtcp over udp接收回调处理函数
rtcp_sock->setOnRead([srcIP, track_idx, weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr , int addr_len) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
return;
}
if (((struct sockaddr_in *) addr)->sin_addr.s_addr != srcIP) {
WarnL << "收到其他地址的rtcp数据:" << SockUtil::inet_ntoa(((struct sockaddr_in *) addr)->sin_addr);
return;
}
strongSelf->onRtcpPacket(track_idx, strongSelf->_track_vec[track_idx], (uint8_t *) buf->data(), buf->size());
});
}
}
RtspSplitter::enableRecvRtp(_rtp_type == Rtsp::RTP_TCP);
......@@ -313,13 +357,42 @@ void RtspPusher::sendOptions() {
sendRtspRequest("OPTIONS", _content_base);
}
inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
void RtspPusher::updateRtcpContext(const RtpPacket::Ptr &rtp){
int track_index = getTrackIndexByTrackType(rtp->type);
auto &ticker = _rtcp_send_ticker[track_index];
auto &rtcp_ctx = _rtcp_context[track_index];
rtcp_ctx->onRtp(rtp->sequence, rtp->timeStamp, rtp->size() - 4);
//send rtcp every 5 second
if (ticker.elapsedTime() > 5 * 1000) {
ticker.resetTime();
static auto send_rtcp = [](RtspPusher *thiz, int index, Buffer::Ptr ptr) {
if (thiz->_rtp_type == Rtsp::RTP_TCP) {
auto &track = thiz->_track_vec[index];
thiz->send(makeRtpOverTcpPrefix((uint16_t) (ptr->size()), track->_interleaved + 1));
thiz->send(std::move(ptr));
} else {
thiz->_rtcp_sock[index]->send(std::move(ptr));
}
};
auto rtcp = rtcp_ctx->createRtcpSR(rtp->ssrc + 1);
auto rtcp_sdes = RtcpSdes::create({SERVER_NAME});
rtcp_sdes->items.type = (uint8_t) SdesType::RTCP_SDES_CNAME;
rtcp_sdes->items.ssrc = htonl(rtp->ssrc);
send_rtcp(this, track_index, std::move(rtcp));
send_rtcp(this, track_index, RtcpHeader::toBuffer(rtcp_sdes));
}
}
void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
switch (_rtp_type) {
case Rtsp::RTP_TCP: {
size_t i = 0;
auto size = pkt->size();
setSendFlushFlag(false);
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
updateRtcpContext(rtp);
if (++i == size) {
setSendFlushFlag(true);
}
......@@ -333,8 +406,9 @@ inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt)
size_t i = 0;
auto size = pkt->size();
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
updateRtcpContext(rtp);
int iTrackIndex = getTrackIndexByTrackType(rtp->type);
auto &pSock = _udp_socks[iTrackIndex];
auto &pSock = _rtp_sock[iTrackIndex];
if (!pSock) {
shutdown(SockException(Err_shutdown, "udp sock not opened yet"));
return;
......@@ -349,8 +423,20 @@ inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt)
}
}
inline int RtspPusher::getTrackIndexByTrackType(TrackType type) {
for (unsigned int i = 0; i < _track_vec.size(); i++) {
int RtspPusher::getTrackIndexByInterleaved(int interleaved) const {
for (int i = 0; i < (int)_track_vec.size(); ++i) {
if (_track_vec[i]->_interleaved == interleaved) {
return i;
}
}
if (_track_vec.size() == 1) {
return 0;
}
throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved);
}
int RtspPusher::getTrackIndexByTrackType(TrackType type) const{
for (int i = 0; i < (int)_track_vec.size(); ++i) {
if (type == _track_vec[i]->_type) {
return i;
}
......
......@@ -21,6 +21,7 @@
#include "Network/TcpClient.h"
#include "RtspSplitter.h"
#include "Pusher/PusherBase.h"
#include "Rtcp/RtcpContext.h"
using namespace std;
using namespace toolkit;
......@@ -51,7 +52,9 @@ protected:
//RtspSplitter override
void onWholeRtspPacket(Parser &parser) override ;
void onRtpPacket(const char *data,size_t len) override {};
void onRtpPacket(const char *data,size_t len) override;
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, uint8_t *data, size_t len);
private:
void onPublishResult(const SockException &ex, bool handshake_done);
......@@ -66,7 +69,8 @@ private:
void handleResSetup(const Parser &parser, unsigned int track_idx);
bool handleAuthenticationFailure(const string &params_str);
inline int getTrackIndexByTrackType(TrackType type);
int getTrackIndexByInterleaved(int interleaved) const;
int getTrackIndexByTrackType(TrackType type) const;
void sendRtpPacket(const RtspMediaSource::RingDataType & pkt) ;
void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap(),const string &sdp = "" );
......@@ -74,6 +78,7 @@ private:
void createUdpSockIfNecessary(int track_idx);
void setSocketFlags();
void updateRtcpContext(const RtpPacket::Ptr &pkt);
private:
unsigned int _cseq = 1;
......@@ -87,7 +92,10 @@ private:
string _content_base;
SdpParser _sdp_parser;
vector<SdpTrack::Ptr> _track_vec;
Socket::Ptr _udp_socks[2];
//RTP端口,trackid idx 为数组下标
Socket::Ptr _rtp_sock[2];
//RTCP端口,trackid idx 为数组下标
Socket::Ptr _rtcp_sock[2];
//超时功能实现
std::shared_ptr<Timer> _publish_timer;
//心跳定时器
......@@ -98,6 +106,11 @@ private:
Event _on_shutdown;
Event _on_published;
function<void(const Parser&)> _on_res_func;
////////// rtcp ////////////////
//rtcp发送时间,trackid idx 为数组下标
Ticker _rtcp_send_ticker[2];
//统计rtp并发送rtcp
vector<RtcpContext::Ptr> _rtcp_context;
};
} /* namespace mediakit */
......
......@@ -26,6 +26,7 @@
#include "RtpReceiver.h"
#include "RtspMediaSourceImp.h"
#include "Common/Stamp.h"
#include "Rtcp/RtcpContext.h"
using namespace std;
using namespace toolkit;
......@@ -79,6 +80,7 @@ protected:
////RtpReceiver override////
void onRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) override;
void onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index) override;
///////MediaSourceEvent override///////
// 关闭
......@@ -152,12 +154,11 @@ private:
//发送rtp给客户端
void sendRtpPacket(const RtspMediaSource::RingDataType &pkt);
//触发rtcp发送
void onSendRtpPacket(const RtpPacket::Ptr &rtp);
void updateRtcpContext(const RtpPacket::Ptr &rtp);
//回复客户端
bool sendRtspResponse(const string &res_code, const std::initializer_list<string> &header, const string &sdp = "", const char *protocol = "RTSP/1.0");
bool sendRtspResponse(const string &res_code, const StrCaseMap &header = StrCaseMap(), const string &sdp = "", const char *protocol = "RTSP/1.0");
//服务器发送rtcp
void sendSenderReport(bool over_tcp, int track_idx);
//设置socket标志
void setSocketFlags();
......@@ -196,11 +197,6 @@ private:
//sdp里面有效的track,包含音频或视频
vector<SdpTrack::Ptr> _sdp_track;
//rtcp统计,trackid idx 为数组下标
RtcpCounter _rtcp_counter[2];
//rtcp发送时间,trackid idx 为数组下标
Ticker _rtcp_send_tickers[2];
////////RTP over udp////////
//RTP端口,trackid idx 为数组下标
Socket::Ptr _rtp_socks[2];
......@@ -216,6 +212,11 @@ private:
//一次发送 get 一次发送post,需要通过x-sessioncookie关联起来
string _http_x_sessioncookie;
function<void(const Buffer::Ptr &)> _on_recv;
////////// rtcp ////////////////
//rtcp发送时间,trackid idx 为数组下标
Ticker _rtcp_send_tickers[2];
//统计rtp并发送rtcp
vector<RtcpContext::Ptr> _rtcp_context;
};
/**
......
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "Rtcp/Rtcp.h"
#include "Util/logger.h"
using namespace std;
using namespace toolkit;
using namespace mediakit;
void printRtcp(const std::shared_ptr<Buffer> &buffer){
auto rtcp_arr = RtcpHeader::loadFromBytes(buffer->data(), buffer->size());
//转换为主机字节序方可打印
InfoL << "\r\n" << rtcp_arr[0]->dumpString();
}
std::shared_ptr<Buffer> makeRtcpSR() {
auto rtcp = RtcpSR::create(3);
rtcp->ssrc = htonl(1);
struct timeval tv;
gettimeofday(&tv, NULL);
rtcp->setNtpStamp(tv);
rtcp->rtpts = htonl(2);
rtcp->packet_count = htonl(3);
rtcp->octet_count = htonl(4);
auto i = 5;
for (auto &ptr : rtcp->getItemList()) {
ReportItem *item = (ReportItem *) ptr;
item->ssrc = htonl(i++);
item->fraction = i++;
item->cumulative = htonl(i++) >> 8;
item->seq_cycles = htons(i++);
item->seq_max = htons(i++);
item->jitter = htonl(i++);
item->last_sr_stamp = htonl(i++);
item->delay_since_last_sr = htonl(i++);
}
//返回网络字节序
return RtcpHeader::toBuffer(rtcp);
}
std::shared_ptr<Buffer> makeRtcpRR() {
auto rtcp = RtcpRR::create(3);
rtcp->ssrc = htonl(1);
auto i = 5;
for (auto &ptr : rtcp->getItemList()) {
ReportItem *item = (ReportItem *) ptr;
item->ssrc = htonl(i++);
item->fraction = i++;
item->cumulative = htonl(i++) >> 8;
item->seq_cycles = htons(i++);
item->seq_max = htons(i++);
item->jitter = htonl(i++);
item->last_sr_stamp = htonl(i++);
item->delay_since_last_sr = htonl(i++);
}
//返回网络字节序
return RtcpHeader::toBuffer(rtcp);
}
std::shared_ptr<Buffer> makeRtcpSDES() {
auto rtcp = RtcpSdes::create({"zlmediakit", "", "https://github.com/xia-chu/ZLMediaKit", "1213642868@qq.com", "123456789012345678"});
auto i = 5;
auto items = rtcp->getItemList();
items[0]->type = (uint8_t)SdesType::RTCP_SDES_CNAME;
items[0]->ssrc = htonl(i++);
items[1]->type = (uint8_t)SdesType::RTCP_SDES_NOTE;
items[1]->ssrc = htonl(i++);
items[2]->type = (uint8_t)SdesType::RTCP_SDES_LOC;
items[2]->ssrc = htonl(i++);
items[3]->type = (uint8_t)SdesType::RTCP_SDES_EMAIL;
items[3]->ssrc = htonl(i++);
items[4]->type = (uint8_t)SdesType::RTCP_SDES_PHONE;
items[4]->ssrc = htonl(i++);
//返回网络字节序
return RtcpHeader::toBuffer(rtcp);
}
int main(int argc, char *argv[]){
Logger::Instance().add(std::make_shared<ConsoleChannel>());
{
static char rtcp_data[] = "\x81\xca\x00\x05\x70\xd8\xac\x1b\x01\x0b\x7a\x73\x68\x50\x43\x40"
"\x7a\x73\x68\x50\x43\x00\x00\x00"
"\x81\xc9\x00\x07\x70\xd8\xac\x1b\x55\x66\x77\x88\x00\x00\x00\x00"
"\x00\x00\x0d\x21\x00\x00\x00\x32\xdd\xf1\x00\x00\x00\x03\x4f\x67"
"\x80\xc8\x00\x06\x55\x66\x77\x88\xe3\x70\xdd\xf1\x00\x00\xc2\xb8"
"\x00\x21\xe4\x90\x00\x00\x0b\x81\x00\x2f\x6a\x60";
auto rtcp_arr = RtcpHeader::loadFromBytes(rtcp_data, sizeof(rtcp_data) - 1);
for (auto &rtcp : rtcp_arr) {
DebugL << "\r\n" << rtcp->dumpString();
}
}
{
printRtcp(makeRtcpSR());
printRtcp(makeRtcpRR());
printRtcp(makeRtcpSDES());
}
{
string str;
auto sr = makeRtcpSR();
auto rr = makeRtcpRR();
auto sdes = makeRtcpSDES();
str.append(sr->data(), sr->size());
str.append(rr->data(), rr->size());
str.append(sdes->data(), sdes->size());
//测试内存越界
char *data = new char[str.size()];
memcpy(data, str.data(), str.size());
auto rtcp_arr = RtcpHeader::loadFromBytes(data, str.size());
for (auto &rtcp : rtcp_arr) {
WarnL << "\r\n" << rtcp->dumpString();
}
delete [] data;
}
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论