From df6735e92f569488c484f6557d9f5147a0805691 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Wed, 23 Aug 2017 20:15:38 +0200 Subject: [PATCH] Implemented RTSP Receiver Report --- lib/rtp.cpp | 40 ++++++++++++++++++++++++++++++++------ lib/rtp.h | 8 +++++++- lib/sdp.cpp | 32 +++++++++++++++++------------- lib/sdp.h | 3 +++ src/output/output_rtsp.cpp | 27 ++++++++++++++++++++++--- 5 files changed, 86 insertions(+), 24 deletions(-) diff --git a/lib/rtp.cpp b/lib/rtp.cpp index f52d7e9e..72853752 100644 --- a/lib/rtp.cpp +++ b/lib/rtp.cpp @@ -4,6 +4,7 @@ #include "timing.h" #include "bitfields.h" #include "mpeg.h" +#include "sdp.h" #include namespace RTP{ @@ -245,18 +246,19 @@ namespace RTP{ increaseSequence(); } - void Packet::sendRTCP(long long &connectedAt, void *socket, unsigned int tid, + void Packet::sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata, void callBack(void *, char *, unsigned int, unsigned int)){ - void *rtcpData = malloc(32); + char *rtcpData = (char*)malloc(32); if (!rtcpData){ FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up."); return; } - ((int *)rtcpData)[0] = htonl(0x80C80006); - ((int *)rtcpData)[1] = htonl(getSSRC()); - // unsigned int tid = packet["trackid"].asInt(); - // timestamp in ms + rtcpData[0] = 0x80;//version 2, no padding, zero receiver reports + rtcpData[1] = 200;//sender report + Bit::htobs(rtcpData+2, 6);//6 4-byte words follow the header + Bit::htobl(rtcpData+4, getSSRC());//set source identifier + // timestamp in ms double ntpTime = 2208988800UL + Util::epoch() + (Util::getMS() % 1000) / 1000.0; if (startRTCP < 1 && startRTCP > -1){startRTCP = ntpTime;} ntpTime -= startRTCP; @@ -276,6 +278,32 @@ namespace RTP{ free(rtcpData); } + void Packet::sendRTCP_RR(long long &connectedAt, SDP::Track & sTrk, unsigned int tid, + DTSC::Meta &metadata, + void callBack(void *, char *, unsigned int, unsigned int)){ + char *rtcpData = (char*)malloc(32); + if (!rtcpData){ + FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up."); + return; + } + if (!(sTrk.lostCurrent + sTrk.packCurrent)){sTrk.packCurrent++;} + rtcpData[0] = 0x81;//version 2, no padding, one receiver report + rtcpData[1] = 201;//receiver report + Bit::htobs(rtcpData+2, 7);//7 4-byte words follow the header + Bit::htobl(rtcpData+4, sTrk.mySSRC);//set receiver identifier + Bit::htobl(rtcpData+8, sTrk.theirSSRC);//set source identifier + rtcpData[12] = (sTrk.lostCurrent * 255) / (sTrk.lostCurrent + sTrk.packCurrent); //fraction lost since prev RR + Bit::htob24(rtcpData+13, sTrk.lostTotal); //cumulative packets lost since start + Bit::htobl(rtcpData+16, sTrk.rtpSeq | (sTrk.packTotal & 0xFFFF0000ul)); //highest sequence received + Bit::htobl(rtcpData+20, 0); /// \TODO jitter (diff in timestamp vs packet arrival) + Bit::htobl(rtcpData+24, 0); /// \TODO last SR (middle 32 bits of last SR or zero) + Bit::htobl(rtcpData+28, 0); /// \TODO delay since last SR in 2b seconds + 2b fraction + callBack(&(sTrk.rtcp), (char *)rtcpData, 32, 0); + sTrk.lostCurrent = 0; + sTrk.packCurrent = 0; + free(rtcpData); + } + Packet::Packet(){ managed = false; data = 0; diff --git a/lib/rtp.h b/lib/rtp.h index 1849e6cf..2d0468cf 100644 --- a/lib/rtp.h +++ b/lib/rtp.h @@ -15,6 +15,10 @@ #include #include +namespace SDP{ + class Track; +}; + /// This namespace holds all RTP-parsing and sending related functionality. namespace RTP{ @@ -59,7 +63,9 @@ namespace RTP{ void sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int), const char *payload, unsigned int payloadlen, unsigned int channel, std::string codec); - void sendRTCP(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata, + void sendRTCP_SR(long long &connectedAt, void *socket, unsigned int tid, DTSC::Meta &metadata, + void callBack(void *, char *, unsigned int, unsigned int)); + void sendRTCP_RR(long long &connectedAt, SDP::Track & sTrk, unsigned int tid, DTSC::Meta &metadata, void callBack(void *, char *, unsigned int, unsigned int)); Packet(); diff --git a/lib/sdp.cpp b/lib/sdp.cpp index f53342bc..711988ce 100644 --- a/lib/sdp.cpp +++ b/lib/sdp.cpp @@ -15,9 +15,14 @@ namespace SDP{ packCount = 0; cPort = 0; rtpSeq = 0; + lostTotal = 0; + lostCurrent = 0; + packTotal = 0; + packCurrent = 0; fpsTime = 0; fpsMeta = 0; fps = 0; + mySSRC = rand(); } /// Extracts a particular parameter from the fmtp string. fmtp member must be set before calling. @@ -175,35 +180,34 @@ namespace SDP{ /// \return True if successful, false otherwise. bool Track::parseTransport(const std::string &transport, const std::string &host, const std::string &source, const DTSC::Track &trk){ - unsigned int SSrc = rand(); if (trk.codec == "H264"){ - pack = RTP::Packet(97, 1, 0, SSrc); + pack = RTP::Packet(97, 1, 0, mySSRC); }else if (trk.codec == "HEVC"){ - pack = RTP::Packet(104, 1, 0, SSrc); + pack = RTP::Packet(104, 1, 0, mySSRC); }else if (trk.codec == "MPEG2"){ - pack = RTP::Packet(32, 1, 0, SSrc); + pack = RTP::Packet(32, 1, 0, mySSRC); }else if (trk.codec == "AAC"){ - pack = RTP::Packet(96, 1, 0, SSrc); + pack = RTP::Packet(96, 1, 0, mySSRC); }else if (trk.codec == "AC3"){ - pack = RTP::Packet(100, 1, 0, SSrc); + pack = RTP::Packet(100, 1, 0, mySSRC); }else if (trk.codec == "MP3" || trk.codec == "MP2"){ - pack = RTP::Packet(14, 1, 0, SSrc); + pack = RTP::Packet(14, 1, 0, mySSRC); }else if (trk.codec == "ALAW"){ if (trk.channels == 1 && trk.rate == 8000){ - pack = RTP::Packet(8, 1, 0, SSrc); + pack = RTP::Packet(8, 1, 0, mySSRC); }else{ - pack = RTP::Packet(101, 1, 0, SSrc); + pack = RTP::Packet(101, 1, 0, mySSRC); } }else if (trk.codec == "PCM"){ if (trk.size == 16 && trk.channels == 2 && trk.rate == 44100){ - pack = RTP::Packet(10, 1, 0, SSrc); + pack = RTP::Packet(10, 1, 0, mySSRC); }else if (trk.size == 16 && trk.channels == 1 && trk.rate == 44100){ - pack = RTP::Packet(11, 1, 0, SSrc); + pack = RTP::Packet(11, 1, 0, mySSRC); }else{ - pack = RTP::Packet(103, 1, 0, SSrc); + pack = RTP::Packet(103, 1, 0, mySSRC); } }else if (trk.codec == "opus"){ - pack = RTP::Packet(102, 1, 0, SSrc); + pack = RTP::Packet(102, 1, 0, mySSRC); }else{ ERROR_MSG("Unsupported codec %s for RTSP on track %u", trk.codec.c_str(), trk.trackID); return false; @@ -231,7 +235,7 @@ namespace SDP{ std::stringstream tStr; tStr << "RTP/AVP/UDP;unicast;client_port=" << cPort << '-' << cPort + 1 << ";"; if (source.size()){tStr << "source=" << source << ";";} - tStr << "server_port=" << portA << "-" << portB << ";ssrc=" << std::hex << SSrc << std::dec; + tStr << "server_port=" << portA << "-" << portB << ";ssrc=" << std::hex << mySSRC << std::dec; transportString = tStr.str(); INFO_MSG("Transport string: %s", transportString.c_str()); } diff --git a/lib/sdp.h b/lib/sdp.h index 8a4dcf5f..62afb074 100644 --- a/lib/sdp.h +++ b/lib/sdp.h @@ -19,6 +19,8 @@ namespace SDP{ int channel; /// Channel number, used in TCP sending uint64_t packCount; uint16_t rtpSeq; + int32_t lostTotal, lostCurrent; + uint32_t packTotal, packCurrent; std::map packBuffer; uint32_t cPort; std::string transportString; /// Current transport string. @@ -26,6 +28,7 @@ namespace SDP{ std::string fmtp; /// fmtp string, used by getParamString / getParamInt std::string spsData; std::string ppsData; + uint32_t mySSRC, theirSSRC; h265::initData hevcInfo; uint64_t fpsTime; double fpsMeta; diff --git a/src/output/output_rtsp.cpp b/src/output/output_rtsp.cpp index a011cd6d..aa842f7d 100644 --- a/src/output/output_rtsp.cpp +++ b/src/output/output_rtsp.cpp @@ -119,7 +119,7 @@ namespace Mist{ callBack = sendUDP; if (Util::epoch() / 5 != sdpState.tracks[tid].rtcpSent){ sdpState.tracks[tid].rtcpSent = Util::epoch() / 5; - sdpState.tracks[tid].pack.sendRTCP(connectedAt, &sdpState.tracks[tid].rtcp, tid, myMeta, + sdpState.tracks[tid].pack.sendRTCP_SR(connectedAt, &sdpState.tracks[tid].rtcp, tid, myMeta, sendUDP); } }else{ @@ -381,20 +381,28 @@ namespace Mist{ myConn.addDown(s.data_len); RTP::Packet pack(s.data, s.data_len); if (!it->second.rtpSeq){it->second.rtpSeq = pack.getSequence();} - // packet is very early - assume dropped after 10 packets - while ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < -10){ + // packet is very early - assume dropped after 30 packets + while ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < -30){ WARN_MSG("Giving up on packet %u", it->second.rtpSeq); ++(it->second.rtpSeq); + ++(it->second.lostTotal); + ++(it->second.lostCurrent); + ++(it->second.packTotal); + ++(it->second.packCurrent); // send any buffered packets we may have while (it->second.packBuffer.count(it->second.rtpSeq)){ sdpState.handleIncomingRTP(it->first, pack); ++(it->second.rtpSeq); + ++(it->second.packTotal); + ++(it->second.packCurrent); } } // send any buffered packets we may have while (it->second.packBuffer.count(it->second.rtpSeq)){ sdpState.handleIncomingRTP(it->first, pack); ++(it->second.rtpSeq); + ++(it->second.packTotal); + ++(it->second.packCurrent); } // packet is slightly early - buffer it if (((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < 0)){ @@ -404,6 +412,10 @@ namespace Mist{ // packet is late if ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) > 0){ // negative difference? + --(it->second.lostTotal); + --(it->second.lostCurrent); + ++(it->second.packTotal); + ++(it->second.packCurrent); WARN_MSG("Dropped a packet that arrived too late! (%d packets difference)", (int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence()))); return; @@ -412,8 +424,17 @@ namespace Mist{ if (it->second.rtpSeq == pack.getSequence()){ sdpState.handleIncomingRTP(it->first, pack); ++(it->second.rtpSeq); + ++(it->second.packTotal); + ++(it->second.packCurrent); + if (!it->second.theirSSRC){ + it->second.theirSSRC = pack.getSSRC(); + } } } + if (Util::epoch() / 5 != it->second.rtcpSent){ + it->second.rtcpSent = Util::epoch() / 5; + it->second.pack.sendRTCP_RR(connectedAt, it->second, it->first, myMeta, sendUDP); + } } } }