mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-09-01 14:49:25 +00:00
Added the SFU Media Demo. Fixed copyrights. Moved RTP stuff back into an header file :)
This commit is contained in:
328
include/rtc/rtp.hpp
Normal file
328
include/rtc/rtp.hpp
Normal file
@ -0,0 +1,328 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Staz Modrzynski
|
||||
* Copyright (c) 2020 Paul-Louis Ageneau
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_SERVER_RTP_HPP
|
||||
#define WEBRTC_SERVER_RTP_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifndef htonll
|
||||
#define htonll(x) \
|
||||
((uint64_t)htonl(((uint64_t)(x)&0xFFFFFFFF) << 32) | (uint64_t)htonl((uint64_t)(x) >> 32))
|
||||
#endif
|
||||
#ifndef ntohll
|
||||
#define ntohll(x) htonll(x)
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
typedef uint32_t SSRC;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct RTP {
|
||||
private:
|
||||
uint8_t _first;
|
||||
uint8_t _payloadType;
|
||||
uint16_t _seqNumber;
|
||||
uint32_t _timestamp;
|
||||
|
||||
public:
|
||||
SSRC ssrc;
|
||||
SSRC csrc[16];
|
||||
|
||||
inline uint8_t version() const { return _first >> 6; }
|
||||
inline bool padding() const { return (_first >> 5) & 0x01; }
|
||||
inline uint8_t csrcCount() const { return _first & 0x0F; }
|
||||
inline uint8_t payloadType() const { return _payloadType; }
|
||||
inline uint16_t seqNumber() const { return ntohs(_seqNumber); }
|
||||
inline uint32_t timestamp() const { return ntohl(_timestamp); }
|
||||
};
|
||||
|
||||
struct RTCP_ReportBlock {
|
||||
SSRC ssrc;
|
||||
|
||||
private:
|
||||
uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit
|
||||
uint16_t _seqNoCycles;
|
||||
uint16_t _highestSeqNo;
|
||||
uint32_t _jitter;
|
||||
uint32_t _lastReport;
|
||||
uint32_t _delaySinceLastReport;
|
||||
|
||||
public:
|
||||
inline void preparePacket(SSRC ssrc, [[maybe_unused]] unsigned int packetsLost,
|
||||
[[maybe_unused]] unsigned int totalPackets, uint16_t highestSeqNo,
|
||||
uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP,
|
||||
uint64_t lastSR_DELAY) {
|
||||
setSeqNo(highestSeqNo, seqNoCycles);
|
||||
setJitter(jitter);
|
||||
setSSRC(ssrc);
|
||||
|
||||
// Middle 32 bits of NTP Timestamp
|
||||
// this->lastReport = lastSR_NTP >> 16u;
|
||||
setNTPOfSR(uint32_t(lastSR_NTP));
|
||||
setDelaySinceSR(uint32_t(lastSR_DELAY));
|
||||
|
||||
// The delay, expressed in units of 1/65536 seconds
|
||||
// this->delaySinceLastReport = lastSR_DELAY;
|
||||
}
|
||||
|
||||
inline void setSSRC(SSRC ssrc) { this->ssrc = htonl(ssrc); }
|
||||
inline SSRC getSSRC() const { return ntohl(ssrc); }
|
||||
|
||||
inline void setPacketsLost([[maybe_unused]] unsigned int packetsLost,
|
||||
[[maybe_unused]] unsigned int totalPackets) {
|
||||
// TODO Implement loss percentages.
|
||||
_fractionLostAndPacketsLost = 0;
|
||||
}
|
||||
inline unsigned int getLossPercentage() const {
|
||||
// TODO Implement loss percentages.
|
||||
return 0;
|
||||
}
|
||||
inline unsigned int getPacketLostCount() const {
|
||||
// TODO Implement total packets lost.
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline uint16_t seqNoCycles() const { return ntohs(_seqNoCycles); }
|
||||
inline uint16_t highestSeqNo() const { return ntohs(_highestSeqNo); }
|
||||
inline uint32_t jitter() const { return ntohl(_jitter); }
|
||||
|
||||
inline void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) {
|
||||
_highestSeqNo = htons(highestSeqNo);
|
||||
_seqNoCycles = htons(seqNoCycles);
|
||||
}
|
||||
|
||||
inline void setJitter(uint32_t jitter) { _jitter = htonl(jitter); }
|
||||
|
||||
inline void setNTPOfSR(uint32_t ntp) { _lastReport = htonl(ntp >> 16u); }
|
||||
inline uint32_t getNTPOfSR() const { return ntohl(_lastReport) << 16u; }
|
||||
|
||||
inline void setDelaySinceSR(uint32_t sr) {
|
||||
// The delay, expressed in units of 1/65536 seconds
|
||||
_delaySinceLastReport = htonl(sr);
|
||||
}
|
||||
inline uint32_t getDelaySinceSR() const { return ntohl(_delaySinceLastReport); }
|
||||
|
||||
inline void log() const {
|
||||
PLOG_DEBUG << "RTCP report block: "
|
||||
<< "ssrc="
|
||||
<< ntohl(ssrc)
|
||||
// TODO: Implement these reports
|
||||
// << ", fractionLost=" << fractionLost
|
||||
// << ", packetsLost=" << packetsLost
|
||||
<< ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles()
|
||||
<< ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR()
|
||||
<< ", lastSRDelay=" << getDelaySinceSR();
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_HEADER {
|
||||
private:
|
||||
uint8_t _first;
|
||||
uint8_t _payloadType;
|
||||
uint16_t _length;
|
||||
|
||||
public:
|
||||
inline uint8_t version() const { return _first >> 6; }
|
||||
inline bool padding() const { return (_first >> 5) & 0x01; }
|
||||
inline uint8_t reportCount() const { return _first & 0x0F; }
|
||||
inline uint8_t payloadType() const { return _payloadType; }
|
||||
inline uint16_t length() const { return ntohs(_length); }
|
||||
|
||||
inline void setPayloadType(uint8_t type) { _payloadType = type; }
|
||||
inline void setReportCount(uint8_t count) { _first = (_first & 0xF0) | (count & 0x0F); }
|
||||
inline void setLength(uint16_t length) { _length = htons(length); }
|
||||
|
||||
inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) {
|
||||
_first = 0x02 << 6; // version 2, no padding
|
||||
setReportCount(reportCount);
|
||||
setPayloadType(payloadType);
|
||||
setLength(length);
|
||||
}
|
||||
|
||||
inline void log() const {
|
||||
PLOG_DEBUG << "RTCP header: "
|
||||
<< "version=" << unsigned(version()) << ", padding=" << padding()
|
||||
<< ", reportCount=" << unsigned(reportCount())
|
||||
<< ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_SR {
|
||||
RTCP_HEADER header;
|
||||
SSRC senderSSRC;
|
||||
|
||||
private:
|
||||
uint64_t _ntpTimestamp;
|
||||
uint32_t _rtpTimestamp;
|
||||
uint32_t _packetCount;
|
||||
uint32_t _octetCount;
|
||||
|
||||
RTCP_ReportBlock _reportBlocks;
|
||||
|
||||
public:
|
||||
inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) {
|
||||
unsigned int length =
|
||||
((sizeof(header) + 24 + reportCount * sizeof(RTCP_ReportBlock)) / 4) - 1;
|
||||
header.prepareHeader(200, reportCount, uint16_t(length));
|
||||
this->senderSSRC = htonl(senderSSRC);
|
||||
}
|
||||
|
||||
inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
|
||||
inline const RTCP_ReportBlock *getReportBlock(int num) const { return &_reportBlocks + num; }
|
||||
|
||||
[[nodiscard]] inline size_t getSize() const {
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
return sizeof(uint32_t) * (1 + size_t(header.length()));
|
||||
}
|
||||
|
||||
inline uint32_t ntpTimestamp() const { return ntohll(_ntpTimestamp); }
|
||||
inline uint32_t rtpTimestamp() const { return ntohl(_rtpTimestamp); }
|
||||
inline uint32_t packetCount() const { return ntohl(_packetCount); }
|
||||
inline uint32_t octetCount() const { return ntohl(_octetCount); }
|
||||
|
||||
inline void setNtpTimestamp(uint32_t ts) { _ntpTimestamp = htonll(ts); }
|
||||
inline void setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); }
|
||||
|
||||
inline void log() const {
|
||||
header.log();
|
||||
PLOG_DEBUG << "RTCP SR: "
|
||||
<< " SSRC=" << ntohl(senderSSRC) << ", NTP_TS=" << ntpTimestamp()
|
||||
<< ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount()
|
||||
<< ", octetCount=" << octetCount();
|
||||
|
||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
||||
getReportBlock(i)->log();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_RR {
|
||||
RTCP_HEADER header;
|
||||
SSRC senderSSRC;
|
||||
|
||||
private:
|
||||
RTCP_ReportBlock _reportBlocks;
|
||||
|
||||
public:
|
||||
inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
|
||||
inline const RTCP_ReportBlock *getReportBlock(int num) const { return &_reportBlocks + num; }
|
||||
|
||||
inline SSRC getSenderSSRC() const { return ntohl(senderSSRC); }
|
||||
inline void setSenderSSRC(SSRC ssrc) { this->senderSSRC = htonl(ssrc); }
|
||||
|
||||
[[nodiscard]] inline size_t getSize() const {
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
return sizeof(uint32_t) * (1 + size_t(header.length()));
|
||||
}
|
||||
|
||||
inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) {
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
size_t length = (sizeWithReportBlocks(reportCount) / 4) - 1;
|
||||
header.prepareHeader(201, reportCount, uint16_t(length));
|
||||
this->senderSSRC = htonl(senderSSRC);
|
||||
}
|
||||
|
||||
inline static size_t sizeWithReportBlocks(uint8_t reportCount) {
|
||||
return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock);
|
||||
}
|
||||
|
||||
inline void log() const {
|
||||
header.log();
|
||||
PLOG_DEBUG << "RTCP RR: "
|
||||
<< " SSRC=" << ntohl(senderSSRC);
|
||||
|
||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
||||
getReportBlock(i)->log();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_REMB {
|
||||
RTCP_HEADER header;
|
||||
SSRC senderSSRC;
|
||||
SSRC mediaSourceSSRC;
|
||||
|
||||
// Unique identifier
|
||||
const char id[4] = {'R', 'E', 'M', 'B'};
|
||||
|
||||
// Num SSRC, Br Exp, Br Mantissa (bit mask)
|
||||
uint32_t bitrate;
|
||||
|
||||
SSRC ssrc[1];
|
||||
|
||||
[[nodiscard]] inline size_t getSize() const {
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
return sizeof(uint32_t) * (1 + size_t(header.length()));
|
||||
}
|
||||
|
||||
inline void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int bitrate) {
|
||||
// Report Count becomes the format here.
|
||||
header.prepareHeader(206, 15, 0);
|
||||
|
||||
// Always zero.
|
||||
mediaSourceSSRC = 0;
|
||||
|
||||
this->senderSSRC = htonl(senderSSRC);
|
||||
setBitrate(numSSRC, bitrate);
|
||||
}
|
||||
|
||||
inline void setBitrate(unsigned int numSSRC, unsigned int bitrate) {
|
||||
unsigned int exp = 0;
|
||||
while (bitrate > pow(2, 18) - 1) {
|
||||
exp++;
|
||||
bitrate /= 2;
|
||||
}
|
||||
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
header.setLength(uint16_t(((sizeof(header) + 4 * 2 + 4 + 4) / 4) - 1 + numSSRC));
|
||||
|
||||
this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | bitrate);
|
||||
}
|
||||
|
||||
// TODO Make this work
|
||||
// uint64_t getBitrate() const{
|
||||
// uint32_t ntohed = ntohl(this->bitrate);
|
||||
// uint64_t bitrate = ntohed & (unsigned int)(pow(2, 18)-1);
|
||||
// unsigned int exp = ntohed & ((unsigned int)( (pow(2, 6)-1)) << (32u-8u-6u));
|
||||
// return bitrate * pow(2,exp);
|
||||
// }
|
||||
//
|
||||
// uint8_t getNumSSRCS() const {
|
||||
// return ntohl(this->bitrate) & (((unsigned int) pow(2,8)-1) << (32u-8u));
|
||||
// }
|
||||
|
||||
inline void setSSRC(uint8_t iterator, SSRC ssrc) { this->ssrc[iterator] = htonl(ssrc); }
|
||||
|
||||
inline void log() const {
|
||||
header.log();
|
||||
PLOG_DEBUG << "RTCP REMB: "
|
||||
<< " SSRC=" << ntohl(senderSSRC);
|
||||
}
|
||||
|
||||
static unsigned int sizeWithSSRCs(int numSSRC) {
|
||||
return (sizeof(header) + 4 * 2 + 4 + 4) + sizeof(SSRC) * numSSRC;
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
};
|
||||
#endif //WEBRTC_SERVER_RTP_HPP
|
Reference in New Issue
Block a user