Implemented RTSP Receiver Report
This commit is contained in:
parent
364190034d
commit
df6735e92f
5 changed files with 86 additions and 24 deletions
38
lib/rtp.cpp
38
lib/rtp.cpp
|
@ -4,6 +4,7 @@
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
#include "bitfields.h"
|
#include "bitfields.h"
|
||||||
#include "mpeg.h"
|
#include "mpeg.h"
|
||||||
|
#include "sdp.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
namespace RTP{
|
namespace RTP{
|
||||||
|
@ -245,17 +246,18 @@ namespace RTP{
|
||||||
increaseSequence();
|
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,
|
DTSC::Meta &metadata,
|
||||||
void callBack(void *, char *, unsigned int, unsigned int)){
|
void callBack(void *, char *, unsigned int, unsigned int)){
|
||||||
void *rtcpData = malloc(32);
|
char *rtcpData = (char*)malloc(32);
|
||||||
if (!rtcpData){
|
if (!rtcpData){
|
||||||
FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up.");
|
FAIL_MSG("Could not allocate 32 bytes. Something is seriously messed up.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
((int *)rtcpData)[0] = htonl(0x80C80006);
|
rtcpData[0] = 0x80;//version 2, no padding, zero receiver reports
|
||||||
((int *)rtcpData)[1] = htonl(getSSRC());
|
rtcpData[1] = 200;//sender report
|
||||||
// unsigned int tid = packet["trackid"].asInt();
|
Bit::htobs(rtcpData+2, 6);//6 4-byte words follow the header
|
||||||
|
Bit::htobl(rtcpData+4, getSSRC());//set source identifier
|
||||||
// timestamp in ms
|
// timestamp in ms
|
||||||
double ntpTime = 2208988800UL + Util::epoch() + (Util::getMS() % 1000) / 1000.0;
|
double ntpTime = 2208988800UL + Util::epoch() + (Util::getMS() % 1000) / 1000.0;
|
||||||
if (startRTCP < 1 && startRTCP > -1){startRTCP = ntpTime;}
|
if (startRTCP < 1 && startRTCP > -1){startRTCP = ntpTime;}
|
||||||
|
@ -276,6 +278,32 @@ namespace RTP{
|
||||||
free(rtcpData);
|
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(){
|
Packet::Packet(){
|
||||||
managed = false;
|
managed = false;
|
||||||
data = 0;
|
data = 0;
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
namespace SDP{
|
||||||
|
class Track;
|
||||||
|
};
|
||||||
|
|
||||||
/// This namespace holds all RTP-parsing and sending related functionality.
|
/// This namespace holds all RTP-parsing and sending related functionality.
|
||||||
namespace RTP{
|
namespace RTP{
|
||||||
|
|
||||||
|
@ -59,7 +63,9 @@ namespace RTP{
|
||||||
void sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
|
void sendData(void *socket, void callBack(void *, char *, unsigned int, unsigned int),
|
||||||
const char *payload, unsigned int payloadlen, unsigned int channel,
|
const char *payload, unsigned int payloadlen, unsigned int channel,
|
||||||
std::string codec);
|
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));
|
void callBack(void *, char *, unsigned int, unsigned int));
|
||||||
|
|
||||||
Packet();
|
Packet();
|
||||||
|
|
32
lib/sdp.cpp
32
lib/sdp.cpp
|
@ -15,9 +15,14 @@ namespace SDP{
|
||||||
packCount = 0;
|
packCount = 0;
|
||||||
cPort = 0;
|
cPort = 0;
|
||||||
rtpSeq = 0;
|
rtpSeq = 0;
|
||||||
|
lostTotal = 0;
|
||||||
|
lostCurrent = 0;
|
||||||
|
packTotal = 0;
|
||||||
|
packCurrent = 0;
|
||||||
fpsTime = 0;
|
fpsTime = 0;
|
||||||
fpsMeta = 0;
|
fpsMeta = 0;
|
||||||
fps = 0;
|
fps = 0;
|
||||||
|
mySSRC = rand();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a particular parameter from the fmtp string. fmtp member must be set before calling.
|
/// 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.
|
/// \return True if successful, false otherwise.
|
||||||
bool Track::parseTransport(const std::string &transport, const std::string &host,
|
bool Track::parseTransport(const std::string &transport, const std::string &host,
|
||||||
const std::string &source, const DTSC::Track &trk){
|
const std::string &source, const DTSC::Track &trk){
|
||||||
unsigned int SSrc = rand();
|
|
||||||
if (trk.codec == "H264"){
|
if (trk.codec == "H264"){
|
||||||
pack = RTP::Packet(97, 1, 0, SSrc);
|
pack = RTP::Packet(97, 1, 0, mySSRC);
|
||||||
}else if (trk.codec == "HEVC"){
|
}else if (trk.codec == "HEVC"){
|
||||||
pack = RTP::Packet(104, 1, 0, SSrc);
|
pack = RTP::Packet(104, 1, 0, mySSRC);
|
||||||
}else if (trk.codec == "MPEG2"){
|
}else if (trk.codec == "MPEG2"){
|
||||||
pack = RTP::Packet(32, 1, 0, SSrc);
|
pack = RTP::Packet(32, 1, 0, mySSRC);
|
||||||
}else if (trk.codec == "AAC"){
|
}else if (trk.codec == "AAC"){
|
||||||
pack = RTP::Packet(96, 1, 0, SSrc);
|
pack = RTP::Packet(96, 1, 0, mySSRC);
|
||||||
}else if (trk.codec == "AC3"){
|
}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"){
|
}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"){
|
}else if (trk.codec == "ALAW"){
|
||||||
if (trk.channels == 1 && trk.rate == 8000){
|
if (trk.channels == 1 && trk.rate == 8000){
|
||||||
pack = RTP::Packet(8, 1, 0, SSrc);
|
pack = RTP::Packet(8, 1, 0, mySSRC);
|
||||||
}else{
|
}else{
|
||||||
pack = RTP::Packet(101, 1, 0, SSrc);
|
pack = RTP::Packet(101, 1, 0, mySSRC);
|
||||||
}
|
}
|
||||||
}else if (trk.codec == "PCM"){
|
}else if (trk.codec == "PCM"){
|
||||||
if (trk.size == 16 && trk.channels == 2 && trk.rate == 44100){
|
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){
|
}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{
|
}else{
|
||||||
pack = RTP::Packet(103, 1, 0, SSrc);
|
pack = RTP::Packet(103, 1, 0, mySSRC);
|
||||||
}
|
}
|
||||||
}else if (trk.codec == "opus"){
|
}else if (trk.codec == "opus"){
|
||||||
pack = RTP::Packet(102, 1, 0, SSrc);
|
pack = RTP::Packet(102, 1, 0, mySSRC);
|
||||||
}else{
|
}else{
|
||||||
ERROR_MSG("Unsupported codec %s for RTSP on track %u", trk.codec.c_str(), trk.trackID);
|
ERROR_MSG("Unsupported codec %s for RTSP on track %u", trk.codec.c_str(), trk.trackID);
|
||||||
return false;
|
return false;
|
||||||
|
@ -231,7 +235,7 @@ namespace SDP{
|
||||||
std::stringstream tStr;
|
std::stringstream tStr;
|
||||||
tStr << "RTP/AVP/UDP;unicast;client_port=" << cPort << '-' << cPort + 1 << ";";
|
tStr << "RTP/AVP/UDP;unicast;client_port=" << cPort << '-' << cPort + 1 << ";";
|
||||||
if (source.size()){tStr << "source=" << source << ";";}
|
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();
|
transportString = tStr.str();
|
||||||
INFO_MSG("Transport string: %s", transportString.c_str());
|
INFO_MSG("Transport string: %s", transportString.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ namespace SDP{
|
||||||
int channel; /// Channel number, used in TCP sending
|
int channel; /// Channel number, used in TCP sending
|
||||||
uint64_t packCount;
|
uint64_t packCount;
|
||||||
uint16_t rtpSeq;
|
uint16_t rtpSeq;
|
||||||
|
int32_t lostTotal, lostCurrent;
|
||||||
|
uint32_t packTotal, packCurrent;
|
||||||
std::map<uint16_t, RTP::Packet> packBuffer;
|
std::map<uint16_t, RTP::Packet> packBuffer;
|
||||||
uint32_t cPort;
|
uint32_t cPort;
|
||||||
std::string transportString; /// Current transport string.
|
std::string transportString; /// Current transport string.
|
||||||
|
@ -26,6 +28,7 @@ namespace SDP{
|
||||||
std::string fmtp; /// fmtp string, used by getParamString / getParamInt
|
std::string fmtp; /// fmtp string, used by getParamString / getParamInt
|
||||||
std::string spsData;
|
std::string spsData;
|
||||||
std::string ppsData;
|
std::string ppsData;
|
||||||
|
uint32_t mySSRC, theirSSRC;
|
||||||
h265::initData hevcInfo;
|
h265::initData hevcInfo;
|
||||||
uint64_t fpsTime;
|
uint64_t fpsTime;
|
||||||
double fpsMeta;
|
double fpsMeta;
|
||||||
|
|
|
@ -119,7 +119,7 @@ namespace Mist{
|
||||||
callBack = sendUDP;
|
callBack = sendUDP;
|
||||||
if (Util::epoch() / 5 != sdpState.tracks[tid].rtcpSent){
|
if (Util::epoch() / 5 != sdpState.tracks[tid].rtcpSent){
|
||||||
sdpState.tracks[tid].rtcpSent = Util::epoch() / 5;
|
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);
|
sendUDP);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
@ -381,20 +381,28 @@ namespace Mist{
|
||||||
myConn.addDown(s.data_len);
|
myConn.addDown(s.data_len);
|
||||||
RTP::Packet pack(s.data, s.data_len);
|
RTP::Packet pack(s.data, s.data_len);
|
||||||
if (!it->second.rtpSeq){it->second.rtpSeq = pack.getSequence();}
|
if (!it->second.rtpSeq){it->second.rtpSeq = pack.getSequence();}
|
||||||
// packet is very early - assume dropped after 10 packets
|
// packet is very early - assume dropped after 30 packets
|
||||||
while ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < -10){
|
while ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < -30){
|
||||||
WARN_MSG("Giving up on packet %u", it->second.rtpSeq);
|
WARN_MSG("Giving up on packet %u", it->second.rtpSeq);
|
||||||
++(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
|
// send any buffered packets we may have
|
||||||
while (it->second.packBuffer.count(it->second.rtpSeq)){
|
while (it->second.packBuffer.count(it->second.rtpSeq)){
|
||||||
sdpState.handleIncomingRTP(it->first, pack);
|
sdpState.handleIncomingRTP(it->first, pack);
|
||||||
++(it->second.rtpSeq);
|
++(it->second.rtpSeq);
|
||||||
|
++(it->second.packTotal);
|
||||||
|
++(it->second.packCurrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// send any buffered packets we may have
|
// send any buffered packets we may have
|
||||||
while (it->second.packBuffer.count(it->second.rtpSeq)){
|
while (it->second.packBuffer.count(it->second.rtpSeq)){
|
||||||
sdpState.handleIncomingRTP(it->first, pack);
|
sdpState.handleIncomingRTP(it->first, pack);
|
||||||
++(it->second.rtpSeq);
|
++(it->second.rtpSeq);
|
||||||
|
++(it->second.packTotal);
|
||||||
|
++(it->second.packCurrent);
|
||||||
}
|
}
|
||||||
// packet is slightly early - buffer it
|
// packet is slightly early - buffer it
|
||||||
if (((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < 0)){
|
if (((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) < 0)){
|
||||||
|
@ -404,6 +412,10 @@ namespace Mist{
|
||||||
// packet is late
|
// packet is late
|
||||||
if ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) > 0){
|
if ((int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())) > 0){
|
||||||
// negative difference?
|
// 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)",
|
WARN_MSG("Dropped a packet that arrived too late! (%d packets difference)",
|
||||||
(int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())));
|
(int16_t)(((uint16_t)it->second.rtpSeq) - ((uint16_t)pack.getSequence())));
|
||||||
return;
|
return;
|
||||||
|
@ -412,9 +424,18 @@ namespace Mist{
|
||||||
if (it->second.rtpSeq == pack.getSequence()){
|
if (it->second.rtpSeq == pack.getSequence()){
|
||||||
sdpState.handleIncomingRTP(it->first, pack);
|
sdpState.handleIncomingRTP(it->first, pack);
|
||||||
++(it->second.rtpSeq);
|
++(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue