Browse Source

Added the SFU Media Demo. Fixed copyrights. Moved RTP stuff back into an header file :)

Staz M 4 years ago
parent
commit
f461a40a6d

+ 1 - 1
examples/media/main.cpp

@@ -1,6 +1,6 @@
 /*
  * libdatachannel client example
- * Copyright (c) 2020 Staz M
+ * Copyright (c) 2020 Staz Modrzynski
  * Copyright (c) 2020 Paul-Louis Ageneau
  *
  * This program is free software; you can redistribute it and/or

+ 14 - 0
examples/sfu-media/CMakeLists.txt

@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+
+add_executable(datachannel-sfu-media main.cpp)
+set_target_properties(datachannel-sfu-media PROPERTIES
+        CXX_STANDARD 17
+        OUTPUT_NAME sfu-media)
+
+if(WIN32)
+    target_link_libraries(datachannel-sfu-media datachannel-static) # DLL exports only the C API
+else()
+    target_link_libraries(datachannel-sfu-media datachannel)
+endif()
+
+target_link_libraries(datachannel-sfu-media datachannel nlohmann_json)

+ 134 - 0
examples/sfu-media/main.cpp

@@ -0,0 +1,134 @@
+/*
+ * libdatachannel client example
+ * Copyright (c) 2020 Staz Modrzynski
+ * Copyright (c) 2020 Paul-Louis Ageneau
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
+
+#include "rtc/rtc.hpp"
+
+#include <iostream>
+#include <memory>
+
+#include <nlohmann/json.hpp>
+
+using nlohmann::json;
+
+class Sender {
+    rtc::PeerConnection conn;
+};
+
+struct Receiver {
+    std::shared_ptr<rtc::PeerConnection> conn;
+    std::shared_ptr<rtc::Track> track;
+};
+int main() {
+    std::vector<std::shared_ptr<Receiver>> receivers;
+
+	try {
+		rtc::InitLogger(rtc::LogLevel::Info);
+
+		auto pc = std::make_shared<rtc::PeerConnection>();
+		pc->onStateChange(
+		    [](rtc::PeerConnection::State state) { std::cout << "State: " << state << std::endl; });
+		pc->onGatheringStateChange([pc](rtc::PeerConnection::GatheringState state) {
+			std::cout << "Gathering State: " << state << std::endl;
+			if (state == rtc::PeerConnection::GatheringState::Complete) {
+				auto description = pc->localDescription();
+				json message = {{"type", description->typeString()},
+				                {"sdp", std::string(description.value())}};
+                std::cout << "Please copy/paste this offer to the SENDER: " << message << std::endl;
+			}
+		});
+
+		rtc::Description::Video media("video", rtc::Description::Direction::RecvOnly);
+		media.addH264Codec(96);
+		media.setBitrate(3000); // Request 3Mbps (Browsers do not encode more than 2.5MBps from a webcam)
+
+		auto track = pc->addTrack(media);
+        pc->setLocalDescription();
+
+		auto session = std::make_shared<rtc::RtcpSession>();
+		track->setRtcpHandler(session);
+
+		track->onMessage(
+		    [&receivers](rtc::binary message) {
+			    // This is an RTP packet
+			    auto rtp = (rtc::RTP*) message.data();
+			    rtp->ssrc = htonl(15);
+			    for (auto pc : receivers) {
+			        if (pc->track != nullptr && pc->track->isOpen()) {
+                        pc->track->send(message);
+                    }
+			    }
+		    },
+		    nullptr);
+
+        // Set the SENDERS Answer
+        {
+            std::cout << "Please copy/paste the answer provided by the SENDER: " << std::endl;
+            std::string sdp;
+            std::getline(std::cin, sdp);
+            std::cout << "Got answer" << sdp << std::endl;
+            json j = json::parse(sdp);
+            rtc::Description answer(j["sdp"].get<std::string>(), j["type"].get<std::string>());
+            pc->setRemoteDescription(answer);
+        }
+
+        // For each receiver
+		while (true) {
+            auto pc = std::make_shared<Receiver>();
+            pc->conn = std::make_shared<rtc::PeerConnection>();
+            pc->conn->onStateChange(
+                    [](rtc::PeerConnection::State state) { std::cout << "State: " << state << std::endl; });
+            pc->conn->onGatheringStateChange([pc](rtc::PeerConnection::GatheringState state) {
+                std::cout << "Gathering State: " << state << std::endl;
+                if (state == rtc::PeerConnection::GatheringState::Complete) {
+                    auto description = pc->conn->localDescription();
+                    json message = {{"type", description->typeString()},
+                                    {"sdp", std::string(description.value())}};
+                    std::cout << "Please copy/paste this offer to the RECEIVER: " << message << std::endl;
+                }
+            });
+            rtc::Description::Video media("video", rtc::Description::Direction::SendOnly);
+            media.addH264Codec(96);
+            media.setBitrate(
+                    3000); // Request 3Mbps (Browsers do not encode more than 2.5MBps from a webcam)
+
+            pc->track = pc->conn->addTrack(media);
+            pc->conn->setLocalDescription();
+
+            auto session = std::make_shared<rtc::RtcpSession>();
+            pc->track->setRtcpHandler(session);
+
+            pc->track->onMessage([](rtc::binary var){}, nullptr);
+
+            std::cout << "Please copy/paste the answer provided by the RECEIVER: " << std::endl;
+            std::string sdp;
+            std::getline(std::cin, sdp);
+            std::cout << "Got answer" << sdp << std::endl;
+            json j = json::parse(sdp);
+            rtc::Description answer(j["sdp"].get<std::string>(), j["type"].get<std::string>());
+            pc->conn->setRemoteDescription(answer);
+
+            receivers.push_back(pc);
+		}
+
+	} catch (const std::exception &e) {
+		std::cerr << "Error: " << e.what() << std::endl;
+	}
+}

+ 87 - 0
examples/sfu-media/main.html

@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>libdatachannel media example</title>
+</head>
+<body>
+
+<div style="display:inline-block; width:40%;">
+    <h1>SENDER</h1>
+    <p id="send-help">Please enter the offer provided to you by the application: </p>
+    <textarea style="width:100%;" id=send-text rows="50"></textarea>
+    <button id=send-btn>Submit</button>
+</div>
+<div style="display:inline-block; width:40%;">
+    <h1>RECEIVER</h1>
+    <p id="recv-help">Please enter the offer provided to you by the application: </p>
+    <textarea id=recv-text style="width:100%;" rows="50"></textarea>
+    <button id=recv-btn>Submit</button>
+</div>
+<div id="videos">
+
+</div>
+<script>
+    document.querySelector('#send-btn').addEventListener('click',  async () => {
+        let offer = JSON.parse(document.querySelector('#send-text').value);
+        rtc = new RTCPeerConnection({
+            // Recommended for libdatachannel
+            bundlePolicy: "max-bundle",
+        });
+
+        rtc.onicegatheringstatechange = (state) => {
+            if (rtc.iceGatheringState === 'complete') {
+                // We only want to provide an answer once all of our candidates have been added to the SDP.
+                let answer = rtc.localDescription;
+                document.querySelector('#send-text').value = JSON.stringify({"type": answer.type, sdp: answer.sdp});
+                document.querySelector('#send-help').value = 'Please paste the answer in the application.';
+                alert('Please paste the answer in the application.');
+            }
+        }
+        await rtc.setRemoteDescription(offer);
+
+        let media = await navigator.mediaDevices.getUserMedia({
+            video: {
+                width: 1280,
+                height: 720
+            }
+        });
+        media.getTracks().forEach(track => rtc.addTrack(track, media));
+        let answer = await rtc.createAnswer();
+        await rtc.setLocalDescription(answer);
+    });
+
+    document.querySelector('#recv-btn').addEventListener('click',  async () => {
+        let offer = JSON.parse(document.querySelector('#recv-text').value);
+        rtc = new RTCPeerConnection({
+            // Recommended for libdatachannel
+            bundlePolicy: "max-bundle",
+        });
+
+        rtc.onicegatheringstatechange = (state) => {
+            if (rtc.iceGatheringState === 'complete') {
+                // We only want to provide an answer once all of our candidates have been added to the SDP.
+                let answer = rtc.localDescription;
+                document.querySelector('#recv-text').value = JSON.stringify({"type": answer.type, sdp: answer.sdp});
+                document.querySelector('#recv-help').value = 'Please paste the answer in the application.';
+                alert('Please paste the answer in the application.');
+            }
+        }
+        let trackCount = 0;
+        rtc.ontrack = (ev) => {
+            let thisID = trackCount++;
+
+            document.querySelector("#videos").innerHTML += "<video width=100% height=100% id='video-" + thisID + "'></video>";
+            let tracks = [];
+            rtc.getReceivers().forEach(recv => tracks.push(recv.track));
+            document.querySelector("#video-" + thisID).srcObject = new MediaStream(tracks);
+            document.querySelector("#video-" + thisID).play();
+        };
+        await rtc.setRemoteDescription(offer);
+        let answer = await rtc.createAnswer();
+        await rtc.setLocalDescription(answer);
+    });
+</script>
+
+</body>
+</html>

+ 1 - 1
include/rtc/description.hpp

@@ -1,6 +1,6 @@
 /**
  * Copyright (c) 2019-2020 Paul-Louis Ageneau
- * Copyright (c) 2020 Staz M
+ * Copyright (c) 2020 Staz Modrzynski
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public

+ 2 - 3
include/rtc/rtcp.hpp

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020 Staz M
+ * Copyright (c) 2020 Staz Modrzynski
  * Copyright (c) 2020 Paul-Louis Ageneau
  *
  * This library is free software; you can redistribute it and/or
@@ -23,11 +23,10 @@
 #include "include.hpp"
 #include "log.hpp"
 #include "message.hpp"
+#include "rtp.hpp"
 
 namespace rtc {
 
-typedef uint32_t SSRC;
-
 class RtcpHandler {
 public:
 	virtual void onOutgoing(std::function<void(rtc::message_ptr)> cb) = 0;

+ 328 - 0
include/rtc/rtp.hpp

@@ -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

+ 4 - 1
src/description.cpp

@@ -1,6 +1,6 @@
 /**
  * Copyright (c) 2019-2020 Paul-Louis Ageneau
- * Copyright (c) 2020 Staz M
+ * Copyright (c) 2020 Staz Modrzynski
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -374,6 +374,9 @@ Description::Entry::Entry(const string &mline, string mid, Direction dir)
 	ss >> mType;
 	ss >> port; // ignored
 	ss >> mDescription;
+    if (direction() == Direction::SendOnly) {
+        mAttributes.emplace_back("ssrc:15 cname:test");
+    }
 }
 
 void Description::Entry::setDirection(Direction dir) { mDirection = dir; }

+ 1 - 298
src/rtcp.cpp

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020 Staz M
+ * Copyright (c) 2020 Staz Modrzynski
  * Copyright (c) 2020 Paul-Louis Ageneau
  *
  * This library is free software; you can redistribute it and/or
@@ -28,306 +28,9 @@
 #include <arpa/inet.h>
 #endif
 
-#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 {
 
-#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)
 
 void RtcpSession::onOutgoing(std::function<void(rtc::message_ptr)> cb) { mTxCallback = cb; }