mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-22 15:15:28 +00:00
Retabbing and reformatting
This commit is contained in:
@ -2,13 +2,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)
|
||||
CXX_STANDARD 17
|
||||
OUTPUT_NAME sfu-media)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(datachannel-sfu-media datachannel-static) # DLL exports only the C API
|
||||
target_link_libraries(datachannel-sfu-media datachannel-static) # DLL exports only the C API
|
||||
else()
|
||||
target_link_libraries(datachannel-sfu-media datachannel)
|
||||
target_link_libraries(datachannel-sfu-media datachannel)
|
||||
endif()
|
||||
|
||||
target_link_libraries(datachannel-sfu-media datachannel nlohmann_json)
|
||||
target_link_libraries(datachannel-sfu-media datachannel nlohmann_json)
|
||||
|
||||
|
@ -29,11 +29,11 @@
|
||||
using nlohmann::json;
|
||||
|
||||
struct Receiver {
|
||||
std::shared_ptr<rtc::PeerConnection> conn;
|
||||
std::shared_ptr<rtc::Track> track;
|
||||
std::shared_ptr<rtc::PeerConnection> conn;
|
||||
std::shared_ptr<rtc::Track> track;
|
||||
};
|
||||
int main() {
|
||||
std::vector<std::shared_ptr<Receiver>> receivers;
|
||||
std::vector<std::shared_ptr<Receiver>> receivers;
|
||||
|
||||
try {
|
||||
rtc::InitLogger(rtc::LogLevel::Info);
|
||||
@ -47,16 +47,17 @@ int main() {
|
||||
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;
|
||||
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)
|
||||
media.setBitrate(
|
||||
3000); // Request 3Mbps (Browsers do not encode more than 2.5MBps from a webcam)
|
||||
|
||||
auto track = pc->addTrack(media);
|
||||
pc->setLocalDescription();
|
||||
pc->setLocalDescription();
|
||||
|
||||
auto session = std::make_shared<rtc::RtcpReceivingSession>();
|
||||
track->setRtcpHandler(session);
|
||||
@ -66,63 +67,65 @@ int main() {
|
||||
track->onMessage(
|
||||
[&receivers](rtc::binary message) {
|
||||
// This is an RTP packet
|
||||
auto rtp = (rtc::RTP*) message.data();
|
||||
auto rtp = (rtc::RTP *)message.data();
|
||||
rtp->setSsrc(targetSSRC);
|
||||
for (auto pc : receivers) {
|
||||
if (pc->track != nullptr && pc->track->isOpen()) {
|
||||
pc->track->send(message);
|
||||
}
|
||||
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);
|
||||
}
|
||||
// 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
|
||||
// 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)
|
||||
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)
|
||||
|
||||
media.addSSRC(targetSSRC, "video-send");
|
||||
media.addSSRC(targetSSRC, "video-send");
|
||||
|
||||
pc->track = pc->conn->addTrack(media);
|
||||
pc->conn->setLocalDescription();
|
||||
pc->track = pc->conn->addTrack(media);
|
||||
pc->conn->setLocalDescription();
|
||||
|
||||
pc->track->onMessage([](rtc::binary var){}, nullptr);
|
||||
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);
|
||||
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);
|
||||
receivers.push_back(pc);
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
|
@ -72,4 +72,3 @@ std::ostream &operator<<(std::ostream &out, const rtc::Candidate::Type &type);
|
||||
std::ostream &operator<<(std::ostream &out, const rtc::Candidate::TransportType &transportType);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -38,8 +38,8 @@ class PeerConnection;
|
||||
|
||||
class DataChannel : public std::enable_shared_from_this<DataChannel>, public Channel {
|
||||
public:
|
||||
DataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label,
|
||||
string protocol, Reliability reliability);
|
||||
DataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label, string protocol,
|
||||
Reliability reliability);
|
||||
virtual ~DataChannel();
|
||||
|
||||
uint16_t stream() const;
|
||||
@ -90,9 +90,9 @@ private:
|
||||
class NegociatedDataChannel final : public DataChannel {
|
||||
public:
|
||||
NegociatedDataChannel(std::weak_ptr<PeerConnection> pc, uint16_t stream, string label,
|
||||
string protocol, Reliability reliability);
|
||||
string protocol, Reliability reliability);
|
||||
NegociatedDataChannel(std::weak_ptr<PeerConnection> pc, std::weak_ptr<SctpTransport> transport,
|
||||
uint16_t stream);
|
||||
uint16_t stream);
|
||||
~NegociatedDataChannel();
|
||||
|
||||
private:
|
||||
|
@ -77,11 +77,9 @@ public:
|
||||
|
||||
virtual void parseSdpLine(string_view line);
|
||||
|
||||
|
||||
std::vector<string>::iterator beginAttributes();
|
||||
std::vector<string>::iterator endAttributes();
|
||||
std::vector<string>::iterator removeAttribute(std::vector<string>::iterator iterator);
|
||||
|
||||
std::vector<string>::iterator beginAttributes();
|
||||
std::vector<string>::iterator endAttributes();
|
||||
std::vector<string>::iterator removeAttribute(std::vector<string>::iterator iterator);
|
||||
|
||||
protected:
|
||||
Entry(const string &mline, string mid, Direction dir = Direction::Unknown);
|
||||
@ -130,13 +128,13 @@ public:
|
||||
string description() const override;
|
||||
Media reciprocate() const;
|
||||
|
||||
void removeFormat(const string &fmt);
|
||||
void removeFormat(const string &fmt);
|
||||
|
||||
void addSSRC(uint32_t ssrc, std::string name);
|
||||
void addSSRC(uint32_t ssrc);
|
||||
void replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, string name);
|
||||
bool hasSSRC(uint32_t ssrc);
|
||||
std::vector<uint32_t> getSSRCs();
|
||||
void addSSRC(uint32_t ssrc, std::string name);
|
||||
void addSSRC(uint32_t ssrc);
|
||||
void replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, string name);
|
||||
bool hasSSRC(uint32_t ssrc);
|
||||
std::vector<uint32_t> getSSRCs();
|
||||
|
||||
void setBitrate(int bitrate);
|
||||
int getBitrate() const;
|
||||
@ -145,32 +143,29 @@ public:
|
||||
|
||||
virtual void parseSdpLine(string_view line) override;
|
||||
|
||||
struct RTPMap {
|
||||
RTPMap(string_view mline);
|
||||
RTPMap() {}
|
||||
struct RTPMap {
|
||||
RTPMap(string_view mline);
|
||||
RTPMap() {}
|
||||
|
||||
void removeFB(const string &string);
|
||||
void addFB(const string &string);
|
||||
void addAttribute(std::string attr) {
|
||||
fmtps.emplace_back(attr);
|
||||
}
|
||||
void removeFB(const string &string);
|
||||
void addFB(const string &string);
|
||||
void addAttribute(std::string attr) { fmtps.emplace_back(attr); }
|
||||
|
||||
int pt;
|
||||
string format;
|
||||
int clockRate;
|
||||
string encParams;
|
||||
|
||||
int pt;
|
||||
string format;
|
||||
int clockRate;
|
||||
string encParams;
|
||||
std::vector<string> rtcpFbs;
|
||||
std::vector<string> fmtps;
|
||||
|
||||
std::vector<string> rtcpFbs;
|
||||
std::vector<string> fmtps;
|
||||
static int parsePT(string_view view);
|
||||
void setMLine(string_view view);
|
||||
};
|
||||
|
||||
static int parsePT(string_view view);
|
||||
void setMLine(string_view view);
|
||||
};
|
||||
|
||||
std::map<int, RTPMap>::iterator beginMaps();
|
||||
std::map<int, RTPMap>::iterator endMaps();
|
||||
std::map<int, RTPMap>::iterator removeMap(std::map<int, RTPMap>::iterator iterator);
|
||||
std::map<int, RTPMap>::iterator beginMaps();
|
||||
std::map<int, RTPMap>::iterator endMaps();
|
||||
std::map<int, RTPMap>::iterator removeMap(std::map<int, RTPMap>::iterator iterator);
|
||||
|
||||
private:
|
||||
virtual string generateSdpLines(string_view eol) const override;
|
||||
@ -184,26 +179,25 @@ public:
|
||||
std::vector<uint32_t> mSsrcs;
|
||||
|
||||
public:
|
||||
void addRTPMap(const RTPMap& map);
|
||||
|
||||
};
|
||||
void addRTPMap(const RTPMap &map);
|
||||
};
|
||||
|
||||
class Audio : public Media {
|
||||
public:
|
||||
Audio(string mid = "audio", Direction dir = Direction::SendOnly);
|
||||
|
||||
void addAudioCodec(int payloadType, const string &codec);
|
||||
void addOpusCodec(int payloadType);
|
||||
void addAudioCodec(int payloadType, const string &codec);
|
||||
void addOpusCodec(int payloadType);
|
||||
};
|
||||
|
||||
class Video : public Media {
|
||||
public:
|
||||
Video(string mid = "video", Direction dir = Direction::SendOnly);
|
||||
|
||||
void addVideoCodec(int payloadType, const string &codec);
|
||||
void addH264Codec(int payloadType);
|
||||
void addVP8Codec(int payloadType);
|
||||
void addVP9Codec(int payloadType);
|
||||
void addVideoCodec(int payloadType, const string &codec);
|
||||
void addH264Codec(int payloadType);
|
||||
void addVP8Codec(int payloadType);
|
||||
void addVP9Codec(int payloadType);
|
||||
};
|
||||
|
||||
bool hasApplication() const;
|
||||
|
@ -49,6 +49,6 @@ enum class LogLevel { // Don't change, it must match plog severity
|
||||
|
||||
void InitLogger(LogLevel level);
|
||||
void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
|
||||
}
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
@ -139,8 +139,8 @@ private:
|
||||
void forwardMessage(message_ptr message);
|
||||
void forwardMedia(message_ptr message);
|
||||
void forwardBufferedAmount(uint16_t stream, size_t amount);
|
||||
std::optional<std::string> getMidFromSSRC(SSRC ssrc);
|
||||
std::optional<uint32_t> getMLineFromSSRC(SSRC ssrc);
|
||||
std::optional<std::string> getMidFromSSRC(SSRC ssrc);
|
||||
std::optional<uint32_t> getMLineFromSSRC(SSRC ssrc);
|
||||
|
||||
std::shared_ptr<DataChannel> emplaceDataChannel(Description::Role role, string label,
|
||||
DataChannelInit init);
|
||||
@ -153,7 +153,6 @@ private:
|
||||
void incomingTrack(Description::Media description);
|
||||
void openTracks();
|
||||
|
||||
|
||||
void validateRemoteDescription(const Description &description);
|
||||
void processLocalDescription(Description description);
|
||||
void processLocalCandidate(Candidate candidate);
|
||||
@ -182,13 +181,13 @@ private:
|
||||
std::shared_ptr<DtlsTransport> mDtlsTransport;
|
||||
std::shared_ptr<SctpTransport> mSctpTransport;
|
||||
|
||||
std::unordered_map<uint16_t, std::weak_ptr<DataChannel>> mDataChannels; // by stream ID
|
||||
std::unordered_map<string, std::weak_ptr<Track>> mTracks; // by mid
|
||||
std::vector<std::weak_ptr<Track>> mTrackLines; // by SDP order
|
||||
std::unordered_map<uint16_t, std::weak_ptr<DataChannel>> mDataChannels; // by stream ID
|
||||
std::unordered_map<string, std::weak_ptr<Track>> mTracks; // by mid
|
||||
std::vector<std::weak_ptr<Track>> mTrackLines; // by SDP order
|
||||
std::shared_mutex mDataChannelsMutex, mTracksMutex;
|
||||
|
||||
std::unordered_map<uint32_t, string> mMidFromSssrc; // cache
|
||||
std::unordered_map<uint32_t , unsigned int> mMLineFromSssrc; // cache
|
||||
std::unordered_map<uint32_t, string> mMidFromSssrc; // cache
|
||||
std::unordered_map<uint32_t, unsigned int> mMLineFromSssrc; // cache
|
||||
|
||||
std::atomic<State> mState;
|
||||
std::atomic<GatheringState> mGatheringState;
|
||||
|
@ -170,4 +170,3 @@ template <typename T> std::optional<T> Queue<T>::popImpl() {
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -37,4 +37,3 @@ struct Reliability {
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -102,12 +102,14 @@ typedef struct {
|
||||
const char *protocol; // empty string if NULL
|
||||
bool negotiated;
|
||||
bool manualStream;
|
||||
uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
|
||||
uint16_t stream; // numeric ID 0-65534, ignored if manualStream is false
|
||||
} rtcDataChannelInit;
|
||||
|
||||
typedef void(RTC_API *rtcLogCallbackFunc)(rtcLogLevel level, const char *message);
|
||||
typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type, void *ptr);
|
||||
typedef void(RTC_API *rtcCandidateCallbackFunc)(int pc, const char *cand, const char *mid, void *ptr);
|
||||
typedef void(RTC_API *rtcDescriptionCallbackFunc)(int pc, const char *sdp, const char *type,
|
||||
void *ptr);
|
||||
typedef void(RTC_API *rtcCandidateCallbackFunc)(int pc, const char *cand, const char *mid,
|
||||
void *ptr);
|
||||
typedef void(RTC_API *rtcStateChangeCallbackFunc)(int pc, rtcState state, void *ptr);
|
||||
typedef void(RTC_API *rtcGatheringStateCallbackFunc)(int pc, rtcGatheringState state, void *ptr);
|
||||
typedef void(RTC_API *rtcSignalingStateCallbackFunc)(int pc, rtcSignalingState state, void *ptr);
|
||||
@ -147,15 +149,18 @@ RTC_EXPORT int rtcGetRemoteDescription(int pc, char *buffer, int size);
|
||||
RTC_EXPORT int rtcGetLocalAddress(int pc, char *buffer, int size);
|
||||
RTC_EXPORT int rtcGetRemoteAddress(int pc, char *buffer, int size);
|
||||
|
||||
RTC_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, char *remote, int remoteSize);
|
||||
RTC_EXPORT int rtcGetSelectedCandidatePair(int pc, char *local, int localSize, char *remote,
|
||||
int remoteSize);
|
||||
|
||||
// DataChannel
|
||||
RTC_EXPORT int rtcSetDataChannelCallback(int pc, rtcDataChannelCallbackFunc cb);
|
||||
RTC_EXPORT int rtcAddDataChannel(int pc, const char *label); // returns dc id
|
||||
RTC_EXPORT int rtcAddDataChannelEx(int pc, const char *label, const rtcDataChannelInit *init); // returns dc id
|
||||
RTC_EXPORT int rtcAddDataChannelEx(int pc, const char *label,
|
||||
const rtcDataChannelInit *init); // returns dc id
|
||||
// Equivalent to calling rtcAddDataChannel() and rtcSetLocalDescription()
|
||||
RTC_EXPORT int rtcCreateDataChannel(int pc, const char *label); // returns dc id
|
||||
RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label, const rtcDataChannelInit *init); // returns dc id
|
||||
RTC_EXPORT int rtcCreateDataChannelEx(int pc, const char *label,
|
||||
const rtcDataChannelInit *init); // returns dc id
|
||||
RTC_EXPORT int rtcDeleteDataChannel(int dc);
|
||||
|
||||
RTC_EXPORT int rtcGetDataChannelStream(int dc);
|
||||
|
@ -27,4 +27,3 @@
|
||||
|
||||
// C API
|
||||
#include "rtc.h"
|
||||
|
||||
|
@ -31,35 +31,34 @@ namespace rtc {
|
||||
|
||||
class RtcpHandler {
|
||||
protected:
|
||||
/**
|
||||
* Use this callback when trying to send custom data (such as RTCP) to the client.
|
||||
*/
|
||||
synchronized_callback<rtc::message_ptr> outgoingCallback;
|
||||
/**
|
||||
* Use this callback when trying to send custom data (such as RTCP) to the client.
|
||||
*/
|
||||
synchronized_callback<rtc::message_ptr> outgoingCallback;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Called when there is traffic coming from the peer
|
||||
* @param ptr
|
||||
* @return
|
||||
*/
|
||||
virtual rtc::message_ptr incoming(rtc::message_ptr ptr) = 0;
|
||||
/**
|
||||
* Called when there is traffic coming from the peer
|
||||
* @param ptr
|
||||
* @return
|
||||
*/
|
||||
virtual rtc::message_ptr incoming(rtc::message_ptr ptr) = 0;
|
||||
|
||||
/**
|
||||
* Called when there is traffic that needs to be sent to the peer
|
||||
* @param ptr
|
||||
* @return
|
||||
*/
|
||||
virtual rtc::message_ptr outgoing(rtc::message_ptr ptr) = 0;
|
||||
/**
|
||||
* Called when there is traffic that needs to be sent to the peer
|
||||
* @param ptr
|
||||
* @return
|
||||
*/
|
||||
virtual rtc::message_ptr outgoing(rtc::message_ptr ptr) = 0;
|
||||
|
||||
/**
|
||||
* This callback is used to send traffic back to the peer.
|
||||
* This callback skips calling the track's methods.
|
||||
* @param cb
|
||||
*/
|
||||
void onOutgoing(const std::function<void(rtc::message_ptr)> &cb);
|
||||
|
||||
/**
|
||||
* This callback is used to send traffic back to the peer.
|
||||
* This callback skips calling the track's methods.
|
||||
* @param cb
|
||||
*/
|
||||
void onOutgoing(const std::function<void(rtc::message_ptr)>& cb);
|
||||
|
||||
virtual bool requestKeyframe() {return false;}
|
||||
|
||||
virtual bool requestKeyframe() { return false; }
|
||||
};
|
||||
|
||||
class Track;
|
||||
@ -67,20 +66,19 @@ class Track;
|
||||
// An RtcpSession can be plugged into a Track to handle the whole RTCP session
|
||||
class RtcpReceivingSession : public RtcpHandler {
|
||||
public:
|
||||
|
||||
rtc::message_ptr incoming(rtc::message_ptr ptr) override;
|
||||
rtc::message_ptr outgoing(rtc::message_ptr ptr) override;
|
||||
bool send(rtc::message_ptr ptr);
|
||||
rtc::message_ptr incoming(rtc::message_ptr ptr) override;
|
||||
rtc::message_ptr outgoing(rtc::message_ptr ptr) override;
|
||||
bool send(rtc::message_ptr ptr);
|
||||
|
||||
void requestBitrate(unsigned int newBitrate);
|
||||
|
||||
bool requestKeyframe() override;
|
||||
bool requestKeyframe() override;
|
||||
|
||||
protected:
|
||||
void pushREMB(unsigned int bitrate);
|
||||
void pushRR(unsigned int lastSR_delay);
|
||||
|
||||
void pushPLI();
|
||||
void pushPLI();
|
||||
|
||||
unsigned int mRequestedBitrate = 0;
|
||||
SSRC mSsrc = 0;
|
||||
|
@ -37,491 +37,456 @@
|
||||
#endif
|
||||
|
||||
namespace rtc {
|
||||
typedef uint32_t SSRC;
|
||||
typedef uint32_t SSRC;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct RTP {
|
||||
private:
|
||||
uint8_t _first;
|
||||
uint8_t _payloadType;
|
||||
uint16_t _seqNumber;
|
||||
uint32_t _timestamp;
|
||||
SSRC _ssrc;
|
||||
uint8_t _first;
|
||||
uint8_t _payloadType;
|
||||
uint16_t _seqNumber;
|
||||
uint32_t _timestamp;
|
||||
SSRC _ssrc;
|
||||
|
||||
public:
|
||||
SSRC csrc[16];
|
||||
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 marker() const { return _payloadType & 0b10000000; }
|
||||
inline uint8_t payloadType() const { return _payloadType & 0b01111111; }
|
||||
inline uint16_t seqNumber() const { return ntohs(_seqNumber); }
|
||||
inline uint32_t timestamp() const { return ntohl(_timestamp); }
|
||||
inline uint32_t ssrc() const { return ntohl(_ssrc);}
|
||||
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 marker() const { return _payloadType & 0b10000000; }
|
||||
inline uint8_t payloadType() const { return _payloadType & 0b01111111; }
|
||||
inline uint16_t seqNumber() const { return ntohs(_seqNumber); }
|
||||
inline uint32_t timestamp() const { return ntohl(_timestamp); }
|
||||
inline uint32_t ssrc() const { return ntohl(_ssrc); }
|
||||
|
||||
inline size_t getSize() const {
|
||||
return ((char*)&csrc) - ((char*)this) + sizeof(SSRC)*csrcCount();
|
||||
}
|
||||
inline size_t getSize() const {
|
||||
return ((char *)&csrc) - ((char *)this) + sizeof(SSRC) * csrcCount();
|
||||
}
|
||||
|
||||
char * getBody() const {
|
||||
return ((char*) &csrc) + sizeof(SSRC)*csrcCount();
|
||||
}
|
||||
char *getBody() const { return ((char *)&csrc) + sizeof(SSRC) * csrcCount(); }
|
||||
|
||||
inline void setSeqNumber(uint16_t newSeqNo) {
|
||||
_seqNumber = htons(newSeqNo);
|
||||
}
|
||||
inline void setPayloadType(uint8_t newPayloadType) {
|
||||
_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
|
||||
}
|
||||
inline void setSsrc(uint32_t ssrc) {
|
||||
_ssrc = htonl(ssrc);
|
||||
}
|
||||
inline void setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); }
|
||||
inline void setPayloadType(uint8_t newPayloadType) {
|
||||
_payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType);
|
||||
}
|
||||
inline void setSsrc(uint32_t ssrc) { _ssrc = htonl(ssrc); }
|
||||
|
||||
void setTimestamp(uint32_t i) {
|
||||
_timestamp = htonl(i);
|
||||
}
|
||||
void setTimestamp(uint32_t i) { _timestamp = htonl(i); }
|
||||
};
|
||||
|
||||
struct RTCP_ReportBlock {
|
||||
SSRC ssrc;
|
||||
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;
|
||||
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);
|
||||
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(uint64_t(lastSR_NTP));
|
||||
setDelaySinceSR(uint32_t(lastSR_DELAY));
|
||||
// Middle 32 bits of NTP Timestamp
|
||||
// this->lastReport = lastSR_NTP >> 16u;
|
||||
setNTPOfSR(uint64_t(lastSR_NTP));
|
||||
setDelaySinceSR(uint32_t(lastSR_DELAY));
|
||||
|
||||
// The delay, expressed in units of 1/65536 seconds
|
||||
// this->delaySinceLastReport = 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 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 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 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 setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) {
|
||||
_highestSeqNo = htons(highestSeqNo);
|
||||
_seqNoCycles = htons(seqNoCycles);
|
||||
}
|
||||
|
||||
inline void setJitter(uint32_t jitter) { _jitter = htonl(jitter); }
|
||||
inline void setJitter(uint32_t jitter) { _jitter = htonl(jitter); }
|
||||
|
||||
inline void setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); }
|
||||
inline uint32_t getNTPOfSR() const { return ntohl(_lastReport) << 16u; }
|
||||
inline void setNTPOfSR(uint64_t ntp) { _lastReport = htonll(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 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_VERBOSE << "RTCP report block: "
|
||||
<< "ssrc="
|
||||
<< ntohl(ssrc)
|
||||
// TODO: Implement these reports
|
||||
// << ", fractionLost=" << fractionLost
|
||||
// << ", packetsLost=" << packetsLost
|
||||
<< ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles()
|
||||
<< ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR()
|
||||
<< ", lastSRDelay=" << getDelaySinceSR();
|
||||
}
|
||||
inline void log() const {
|
||||
PLOG_VERBOSE << "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;
|
||||
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 size_t lengthInBytes() const {
|
||||
return (1+length())*4;
|
||||
}
|
||||
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 size_t lengthInBytes() const { return (1 + length()) * 4; }
|
||||
|
||||
inline void setPayloadType(uint8_t type) { _payloadType = type; }
|
||||
inline void setReportCount(uint8_t count) { _first = (_first & 0b11100000u) | (count & 0b00011111u); }
|
||||
inline void setLength(uint16_t length) { _length = htons(length); }
|
||||
inline void setPayloadType(uint8_t type) { _payloadType = type; }
|
||||
inline void setReportCount(uint8_t count) {
|
||||
_first = (_first & 0b11100000u) | (count & 0b00011111u);
|
||||
}
|
||||
inline void setLength(uint16_t length) { _length = htons(length); }
|
||||
|
||||
inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) {
|
||||
_first = 0b10000000; // version 2, no padding
|
||||
setReportCount(reportCount);
|
||||
setPayloadType(payloadType);
|
||||
setLength(length);
|
||||
}
|
||||
inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) {
|
||||
_first = 0b10000000; // version 2, no padding
|
||||
setReportCount(reportCount);
|
||||
setPayloadType(payloadType);
|
||||
setLength(length);
|
||||
}
|
||||
|
||||
inline void log() const {
|
||||
PLOG_INFO << "RTCP header: "
|
||||
<< "version=" << unsigned(version()) << ", padding=" << padding()
|
||||
<< ", reportCount=" << unsigned(reportCount())
|
||||
<< ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
|
||||
}
|
||||
inline void log() const {
|
||||
PLOG_INFO << "RTCP header: "
|
||||
<< "version=" << unsigned(version()) << ", padding=" << padding()
|
||||
<< ", reportCount=" << unsigned(reportCount())
|
||||
<< ", payloadType=" << unsigned(payloadType()) << ", length=" << length();
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_FB_HEADER {
|
||||
RTCP_HEADER header;
|
||||
SSRC packetSender;
|
||||
SSRC mediaSource;
|
||||
RTCP_HEADER header;
|
||||
SSRC packetSender;
|
||||
SSRC mediaSource;
|
||||
|
||||
[[nodiscard]] SSRC getPacketSenderSSRC() const {
|
||||
return ntohl(packetSender);
|
||||
}
|
||||
[[nodiscard]] SSRC getPacketSenderSSRC() const { return ntohl(packetSender); }
|
||||
|
||||
[[nodiscard]] SSRC getMediaSourceSSRC() const {
|
||||
return ntohl(mediaSource);
|
||||
}
|
||||
[[nodiscard]] SSRC getMediaSourceSSRC() const { return ntohl(mediaSource); }
|
||||
|
||||
void setPacketSenderSSRC(SSRC ssrc) {
|
||||
this->packetSender = htonl(ssrc);
|
||||
}
|
||||
void setPacketSenderSSRC(SSRC ssrc) { this->packetSender = htonl(ssrc); }
|
||||
|
||||
void setMediaSourceSSRC(SSRC ssrc) {
|
||||
this->mediaSource = htonl(ssrc);
|
||||
}
|
||||
void setMediaSourceSSRC(SSRC ssrc) { this->mediaSource = htonl(ssrc); }
|
||||
|
||||
void log() {
|
||||
header.log();
|
||||
PLOG_VERBOSE << "FB: " << " packet sender: " << getPacketSenderSSRC() << " media source: " << getMediaSourceSSRC();
|
||||
}
|
||||
void log() {
|
||||
header.log();
|
||||
PLOG_VERBOSE << "FB: "
|
||||
<< " packet sender: " << getPacketSenderSSRC()
|
||||
<< " media source: " << getMediaSourceSSRC();
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_SR {
|
||||
RTCP_HEADER header;
|
||||
SSRC _senderSSRC;
|
||||
RTCP_HEADER header;
|
||||
SSRC _senderSSRC;
|
||||
|
||||
private:
|
||||
uint64_t _ntpTimestamp;
|
||||
uint32_t _rtpTimestamp;
|
||||
uint32_t _packetCount;
|
||||
uint32_t _octetCount;
|
||||
uint64_t _ntpTimestamp;
|
||||
uint32_t _rtpTimestamp;
|
||||
uint32_t _packetCount;
|
||||
uint32_t _octetCount;
|
||||
|
||||
RTCP_ReportBlock _reportBlocks;
|
||||
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 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; }
|
||||
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()));
|
||||
}
|
||||
[[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 uint64_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 uint32_t senderSSRC() const {return ntohl(_senderSSRC);}
|
||||
inline uint64_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 uint32_t senderSSRC() const { return ntohl(_senderSSRC); }
|
||||
|
||||
inline void setNtpTimestamp(uint32_t ts) { _ntpTimestamp = htonll(ts); }
|
||||
inline void setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); }
|
||||
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_VERBOSE << "RTCP SR: "
|
||||
<< " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp()
|
||||
<< ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount()
|
||||
<< ", octetCount=" << octetCount();
|
||||
inline void log() const {
|
||||
header.log();
|
||||
PLOG_VERBOSE << "RTCP SR: "
|
||||
<< " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp()
|
||||
<< ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount()
|
||||
<< ", octetCount=" << octetCount();
|
||||
|
||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
||||
getReportBlock(i)->log();
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
||||
getReportBlock(i)->log();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_RR {
|
||||
RTCP_HEADER header;
|
||||
SSRC _senderSSRC;
|
||||
RTCP_HEADER header;
|
||||
SSRC _senderSSRC;
|
||||
|
||||
private:
|
||||
RTCP_ReportBlock _reportBlocks;
|
||||
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 RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
|
||||
inline const RTCP_ReportBlock *getReportBlock(int num) const { return &_reportBlocks + num; }
|
||||
|
||||
inline SSRC senderSSRC() const { return ntohl(_senderSSRC); }
|
||||
inline void setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); }
|
||||
inline SSRC senderSSRC() 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()));
|
||||
}
|
||||
[[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 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 static size_t sizeWithReportBlocks(uint8_t reportCount) {
|
||||
return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock);
|
||||
}
|
||||
|
||||
inline bool isSenderReport() {
|
||||
return header.payloadType() == 200;
|
||||
}
|
||||
inline bool isSenderReport() { return header.payloadType() == 200; }
|
||||
|
||||
inline bool isReceiverReport() {
|
||||
return header.payloadType() == 201;
|
||||
}
|
||||
inline bool isReceiverReport() { return header.payloadType() == 201; }
|
||||
|
||||
inline void log() const {
|
||||
header.log();
|
||||
PLOG_VERBOSE << "RTCP RR: "
|
||||
<< " SSRC=" << ntohl(_senderSSRC);
|
||||
inline void log() const {
|
||||
header.log();
|
||||
PLOG_VERBOSE << "RTCP RR: "
|
||||
<< " SSRC=" << ntohl(_senderSSRC);
|
||||
|
||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
||||
getReportBlock(i)->log();
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
|
||||
getReportBlock(i)->log();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct RTCP_REMB {
|
||||
RTCP_FB_HEADER header;
|
||||
RTCP_FB_HEADER header;
|
||||
|
||||
/*! \brief Unique identifier ('R' 'E' 'M' 'B') */
|
||||
char id[4];
|
||||
/*! \brief Unique identifier ('R' 'E' 'M' 'B') */
|
||||
char id[4];
|
||||
|
||||
/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */
|
||||
uint32_t bitrate;
|
||||
/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */
|
||||
uint32_t bitrate;
|
||||
|
||||
SSRC ssrc[1];
|
||||
SSRC ssrc[1];
|
||||
|
||||
[[nodiscard]] unsigned int getSize() const {
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
return sizeof(uint32_t) * (1 + header.header.length());
|
||||
}
|
||||
[[nodiscard]] unsigned int getSize() const {
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
return sizeof(uint32_t) * (1 + header.header.length());
|
||||
}
|
||||
|
||||
void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int bitrate) {
|
||||
void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int bitrate) {
|
||||
|
||||
// Report Count becomes the format here.
|
||||
header.header.prepareHeader(206, 15, 0);
|
||||
// Report Count becomes the format here.
|
||||
header.header.prepareHeader(206, 15, 0);
|
||||
|
||||
// Always zero.
|
||||
header.setMediaSourceSSRC(0);
|
||||
// Always zero.
|
||||
header.setMediaSourceSSRC(0);
|
||||
|
||||
header.setPacketSenderSSRC(senderSSRC);
|
||||
header.setPacketSenderSSRC(senderSSRC);
|
||||
|
||||
id[0] = 'R';
|
||||
id[1] = 'E';
|
||||
id[2] = 'M';
|
||||
id[3] = 'B';
|
||||
id[0] = 'R';
|
||||
id[1] = 'E';
|
||||
id[2] = 'M';
|
||||
id[3] = 'B';
|
||||
|
||||
setBitrate(numSSRC, bitrate);
|
||||
}
|
||||
setBitrate(numSSRC, bitrate);
|
||||
}
|
||||
|
||||
void setBitrate(unsigned int numSSRC, unsigned int bitrate) {
|
||||
unsigned int exp = 0;
|
||||
while (bitrate > pow(2, 18) - 1) {
|
||||
exp++;
|
||||
bitrate /= 2;
|
||||
}
|
||||
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.header.setLength(uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
|
||||
// "length" in packet is one less than the number of 32 bit words in the packet.
|
||||
header.header.setLength(
|
||||
uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC));
|
||||
|
||||
this->bitrate = htonl(
|
||||
(numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | bitrate
|
||||
);
|
||||
}
|
||||
this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | bitrate);
|
||||
}
|
||||
|
||||
void setSsrc(int iterator, SSRC newSssrc){
|
||||
ssrc[iterator] = htonl(newSssrc);
|
||||
}
|
||||
void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); }
|
||||
|
||||
size_t static inline sizeWithSSRCs(int count) {
|
||||
return sizeof(RTCP_REMB) + (count-1)*sizeof(SSRC);
|
||||
}
|
||||
size_t static inline sizeWithSSRCs(int count) {
|
||||
return sizeof(RTCP_REMB) + (count - 1) * sizeof(SSRC);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct RTCP_PLI {
|
||||
RTCP_FB_HEADER header;
|
||||
RTCP_FB_HEADER header;
|
||||
|
||||
void preparePacket(SSRC messageSSRC) {
|
||||
header.header.prepareHeader(206, 1, 2);
|
||||
header.setPacketSenderSSRC(messageSSRC);
|
||||
header.setMediaSourceSSRC(messageSSRC);
|
||||
}
|
||||
void preparePacket(SSRC messageSSRC) {
|
||||
header.header.prepareHeader(206, 1, 2);
|
||||
header.setPacketSenderSSRC(messageSSRC);
|
||||
header.setMediaSourceSSRC(messageSSRC);
|
||||
}
|
||||
|
||||
void print() {
|
||||
header.log();
|
||||
}
|
||||
void print() { header.log(); }
|
||||
|
||||
[[nodiscard]] static unsigned int size() {
|
||||
return sizeof(RTCP_FB_HEADER);
|
||||
}
|
||||
[[nodiscard]] static unsigned int size() { return sizeof(RTCP_FB_HEADER); }
|
||||
};
|
||||
|
||||
struct RTCP_FIR_PART {
|
||||
uint32_t ssrc;
|
||||
uint32_t ssrc;
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
uint32_t seqNo: 8;
|
||||
uint32_t: 24;
|
||||
uint32_t seqNo : 8;
|
||||
uint32_t : 24;
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
uint32_t: 24;
|
||||
uint32_t seqNo: 8;
|
||||
uint32_t : 24;
|
||||
uint32_t seqNo : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RTCP_FIR {
|
||||
RTCP_FB_HEADER header;
|
||||
RTCP_FIR_PART parts[1];
|
||||
RTCP_FB_HEADER header;
|
||||
RTCP_FIR_PART parts[1];
|
||||
|
||||
void preparePacket(SSRC messageSSRC, uint8_t seqNo) {
|
||||
header.header.prepareHeader(206, 4, 2 + 2 * 1);
|
||||
header.setPacketSenderSSRC(messageSSRC);
|
||||
header.setMediaSourceSSRC(messageSSRC);
|
||||
parts[0].ssrc = htonl(messageSSRC);
|
||||
parts[0].seqNo = seqNo;
|
||||
}
|
||||
void preparePacket(SSRC messageSSRC, uint8_t seqNo) {
|
||||
header.header.prepareHeader(206, 4, 2 + 2 * 1);
|
||||
header.setPacketSenderSSRC(messageSSRC);
|
||||
header.setMediaSourceSSRC(messageSSRC);
|
||||
parts[0].ssrc = htonl(messageSSRC);
|
||||
parts[0].seqNo = seqNo;
|
||||
}
|
||||
|
||||
void print() {
|
||||
header.log();
|
||||
}
|
||||
void print() { header.log(); }
|
||||
|
||||
[[nodiscard]] static unsigned int size() {
|
||||
return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART);
|
||||
}
|
||||
[[nodiscard]] static unsigned int size() {
|
||||
return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART);
|
||||
}
|
||||
};
|
||||
|
||||
struct RTCP_NACK_PART {
|
||||
uint16_t pid;
|
||||
uint16_t blp;
|
||||
uint16_t pid;
|
||||
uint16_t blp;
|
||||
};
|
||||
|
||||
class RTCP_NACK {
|
||||
public:
|
||||
RTCP_FB_HEADER header;
|
||||
RTCP_NACK_PART parts[1];
|
||||
RTCP_FB_HEADER header;
|
||||
RTCP_NACK_PART parts[1];
|
||||
|
||||
public:
|
||||
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
|
||||
header.header.prepareHeader(205, 1, 2 + discreteSeqNoCount);
|
||||
header.setMediaSourceSSRC(ssrc);
|
||||
header.setPacketSenderSSRC(ssrc);
|
||||
}
|
||||
void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) {
|
||||
header.header.prepareHeader(205, 1, 2 + discreteSeqNoCount);
|
||||
header.setMediaSourceSSRC(ssrc);
|
||||
header.setPacketSenderSSRC(ssrc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a packet to the list of missing packets.
|
||||
* @param fciCount The number of FCI fields that are present in this packet.
|
||||
* Let the number start at zero and let this function grow the number.
|
||||
* @param fciPID The seq no of the active FCI. It will be initialized automatically, and will change automatically.
|
||||
* @param missingPacket The seq no of the missing packet. This will be added to the queue.
|
||||
* @return true if the packet has grown, false otherwise.
|
||||
*/
|
||||
bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, const uint16_t &missingPacket) {
|
||||
if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) {
|
||||
parts[*fciCount].pid = htons(missingPacket);
|
||||
parts[*fciCount].blp = 0;
|
||||
*fciPID = missingPacket;
|
||||
(*fciCount)++;
|
||||
return true;
|
||||
} else {
|
||||
// TODO SPEEED!
|
||||
parts[(*fciCount) - 1].blp = htons(
|
||||
ntohs(parts[(*fciCount) - 1].blp) | (1u << (unsigned int) (missingPacket - *fciPID)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add a packet to the list of missing packets.
|
||||
* @param fciCount The number of FCI fields that are present in this packet.
|
||||
* Let the number start at zero and let this function grow the number.
|
||||
* @param fciPID The seq no of the active FCI. It will be initialized automatically, and will
|
||||
* change automatically.
|
||||
* @param missingPacket The seq no of the missing packet. This will be added to the queue.
|
||||
* @return true if the packet has grown, false otherwise.
|
||||
*/
|
||||
bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, const uint16_t &missingPacket) {
|
||||
if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) {
|
||||
parts[*fciCount].pid = htons(missingPacket);
|
||||
parts[*fciCount].blp = 0;
|
||||
*fciPID = missingPacket;
|
||||
(*fciCount)++;
|
||||
return true;
|
||||
} else {
|
||||
// TODO SPEEED!
|
||||
parts[(*fciCount) - 1].blp = htons(ntohs(parts[(*fciCount) - 1].blp) |
|
||||
(1u << (unsigned int)(missingPacket - *fciPID)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static unsigned int getSize(unsigned int discreteSeqNoCount) {
|
||||
return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount;
|
||||
}
|
||||
[[nodiscard]] static unsigned int getSize(unsigned int discreteSeqNoCount) {
|
||||
return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount;
|
||||
}
|
||||
|
||||
[[nodiscard]] unsigned int getSeqNoCount() {
|
||||
return header.header.length() - 2;
|
||||
}
|
||||
[[nodiscard]] unsigned int getSeqNoCount() { return header.header.length() - 2; }
|
||||
};
|
||||
|
||||
class RTP_RTX {
|
||||
private:
|
||||
RTP header;
|
||||
RTP header;
|
||||
|
||||
public:
|
||||
size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) {
|
||||
memmove((char *)dest, (char *)this, header.getSize());
|
||||
dest->setSeqNumber(getOriginalSeqNo());
|
||||
dest->setPayloadType(originalPayloadType);
|
||||
memmove(dest->getBody(), getBody(), getBodySize(totalSize));
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) {
|
||||
memmove((char*)dest, (char*)this, header.getSize());
|
||||
dest->setSeqNumber(getOriginalSeqNo());
|
||||
dest->setPayloadType(originalPayloadType);
|
||||
memmove(dest->getBody(), getBody(), getBodySize(totalSize));
|
||||
return totalSize;
|
||||
}
|
||||
[[nodiscard]] uint16_t getOriginalSeqNo() const {
|
||||
return ntohs(*(uint16_t *)(header.getBody()));
|
||||
}
|
||||
|
||||
[[nodiscard]] uint16_t getOriginalSeqNo() const {
|
||||
return ntohs(*(uint16_t *) (header.getBody()));
|
||||
}
|
||||
char *getBody() { return header.getBody() + sizeof(uint16_t); }
|
||||
|
||||
char *getBody() {
|
||||
return header.getBody() + sizeof(uint16_t);
|
||||
}
|
||||
size_t getBodySize(size_t totalSize) { return totalSize - ((char *)getBody() - (char *)this); }
|
||||
|
||||
size_t getBodySize(size_t totalSize) {
|
||||
return totalSize - ((char *) getBody() - (char *) this);
|
||||
}
|
||||
RTP &getHeader() { return header; }
|
||||
|
||||
RTP &getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) {
|
||||
header.setSeqNumber(getOriginalSeqNo());
|
||||
header.setSsrc(originalSSRC); // TODO Endianess
|
||||
header.setPayloadType(originalPayloadType);
|
||||
// TODO, the -12 is the size of the header (which is variable!)
|
||||
memmove(header.getBody(), header.getBody() + sizeof(uint16_t), totalSize - 12 - sizeof(uint16_t));
|
||||
return totalSize - sizeof(uint16_t);
|
||||
}
|
||||
size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) {
|
||||
header.setSeqNumber(getOriginalSeqNo());
|
||||
header.setSsrc(originalSSRC); // TODO Endianess
|
||||
header.setPayloadType(originalPayloadType);
|
||||
// TODO, the -12 is the size of the header (which is variable!)
|
||||
memmove(header.getBody(), header.getBody() + sizeof(uint16_t),
|
||||
totalSize - 12 - sizeof(uint16_t));
|
||||
return totalSize - sizeof(uint16_t);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(pop)
|
||||
};
|
||||
#endif //WEBRTC_SERVER_RTP_HPP
|
||||
}; // namespace rtc
|
||||
#endif // WEBRTC_SERVER_RTP_HPP
|
||||
|
@ -80,10 +80,8 @@ private:
|
||||
std::shared_ptr<RtcpHandler> mRtcpHandler;
|
||||
|
||||
friend class PeerConnection;
|
||||
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -25,8 +25,7 @@ namespace rtc {
|
||||
using std::to_integer;
|
||||
|
||||
string to_base64(const binary &data) {
|
||||
static const char tab[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
string out;
|
||||
out.reserve(3 * ((data.size() + 3) / 4));
|
||||
|
@ -61,9 +61,8 @@ Candidate::Candidate(string candidate) : Candidate() {
|
||||
mCandidate = std::move(candidate);
|
||||
}
|
||||
|
||||
Candidate::Candidate(string candidate, string mid)
|
||||
: Candidate(std::move(candidate)) {
|
||||
if(!mid.empty())
|
||||
Candidate::Candidate(string candidate, string mid) : Candidate(std::move(candidate)) {
|
||||
if (!mid.empty())
|
||||
mMid.emplace(std::move(mid));
|
||||
}
|
||||
|
||||
|
@ -304,9 +304,7 @@ int rtcDeletePeerConnection(int pc) {
|
||||
});
|
||||
}
|
||||
|
||||
int rtcAddDataChannel(int pc, const char *label) {
|
||||
return rtcAddDataChannelEx(pc, label, nullptr);
|
||||
}
|
||||
int rtcAddDataChannel(int pc, const char *label) { return rtcAddDataChannelEx(pc, label, nullptr); }
|
||||
|
||||
int rtcAddDataChannelEx(int pc, const char *label, const rtcDataChannelInit *init) {
|
||||
return WRAP({
|
||||
|
@ -153,22 +153,23 @@ Certificate::Certificate(string crt_pem, string key_pem) {
|
||||
mFingerprint = make_fingerprint(mX509.get());
|
||||
}
|
||||
|
||||
Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey) :
|
||||
mX509(std::move(x509)), mPKey(std::move(pkey))
|
||||
{
|
||||
Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey)
|
||||
: mX509(std::move(x509)), mPKey(std::move(pkey)) {
|
||||
mFingerprint = make_fingerprint(mX509.get());
|
||||
}
|
||||
|
||||
string Certificate::fingerprint() const { return mFingerprint; }
|
||||
|
||||
std::tuple<X509 *, EVP_PKEY *> Certificate::credentials() const { return {mX509.get(), mPKey.get()}; }
|
||||
std::tuple<X509 *, EVP_PKEY *> Certificate::credentials() const {
|
||||
return {mX509.get(), mPKey.get()};
|
||||
}
|
||||
|
||||
string make_fingerprint(X509 *x509) {
|
||||
const size_t size = 32;
|
||||
unsigned char buffer[size];
|
||||
unsigned int len = size;
|
||||
if (!X509_digest(x509, EVP_sha256(), buffer, &len))
|
||||
throw std::runtime_error("X509 fingerprint error");
|
||||
unsigned char buffer[size];
|
||||
unsigned int len = size;
|
||||
if (!X509_digest(x509, EVP_sha256(), buffer, &len))
|
||||
throw std::runtime_error("X509 fingerprint error");
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::uppercase << std::setfill('0');
|
||||
@ -186,10 +187,10 @@ certificate_ptr make_certificate_impl(string commonName) {
|
||||
shared_ptr<X509> x509(X509_new(), X509_free);
|
||||
shared_ptr<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free);
|
||||
|
||||
unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), RSA_free);
|
||||
unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), RSA_free);
|
||||
unique_ptr<BIGNUM, decltype(&BN_free)> exponent(BN_new(), BN_free);
|
||||
unique_ptr<BIGNUM, decltype(&BN_free)> serial_number(BN_new(), BN_free);
|
||||
unique_ptr<X509_NAME, decltype(&X509_NAME_free)> name(X509_NAME_new(), X509_NAME_free);
|
||||
unique_ptr<X509_NAME, decltype(&X509_NAME_free)> name(X509_NAME_new(), X509_NAME_free);
|
||||
|
||||
if (!x509 || !pkey || !rsa || !exponent || !serial_number || !name)
|
||||
throw std::runtime_error("Unable allocate structures for certificate generation");
|
||||
|
@ -26,13 +26,9 @@ size_t Channel::bufferedAmount() const { return mBufferedAmount; }
|
||||
|
||||
size_t Channel::availableAmount() const { return 0; }
|
||||
|
||||
void Channel::onOpen(std::function<void()> callback) {
|
||||
mOpenCallback = callback;
|
||||
}
|
||||
void Channel::onOpen(std::function<void()> callback) { mOpenCallback = callback; }
|
||||
|
||||
void Channel::onClosed(std::function<void()> callback) {
|
||||
mClosedCallback = callback;
|
||||
}
|
||||
void Channel::onClosed(std::function<void()> callback) { mClosedCallback = callback; }
|
||||
|
||||
void Channel::onError(std::function<void(string error)> callback) { mErrorCallback = callback; }
|
||||
|
||||
@ -57,9 +53,7 @@ void Channel::onBufferedAmountLow(std::function<void()> callback) {
|
||||
|
||||
void Channel::setBufferedAmountLowThreshold(size_t amount) { mBufferedAmountLowThreshold = amount; }
|
||||
|
||||
void Channel::onAvailable(std::function<void()> callback) {
|
||||
mAvailableCallback = callback;
|
||||
}
|
||||
void Channel::onAvailable(std::function<void()> callback) { mAvailableCallback = callback; }
|
||||
|
||||
void Channel::triggerOpen() { mOpenCallback(); }
|
||||
|
||||
@ -96,4 +90,3 @@ void Channel::resetCallbacks() {
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -137,8 +137,8 @@ Description::Description(const string &sdp, Type type, Role role)
|
||||
}
|
||||
|
||||
Description::Description(const string &sdp, string typeString)
|
||||
: Description(sdp, !typeString.empty() ? stringToType(typeString) : Type::Unspec, Role::ActPass) {
|
||||
}
|
||||
: Description(sdp, !typeString.empty() ? stringToType(typeString) : Type::Unspec,
|
||||
Role::ActPass) {}
|
||||
|
||||
Description::Type Description::type() const { return mType; }
|
||||
|
||||
@ -177,7 +177,7 @@ void Description::addCandidate(Candidate candidate) {
|
||||
}
|
||||
|
||||
void Description::addCandidates(std::vector<Candidate> candidates) {
|
||||
for(Candidate candidate : candidates) {
|
||||
for (Candidate candidate : candidates) {
|
||||
candidate.hintMid(bundleMid());
|
||||
mCandidates.emplace_back(std::move(candidate));
|
||||
}
|
||||
@ -385,7 +385,8 @@ int Description::addAudio(string mid, Direction dir) {
|
||||
return addMedia(Audio(std::move(mid), dir));
|
||||
}
|
||||
|
||||
std::variant<Description::Media *, Description::Application *> Description::media(unsigned int index) {
|
||||
std::variant<Description::Media *, Description::Application *>
|
||||
Description::media(unsigned int index) {
|
||||
if (index >= mEntries.size())
|
||||
throw std::out_of_range("Media index out of range");
|
||||
|
||||
@ -432,7 +433,6 @@ Description::Entry::Entry(const string &mline, string mid, Direction dir)
|
||||
ss >> mType;
|
||||
ss >> port; // ignored
|
||||
ss >> mDescription;
|
||||
|
||||
}
|
||||
|
||||
void Description::Entry::setDirection(Direction dir) { mDirection = dir; }
|
||||
@ -472,9 +472,10 @@ string Description::Entry::generateSdpLines(string_view eol) const {
|
||||
}
|
||||
|
||||
for (const auto &attr : mAttributes) {
|
||||
if (attr.find("extmap") == std::string::npos && attr.find("rtcp-rsize") == std::string::npos)
|
||||
sdp << "a=" << attr << eol;
|
||||
}
|
||||
if (attr.find("extmap") == std::string::npos &&
|
||||
attr.find("rtcp-rsize") == std::string::npos)
|
||||
sdp << "a=" << attr << eol;
|
||||
}
|
||||
|
||||
return sdp.str();
|
||||
}
|
||||
@ -500,38 +501,35 @@ void Description::Entry::parseSdpLine(string_view line) {
|
||||
mAttributes.emplace_back(line.substr(2));
|
||||
}
|
||||
}
|
||||
std::vector< string>::iterator Description::Entry::beginAttributes() {
|
||||
return mAttributes.begin();
|
||||
}
|
||||
std::vector< string>::iterator Description::Entry::endAttributes() {
|
||||
return mAttributes.end();
|
||||
}
|
||||
std::vector< string>::iterator Description::Entry::removeAttribute(std::vector<string>::iterator it) {
|
||||
return mAttributes.erase(it);
|
||||
std::vector<string>::iterator Description::Entry::beginAttributes() { return mAttributes.begin(); }
|
||||
std::vector<string>::iterator Description::Entry::endAttributes() { return mAttributes.end(); }
|
||||
std::vector<string>::iterator
|
||||
Description::Entry::removeAttribute(std::vector<string>::iterator it) {
|
||||
return mAttributes.erase(it);
|
||||
}
|
||||
|
||||
void Description::Media::addSSRC(uint32_t ssrc, std::string name) {
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + name);
|
||||
mSsrcs.emplace_back(ssrc);
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + name);
|
||||
mSsrcs.emplace_back(ssrc);
|
||||
}
|
||||
|
||||
void Description::Media::replaceSSRC(uint32_t oldSSRC, uint32_t ssrc, std::string name) {
|
||||
auto it = mAttributes.begin();
|
||||
while (it != mAttributes.end()) {
|
||||
if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) {
|
||||
it = mAttributes.erase(it);
|
||||
}else
|
||||
it++;
|
||||
}
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + name);
|
||||
auto it = mAttributes.begin();
|
||||
while (it != mAttributes.end()) {
|
||||
if (it->find("ssrc:" + std::to_string(oldSSRC)) == 0) {
|
||||
it = mAttributes.erase(it);
|
||||
} else
|
||||
it++;
|
||||
}
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc) + " cname:" + name);
|
||||
}
|
||||
|
||||
void Description::Media::addSSRC(uint32_t ssrc) {
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc));
|
||||
mAttributes.emplace_back("ssrc:" + std::to_string(ssrc));
|
||||
}
|
||||
|
||||
bool Description::Media::hasSSRC(uint32_t ssrc) {
|
||||
return std::find(mSsrcs.begin(), mSsrcs.end(), ssrc) != mSsrcs.end();
|
||||
return std::find(mSsrcs.begin(), mSsrcs.end(), ssrc) != mSsrcs.end();
|
||||
}
|
||||
|
||||
Description::Application::Application(string mid)
|
||||
@ -682,48 +680,48 @@ void Description::Media::removeFormat(const string &fmt) {
|
||||
|
||||
void Description::Video::addVideoCodec(int payloadType, const string &codec) {
|
||||
RTPMap map(std::to_string(payloadType) + ' ' + codec + "/90000");
|
||||
map.addFB("nack");
|
||||
map.addFB("nack pli");
|
||||
// map.addFB("nack fir");
|
||||
map.addFB("nack");
|
||||
map.addFB("nack pli");
|
||||
// map.addFB("nack fir");
|
||||
map.addFB("goog-remb");
|
||||
if (codec == "H264") {
|
||||
// Use Constrained Baseline profile Level 4.2 (necessary for Firefox)
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#Supported_video_codecs
|
||||
// TODO: Should be 42E0 but 42C0 appears to be more compatible. Investigate this.
|
||||
map.fmtps.emplace_back("profile-level-id=4de01f;packetization-mode=1;level-asymmetry-allowed=1");
|
||||
map.fmtps.emplace_back(
|
||||
"profile-level-id=4de01f;packetization-mode=1;level-asymmetry-allowed=1");
|
||||
|
||||
// Because certain Android devices don't like me, let us just negotiate some random
|
||||
{
|
||||
RTPMap map(std::to_string(payloadType+1) + ' ' + codec + "/90000");
|
||||
RTPMap map(std::to_string(payloadType + 1) + ' ' + codec + "/90000");
|
||||
map.addFB("nack");
|
||||
map.addFB("nack pli");
|
||||
// map.addFB("nack fir");
|
||||
map.addFB("nack pli");
|
||||
// map.addFB("nack fir");
|
||||
map.addFB("goog-remb");
|
||||
addRTPMap(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
addRTPMap(map);
|
||||
|
||||
|
||||
// // RTX Packets
|
||||
/* TODO
|
||||
* TIL that Firefox does not properly support the negotiation of RTX! It works, but doesn't negotiate the SSRC so
|
||||
* we have no idea what SSRC is RTX going to be. Three solutions:
|
||||
* One) we don't negotitate it and (maybe) break RTX support with Edge.
|
||||
* Two) we do negotiate it and rebuild the original packet before we send it distribute it to each track.
|
||||
* Three) we complain to mozilla. This one probably won't do much.
|
||||
*/
|
||||
// RTPMap rtx(std::to_string(payloadType+1) + " rtx/90000");
|
||||
// // TODO rtx-time is how long can a request be stashed for before needing to resend it. Needs to be parameterized
|
||||
// rtx.addAttribute("apt=" + std::to_string(payloadType) + ";rtx-time=3000");
|
||||
// addRTPMap(rtx);
|
||||
// // RTX Packets
|
||||
/* TODO
|
||||
* TIL that Firefox does not properly support the negotiation of RTX! It works, but doesn't
|
||||
* negotiate the SSRC so we have no idea what SSRC is RTX going to be. Three solutions: One) we
|
||||
* don't negotitate it and (maybe) break RTX support with Edge. Two) we do negotiate it and
|
||||
* rebuild the original packet before we send it distribute it to each track. Three) we complain
|
||||
* to mozilla. This one probably won't do much.
|
||||
*/
|
||||
// RTPMap rtx(std::to_string(payloadType+1) + " rtx/90000");
|
||||
// // TODO rtx-time is how long can a request be stashed for before needing to resend it.
|
||||
// Needs to be parameterized rtx.addAttribute("apt=" + std::to_string(payloadType) +
|
||||
// ";rtx-time=3000"); addRTPMap(rtx);
|
||||
}
|
||||
|
||||
void Description::Audio::addAudioCodec(int payloadType, const string &codec) {
|
||||
// TODO This 48000/2 should be parameterized
|
||||
RTPMap map(std::to_string(payloadType) + ' ' + codec + "/48000/2");
|
||||
map.fmtps.emplace_back("maxaveragebitrate=96000; stereo=1; sprop-stereo=1; useinbandfec=1");
|
||||
addRTPMap(map);
|
||||
// TODO This 48000/2 should be parameterized
|
||||
RTPMap map(std::to_string(payloadType) + ' ' + codec + "/48000/2");
|
||||
map.fmtps.emplace_back("maxaveragebitrate=96000; stereo=1; sprop-stereo=1; useinbandfec=1");
|
||||
addRTPMap(map);
|
||||
}
|
||||
|
||||
void Description::Video::addH264Codec(int pt) { addVideoCodec(pt, "H264"); }
|
||||
@ -758,9 +756,9 @@ string Description::Media::generateSdpLines(string_view eol) const {
|
||||
sdp << eol;
|
||||
|
||||
for (const auto &val : map.rtcpFbs) {
|
||||
if (val != "transport-cc" )
|
||||
sdp << "a=rtcp-fb:" << map.pt << ' ' << val << eol;
|
||||
}
|
||||
if (val != "transport-cc")
|
||||
sdp << "a=rtcp-fb:" << map.pt << ' ' << val << eol;
|
||||
}
|
||||
for (const auto &val : map.fmtps)
|
||||
sdp << "a=fmtp:" << map.pt << ' ' << val << eol;
|
||||
}
|
||||
@ -774,32 +772,32 @@ void Description::Media::parseSdpLine(string_view line) {
|
||||
auto [key, value] = parse_pair(attr);
|
||||
|
||||
if (key == "rtpmap") {
|
||||
auto pt = Description::Media::RTPMap::parsePT(value);
|
||||
auto it = mRtpMap.find(pt);
|
||||
if (it == mRtpMap.end()) {
|
||||
it = mRtpMap.insert(std::make_pair(pt, Description::Media::RTPMap(value))).first;
|
||||
}else {
|
||||
it->second.setMLine(value);
|
||||
}
|
||||
auto pt = Description::Media::RTPMap::parsePT(value);
|
||||
auto it = mRtpMap.find(pt);
|
||||
if (it == mRtpMap.end()) {
|
||||
it = mRtpMap.insert(std::make_pair(pt, Description::Media::RTPMap(value))).first;
|
||||
} else {
|
||||
it->second.setMLine(value);
|
||||
}
|
||||
} else if (key == "rtcp-fb") {
|
||||
size_t p = value.find(' ');
|
||||
int pt = to_integer<int>(value.substr(0, p));
|
||||
auto it = mRtpMap.find(pt);
|
||||
if (it == mRtpMap.end()) {
|
||||
it = mRtpMap.insert(std::make_pair(pt, Description::Media::RTPMap())).first;
|
||||
}
|
||||
it->second.rtcpFbs.emplace_back(value.substr(p + 1));
|
||||
it = mRtpMap.insert(std::make_pair(pt, Description::Media::RTPMap())).first;
|
||||
}
|
||||
it->second.rtcpFbs.emplace_back(value.substr(p + 1));
|
||||
} else if (key == "fmtp") {
|
||||
size_t p = value.find(' ');
|
||||
int pt = to_integer<int>(value.substr(0, p));
|
||||
auto it = mRtpMap.find(pt);
|
||||
if (it == mRtpMap.end())
|
||||
it = mRtpMap.insert(std::make_pair(pt, Description::Media::RTPMap())).first;
|
||||
it->second.fmtps.emplace_back(value.substr(p + 1));
|
||||
it = mRtpMap.insert(std::make_pair(pt, Description::Media::RTPMap())).first;
|
||||
it->second.fmtps.emplace_back(value.substr(p + 1));
|
||||
} else if (key == "rtcp-mux") {
|
||||
// always added
|
||||
}else if (key == "ssrc") {
|
||||
mSsrcs.emplace_back(std::stoul((std::string)value));
|
||||
// always added
|
||||
} else if (key == "ssrc") {
|
||||
mSsrcs.emplace_back(std::stoul((std::string)value));
|
||||
} else {
|
||||
Entry::parseSdpLine(line);
|
||||
}
|
||||
@ -810,37 +808,35 @@ void Description::Media::parseSdpLine(string_view line) {
|
||||
}
|
||||
}
|
||||
|
||||
void Description::Media::addRTPMap(const Description::Media::RTPMap& map) {
|
||||
mRtpMap.emplace(map.pt, map);
|
||||
void Description::Media::addRTPMap(const Description::Media::RTPMap &map) {
|
||||
mRtpMap.emplace(map.pt, map);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Description::Media::getSSRCs() {
|
||||
std::vector<uint32_t> vec;
|
||||
for (auto &val : mAttributes) {
|
||||
PLOG_DEBUG << val;
|
||||
if (val.find("ssrc:") == 0) {
|
||||
vec.emplace_back(std::stoul((std::string)val.substr(5, val.find(" "))));
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
std::vector<uint32_t> vec;
|
||||
for (auto &val : mAttributes) {
|
||||
PLOG_DEBUG << val;
|
||||
if (val.find("ssrc:") == 0) {
|
||||
vec.emplace_back(std::stoul((std::string)val.substr(5, val.find(" "))));
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::map<int, Description::Media::RTPMap>::iterator Description::Media::beginMaps() {
|
||||
return mRtpMap.begin();
|
||||
return mRtpMap.begin();
|
||||
}
|
||||
|
||||
std::map<int, Description::Media::RTPMap>::iterator Description::Media::endMaps() {
|
||||
return mRtpMap.end();
|
||||
return mRtpMap.end();
|
||||
}
|
||||
|
||||
std::map<int, Description::Media::RTPMap>::iterator
|
||||
Description::Media::removeMap(std::map<int, Description::Media::RTPMap>::iterator iterator) {
|
||||
return mRtpMap.erase(iterator);
|
||||
return mRtpMap.erase(iterator);
|
||||
}
|
||||
|
||||
Description::Media::RTPMap::RTPMap(string_view mline) {
|
||||
setMLine(mline);
|
||||
}
|
||||
Description::Media::RTPMap::RTPMap(string_view mline) { setMLine(mline); }
|
||||
|
||||
void Description::Media::RTPMap::removeFB(const string &str) {
|
||||
auto it = rtcpFbs.begin();
|
||||
@ -855,39 +851,37 @@ void Description::Media::RTPMap::removeFB(const string &str) {
|
||||
void Description::Media::RTPMap::addFB(const string &str) { rtcpFbs.emplace_back(str); }
|
||||
|
||||
int Description::Media::RTPMap::parsePT(string_view view) {
|
||||
size_t p = view.find(' ');
|
||||
size_t p = view.find(' ');
|
||||
|
||||
return to_integer<int>(view.substr(0, p));
|
||||
return to_integer<int>(view.substr(0, p));
|
||||
}
|
||||
|
||||
void Description::Media::RTPMap::setMLine(string_view mline) {
|
||||
size_t p = mline.find(' ');
|
||||
size_t p = mline.find(' ');
|
||||
|
||||
this->pt = to_integer<int>(mline.substr(0, p));
|
||||
this->pt = to_integer<int>(mline.substr(0, p));
|
||||
|
||||
string_view line = mline.substr(p + 1);
|
||||
size_t spl = line.find('/');
|
||||
this->format = line.substr(0, spl);
|
||||
string_view line = mline.substr(p + 1);
|
||||
size_t spl = line.find('/');
|
||||
this->format = line.substr(0, spl);
|
||||
|
||||
line = line.substr(spl + 1);
|
||||
spl = line.find('/');
|
||||
if (spl == string::npos) {
|
||||
spl = line.find(' ');
|
||||
}
|
||||
if (spl == string::npos)
|
||||
this->clockRate = to_integer<int>(line);
|
||||
else {
|
||||
this->clockRate = to_integer<int>(line.substr(0, spl));
|
||||
this->encParams = line.substr(spl+1);
|
||||
}
|
||||
line = line.substr(spl + 1);
|
||||
spl = line.find('/');
|
||||
if (spl == string::npos) {
|
||||
spl = line.find(' ');
|
||||
}
|
||||
if (spl == string::npos)
|
||||
this->clockRate = to_integer<int>(line);
|
||||
else {
|
||||
this->clockRate = to_integer<int>(line.substr(0, spl));
|
||||
this->encParams = line.substr(spl + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Description::Audio::Audio(string mid, Direction dir)
|
||||
: Media("audio 9 UDP/TLS/RTP/SAVPF", std::move(mid), dir) {}
|
||||
|
||||
void Description::Audio::addOpusCodec(int payloadType) {
|
||||
addAudioCodec(payloadType, "OPUS");
|
||||
}
|
||||
void Description::Audio::addOpusCodec(int payloadType) { addAudioCodec(payloadType, "OPUS"); }
|
||||
|
||||
Description::Video::Video(string mid, Direction dir)
|
||||
: Media("video 9 UDP/TLS/RTP/SAVPF", std::move(mid), dir) {}
|
||||
|
@ -110,31 +110,30 @@ bool DtlsSrtpTransport::sendMedia(message_ptr message) {
|
||||
if (err == srtp_err_status_replay_fail)
|
||||
throw std::runtime_error("SRTCP packet is a replay");
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTCP_SR*) message->data())->senderSSRC();
|
||||
PLOG_INFO << "Adding SSRC to SRTCP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_protect_rtcp(mSrtpOut, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}else {
|
||||
throw std::runtime_error("SRTCP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
auto ssrc = ((RTCP_SR *)message->data())->senderSSRC();
|
||||
PLOG_INFO << "Adding SSRC to SRTCP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_protect_rtcp(mSrtpOut, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
} else {
|
||||
throw std::runtime_error("SRTCP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
}
|
||||
PLOG_VERBOSE << "Protected SRTCP packet, size=" << size;
|
||||
} else {
|
||||
if (srtp_err_status_t err = srtp_protect(mSrtpOut, message->data(), &size)) {
|
||||
if (err == srtp_err_status_replay_fail)
|
||||
throw std::runtime_error("Outgoing SRTP packet is a replay");
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTP*) message->data())->ssrc();
|
||||
PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_protect_rtcp(mSrtpOut, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
else
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTP *)message->data())->ssrc();
|
||||
PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_protect_rtcp(mSrtpOut, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
} else
|
||||
throw std::runtime_error("SRTP protect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
@ -189,23 +188,22 @@ void DtlsSrtpTransport::incoming(message_ptr message) {
|
||||
PLOG_WARNING << "Incoming SRTCP packet is a replay";
|
||||
else if (err == srtp_err_status_auth_fail)
|
||||
PLOG_WARNING << "Incoming SRTCP packet failed authentication check";
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTCP_SR*) message->data())->senderSSRC();
|
||||
PLOG_INFO << "Adding SSRC to RTCP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_unprotect_rtcp(mSrtpIn, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP unprotect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
else {
|
||||
PLOG_WARNING << "SRTCP unprotect error, status=" << err << " SSRC="
|
||||
<< ((RTCP_SR *) message->data())->senderSSRC();
|
||||
}
|
||||
return;
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTCP_SR *)message->data())->senderSSRC();
|
||||
PLOG_INFO << "Adding SSRC to RTCP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_unprotect_rtcp(mSrtpIn, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP unprotect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
} else {
|
||||
PLOG_WARNING << "SRTCP unprotect error, status=" << err
|
||||
<< " SSRC=" << ((RTCP_SR *)message->data())->senderSSRC();
|
||||
}
|
||||
return;
|
||||
}
|
||||
PLOG_VERBOSE << "Unprotected SRTCP packet, size=" << size;
|
||||
message->type = Message::Type::Control;
|
||||
auto rtp = (RTCP_SR*) message->data();
|
||||
auto rtp = (RTCP_SR *)message->data();
|
||||
message->stream = rtp->senderSSRC();
|
||||
} else {
|
||||
PLOG_VERBOSE << "Incoming SRTP packet, size=" << size;
|
||||
@ -214,21 +212,21 @@ void DtlsSrtpTransport::incoming(message_ptr message) {
|
||||
PLOG_WARNING << "Incoming SRTP packet is a replay";
|
||||
else if (err == srtp_err_status_auth_fail)
|
||||
PLOG_WARNING << "Incoming SRTP packet failed authentication check";
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTP*) message->data())->ssrc();
|
||||
PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_unprotect(mSrtpIn, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP unprotect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
else
|
||||
PLOG_WARNING << "SRTP unprotect error, status=" << err << " SSRC=" << ((RTP*)message->data())->ssrc();
|
||||
else if (err == srtp_err_status_no_ctx) {
|
||||
auto ssrc = ((RTP *)message->data())->ssrc();
|
||||
PLOG_INFO << "Adding SSRC to RTP: " << ssrc;
|
||||
addSSRC(ssrc);
|
||||
if ((err = srtp_unprotect(mSrtpIn, message->data(), &size)))
|
||||
throw std::runtime_error("SRTCP unprotect error, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
} else
|
||||
PLOG_WARNING << "SRTP unprotect error, status=" << err
|
||||
<< " SSRC=" << ((RTP *)message->data())->ssrc();
|
||||
return;
|
||||
}
|
||||
PLOG_VERBOSE << "Unprotected SRTP packet, size=" << size;
|
||||
message->type = Message::Type::Binary;
|
||||
auto rtp = (RTP*) message->data();
|
||||
auto rtp = (RTP *)message->data();
|
||||
message->stream = rtp->ssrc();
|
||||
}
|
||||
|
||||
@ -301,18 +299,18 @@ void DtlsSrtpTransport::postHandshake() {
|
||||
std::memcpy(mServerSessionKey + SRTP_AES_128_KEY_LEN, serverSalt, SRTP_SALT_LEN);
|
||||
|
||||
// Add SSRC=1 as an inbound because that is what Chrome does.
|
||||
srtp_policy_t inbound = {};
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtcp);
|
||||
inbound.ssrc.type = ssrc_specific;
|
||||
inbound.ssrc.value = 1;
|
||||
inbound.key = mIsClient ? mServerSessionKey : mClientSessionKey;
|
||||
inbound.next = nullptr;
|
||||
srtp_policy_t inbound = {};
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtcp);
|
||||
inbound.ssrc.type = ssrc_specific;
|
||||
inbound.ssrc.value = 1;
|
||||
inbound.key = mIsClient ? mServerSessionKey : mClientSessionKey;
|
||||
inbound.next = nullptr;
|
||||
|
||||
if (srtp_err_status_t err = srtp_add_stream(mSrtpIn, &inbound)) {
|
||||
throw std::runtime_error("SRTP add inbound stream failed, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
if (srtp_err_status_t err = srtp_add_stream(mSrtpIn, &inbound)) {
|
||||
throw std::runtime_error("SRTP add inbound stream failed, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
|
||||
mInitDone = true;
|
||||
}
|
||||
@ -321,34 +319,33 @@ void DtlsSrtpTransport::addSSRC(uint32_t ssrc) {
|
||||
if (!mInitDone)
|
||||
throw std::logic_error("Attempted to add SSRC before SRTP keying material is derived");
|
||||
|
||||
srtp_policy_t inbound = {};
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtcp);
|
||||
inbound.ssrc.type = ssrc_specific;
|
||||
inbound.ssrc.value = ssrc;
|
||||
inbound.key = mIsClient ? mServerSessionKey : mClientSessionKey;
|
||||
inbound.next = nullptr;
|
||||
inbound.allow_repeat_tx = true;
|
||||
srtp_policy_t inbound = {};
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&inbound.rtcp);
|
||||
inbound.ssrc.type = ssrc_specific;
|
||||
inbound.ssrc.value = ssrc;
|
||||
inbound.key = mIsClient ? mServerSessionKey : mClientSessionKey;
|
||||
inbound.next = nullptr;
|
||||
inbound.allow_repeat_tx = true;
|
||||
|
||||
if (srtp_err_status_t err = srtp_add_stream(mSrtpIn, &inbound))
|
||||
throw std::runtime_error("SRTP add inbound stream failed, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
if (srtp_err_status_t err = srtp_add_stream(mSrtpIn, &inbound))
|
||||
throw std::runtime_error("SRTP add inbound stream failed, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
|
||||
srtp_policy_t outbound = {};
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&outbound.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&outbound.rtcp);
|
||||
outbound.ssrc.type = ssrc_specific;
|
||||
outbound.ssrc.value = ssrc;
|
||||
outbound.key = mIsClient ? mClientSessionKey : mServerSessionKey;
|
||||
outbound.next = nullptr;
|
||||
outbound.allow_repeat_tx = true;
|
||||
srtp_policy_t outbound = {};
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&outbound.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&outbound.rtcp);
|
||||
outbound.ssrc.type = ssrc_specific;
|
||||
outbound.ssrc.value = ssrc;
|
||||
outbound.key = mIsClient ? mClientSessionKey : mServerSessionKey;
|
||||
outbound.next = nullptr;
|
||||
outbound.allow_repeat_tx = true;
|
||||
|
||||
if (srtp_err_status_t err = srtp_add_stream(mSrtpOut, &outbound))
|
||||
throw std::runtime_error("SRTP add outbound stream failed, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
if (srtp_err_status_t err = srtp_add_stream(mSrtpOut, &outbound))
|
||||
throw std::runtime_error("SRTP add outbound stream failed, status=" +
|
||||
to_string(static_cast<int>(err)));
|
||||
}
|
||||
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
@ -177,7 +177,7 @@ void DtlsTransport::runRecvLoop() {
|
||||
// Receive loop
|
||||
try {
|
||||
PLOG_INFO << "DTLS handshake finished";
|
||||
postHandshake();
|
||||
postHandshake();
|
||||
changeState(State::Connected);
|
||||
|
||||
const size_t bufferSize = maxMtu;
|
||||
@ -575,4 +575,3 @@ long DtlsTransport::BioMethodCtrl(BIO * /*bio*/, int cmd, long /*num*/, void * /
|
||||
#endif
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -92,4 +92,3 @@ protected:
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -130,9 +130,7 @@ IceTransport::~IceTransport() {
|
||||
mAgent.reset();
|
||||
}
|
||||
|
||||
bool IceTransport::stop() {
|
||||
return Transport::stop();
|
||||
}
|
||||
bool IceTransport::stop() { return Transport::stop(); }
|
||||
|
||||
Description::Role IceTransport::role() const { return mRole; }
|
||||
|
||||
@ -141,11 +139,13 @@ Description IceTransport::getLocalDescription(Description::Type type) const {
|
||||
if (juice_get_local_description(mAgent.get(), sdp, JUICE_MAX_SDP_STRING_LEN) < 0)
|
||||
throw std::runtime_error("Failed to generate local SDP");
|
||||
|
||||
return Description(string(sdp), type, type == Description::Type::Offer ? Description::Role::ActPass : mRole);
|
||||
return Description(string(sdp), type,
|
||||
type == Description::Type::Offer ? Description::Role::ActPass : mRole);
|
||||
}
|
||||
|
||||
void IceTransport::setRemoteDescription(const Description &description) {
|
||||
mRole = description.role() == Description::Role::Active ? Description::Role::Passive : Description::Role::Active;
|
||||
mRole = description.role() == Description::Role::Active ? Description::Role::Passive
|
||||
: Description::Role::Active;
|
||||
|
||||
mMid = description.bundleMid();
|
||||
if (juice_set_remote_description(mAgent.get(),
|
||||
@ -191,7 +191,7 @@ bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote)
|
||||
char sdpLocal[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
|
||||
char sdpRemote[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
|
||||
if (juice_get_selected_candidates(mAgent.get(), sdpLocal, JUICE_MAX_CANDIDATE_SDP_STRING_LEN,
|
||||
sdpRemote, JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0) {
|
||||
sdpRemote, JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0) {
|
||||
if (local) {
|
||||
*local = Candidate(sdpLocal, mMid);
|
||||
local->resolve(Candidate::ResolveMode::Simple);
|
||||
@ -736,15 +736,17 @@ void IceTransport::LogCallback(const gchar * /*logDomain*/, GLogLevelFlags logLe
|
||||
|
||||
bool IceTransport::getSelectedCandidatePair(Candidate *local, Candidate *remote) {
|
||||
NiceCandidate *niceLocal, *niceRemote;
|
||||
if(!nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &niceLocal, &niceRemote))
|
||||
if (!nice_agent_get_selected_pair(mNiceAgent.get(), mStreamId, 1, &niceLocal, &niceRemote))
|
||||
return false;
|
||||
|
||||
gchar *sdpLocal = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceLocal);
|
||||
if(local) *local = Candidate(sdpLocal, mMid);
|
||||
if (local)
|
||||
*local = Candidate(sdpLocal, mMid);
|
||||
g_free(sdpLocal);
|
||||
|
||||
gchar *sdpRemote = nice_agent_generate_local_candidate_sdp(mNiceAgent.get(), niceRemote);
|
||||
if(remote) *remote = Candidate(sdpRemote, mMid);
|
||||
if (remote)
|
||||
*remote = Candidate(sdpRemote, mMid);
|
||||
g_free(sdpRemote);
|
||||
|
||||
if (local)
|
||||
|
@ -20,8 +20,8 @@
|
||||
#define RTC_ICE_TRANSPORT_H
|
||||
|
||||
#include "candidate.hpp"
|
||||
#include "description.hpp"
|
||||
#include "configuration.hpp"
|
||||
#include "description.hpp"
|
||||
#include "include.hpp"
|
||||
#include "peerconnection.hpp"
|
||||
#include "transport.hpp"
|
||||
|
@ -142,4 +142,3 @@ Init::~Init() {
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -44,5 +44,4 @@ void InitLogger(plog::Severity severity, plog::IAppender *appender) {
|
||||
logger->addAppender(appender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
@ -119,7 +119,6 @@ bool PeerConnection::hasMedia() const {
|
||||
void PeerConnection::setLocalDescription(Description::Type type) {
|
||||
PLOG_VERBOSE << "Setting local description, type=" << Description::typeToString(type);
|
||||
|
||||
|
||||
SignalingState signalingState = mSignalingState.load();
|
||||
if (type == Description::Type::Rollback) {
|
||||
if (signalingState == SignalingState::HaveLocalOffer ||
|
||||
@ -679,205 +678,201 @@ void PeerConnection::forwardMedia(message_ptr message) {
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
|
||||
// Browsers like to compound their packets with a random SSRC.
|
||||
// we have to do this monstrosity to distribute the report blocks
|
||||
std::optional<unsigned int> mediaLine;
|
||||
if (message->type == Message::Control) {
|
||||
size_t offset = 0;
|
||||
std::vector<SSRC> ssrcsFound;
|
||||
bool hasFound = false;
|
||||
std::optional<unsigned int> mediaLine;
|
||||
if (message->type == Message::Control) {
|
||||
size_t offset = 0;
|
||||
std::vector<SSRC> ssrcsFound;
|
||||
bool hasFound = false;
|
||||
|
||||
while ((sizeof(rtc::RTCP_HEADER) + offset) <= message->size()) {
|
||||
auto header = (rtc::RTCP_HEADER *) (message->data() + offset);
|
||||
if (header->lengthInBytes() > message->size() - offset) {
|
||||
PLOG_WARNING << "Packet was truncated";
|
||||
break;
|
||||
}
|
||||
offset += header->lengthInBytes();
|
||||
if (header->payloadType() == 205 || header->payloadType() == 206) {
|
||||
auto rtcpfb = (RTCP_FB_HEADER *) header;
|
||||
auto ssrc = rtcpfb->getPacketSenderSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
while ((sizeof(rtc::RTCP_HEADER) + offset) <= message->size()) {
|
||||
auto header = (rtc::RTCP_HEADER *)(message->data() + offset);
|
||||
if (header->lengthInBytes() > message->size() - offset) {
|
||||
PLOG_WARNING << "Packet was truncated";
|
||||
break;
|
||||
}
|
||||
offset += header->lengthInBytes();
|
||||
if (header->payloadType() == 205 || header->payloadType() == 206) {
|
||||
auto rtcpfb = (RTCP_FB_HEADER *)header;
|
||||
auto ssrc = rtcpfb->getPacketSenderSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
ssrc = rtcpfb->getMediaSourceSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
}else if (header->payloadType() == 200 || header->payloadType() == 201) {
|
||||
auto rtcpsr = (RTCP_SR *) header;
|
||||
auto ssrc = rtcpsr->senderSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < rtcpsr->header.reportCount(); i++) {
|
||||
auto block = rtcpsr->getReportBlock(i);
|
||||
ssrc = block->getSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//PT=202 == SDES
|
||||
//PT=207 == Extended Report
|
||||
if (header->payloadType() != 202 && header->payloadType() != 207) {
|
||||
PLOG_WARNING << "Unknown packet type: " << (int) header->version() << " " << header->payloadType() << "";
|
||||
}
|
||||
}
|
||||
}
|
||||
ssrc = rtcpfb->getMediaSourceSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
} else if (header->payloadType() == 200 || header->payloadType() == 201) {
|
||||
auto rtcpsr = (RTCP_SR *)header;
|
||||
auto ssrc = rtcpsr->senderSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < rtcpsr->header.reportCount(); i++) {
|
||||
auto block = rtcpsr->getReportBlock(i);
|
||||
ssrc = block->getSSRC();
|
||||
if (std::find(ssrcsFound.begin(), ssrcsFound.end(), ssrc) == ssrcsFound.end()) {
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
if (mediaLine.has_value()) {
|
||||
hasFound = true;
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
ssrcsFound.emplace_back(ssrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// PT=202 == SDES
|
||||
// PT=207 == Extended Report
|
||||
if (header->payloadType() != 202 && header->payloadType() != 207) {
|
||||
PLOG_WARNING << "Unknown packet type: " << (int)header->version() << " "
|
||||
<< header->payloadType() << "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasFound)
|
||||
return;
|
||||
}
|
||||
if (hasFound)
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int ssrc = message->stream;
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
unsigned int ssrc = message->stream;
|
||||
mediaLine = getMLineFromSSRC(ssrc);
|
||||
|
||||
if (!mediaLine) {
|
||||
/* TODO
|
||||
* So the problem is that when stop sending streams, we stop getting report blocks for those streams
|
||||
* Therefore when we get compound RTCP packets, they are empty, and we can't forward them.
|
||||
* Therefore, it is expected that we don't know where to forward packets.
|
||||
* Is this ideal? No! Do I know how to fix it? No!
|
||||
*/
|
||||
// PLOG_WARNING << "Track not found for SSRC " << ssrc << ", dropping";
|
||||
/* TODO
|
||||
* So the problem is that when stop sending streams, we stop getting report blocks for
|
||||
* those streams Therefore when we get compound RTCP packets, they are empty, and we can't
|
||||
* forward them. Therefore, it is expected that we don't know where to forward packets. Is
|
||||
* this ideal? No! Do I know how to fix it? No!
|
||||
*/
|
||||
// PLOG_WARNING << "Track not found for SSRC " << ssrc << ", dropping";
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_lock lock(mTracksMutex); // read-only
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
if (auto track = mTrackLines[*mediaLine].lock()) {
|
||||
track->incoming(message);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<unsigned int> PeerConnection::getMLineFromSSRC(SSRC ssrc) {
|
||||
if (auto it = mMLineFromSssrc.find(ssrc); it != mMLineFromSssrc.end()) {
|
||||
return it->second;
|
||||
}else {
|
||||
{
|
||||
std::lock_guard lock(mRemoteDescriptionMutex);
|
||||
if (!mRemoteDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mRemoteDescription->mediaCount(); ++i) {
|
||||
if (std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> bool {
|
||||
return false;
|
||||
},
|
||||
[&](Description::Media *media) -> bool {
|
||||
return media->hasSSRC(ssrc);
|
||||
}},
|
||||
mRemoteDescription->media(i))) {
|
||||
if (auto it = mMLineFromSssrc.find(ssrc); it != mMLineFromSssrc.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
{
|
||||
std::lock_guard lock(mRemoteDescriptionMutex);
|
||||
if (!mRemoteDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mRemoteDescription->mediaCount(); ++i) {
|
||||
if (std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> bool { return false; },
|
||||
[&](Description::Media *media) -> bool {
|
||||
return media->hasSSRC(ssrc);
|
||||
}},
|
||||
mRemoteDescription->media(i))) {
|
||||
|
||||
mMLineFromSssrc.emplace(ssrc, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mLocalDescriptionMutex);
|
||||
if (!mLocalDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mLocalDescription->mediaCount(); ++i) {
|
||||
if (std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> bool {
|
||||
return false;
|
||||
},
|
||||
[&](Description::Media *media) -> bool {
|
||||
return media->hasSSRC(ssrc);
|
||||
}},
|
||||
mLocalDescription->media(i))) {
|
||||
mMLineFromSssrc.emplace(ssrc, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mLocalDescriptionMutex);
|
||||
if (!mLocalDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mLocalDescription->mediaCount(); ++i) {
|
||||
if (std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> bool { return false; },
|
||||
[&](Description::Media *media) -> bool {
|
||||
return media->hasSSRC(ssrc);
|
||||
}},
|
||||
mLocalDescription->media(i))) {
|
||||
|
||||
mMLineFromSssrc.emplace(ssrc, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
mMLineFromSssrc.emplace(ssrc, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> PeerConnection::getMidFromSSRC(SSRC ssrc) {
|
||||
if (auto it = mMidFromSssrc.find(ssrc); it != mMidFromSssrc.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
{
|
||||
std::lock_guard lock(mRemoteDescriptionMutex);
|
||||
if (!mRemoteDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mRemoteDescription->mediaCount(); ++i) {
|
||||
if (auto found = std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> std::optional<string> {
|
||||
return std::nullopt;
|
||||
},
|
||||
[&](Description::Media *media) -> std::optional<string> {
|
||||
return media->hasSSRC(ssrc)
|
||||
? std::make_optional(media->mid())
|
||||
: nullopt;
|
||||
}},
|
||||
mRemoteDescription->media(i))) {
|
||||
if (auto it = mMidFromSssrc.find(ssrc); it != mMidFromSssrc.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
{
|
||||
std::lock_guard lock(mRemoteDescriptionMutex);
|
||||
if (!mRemoteDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mRemoteDescription->mediaCount(); ++i) {
|
||||
if (auto found = std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> std::optional<string> {
|
||||
return std::nullopt;
|
||||
},
|
||||
[&](Description::Media *media) -> std::optional<string> {
|
||||
return media->hasSSRC(ssrc)
|
||||
? std::make_optional(media->mid())
|
||||
: nullopt;
|
||||
}},
|
||||
mRemoteDescription->media(i))) {
|
||||
|
||||
mMidFromSssrc.emplace(ssrc, *found);
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mLocalDescriptionMutex);
|
||||
if (!mLocalDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mLocalDescription->mediaCount(); ++i) {
|
||||
if (auto found = std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> std::optional<string> {
|
||||
return std::nullopt;
|
||||
},
|
||||
[&](Description::Media *media) -> std::optional<string> {
|
||||
return media->hasSSRC(ssrc)
|
||||
? std::make_optional(media->mid())
|
||||
: nullopt;
|
||||
}},
|
||||
mLocalDescription->media(i))) {
|
||||
mMidFromSssrc.emplace(ssrc, *found);
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mLocalDescriptionMutex);
|
||||
if (!mLocalDescription)
|
||||
return nullopt;
|
||||
for (unsigned int i = 0; i < mLocalDescription->mediaCount(); ++i) {
|
||||
if (auto found = std::visit(
|
||||
rtc::overloaded{[&](Description::Application *) -> std::optional<string> {
|
||||
return std::nullopt;
|
||||
},
|
||||
[&](Description::Media *media) -> std::optional<string> {
|
||||
return media->hasSSRC(ssrc)
|
||||
? std::make_optional(media->mid())
|
||||
: nullopt;
|
||||
}},
|
||||
mLocalDescription->media(i))) {
|
||||
|
||||
mMidFromSssrc.emplace(ssrc, *found);
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
}
|
||||
mMidFromSssrc.emplace(ssrc, *found);
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullopt;
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) {
|
||||
@ -979,7 +974,7 @@ void PeerConnection::incomingTrack(Description::Media description) {
|
||||
if (mTracks.find(description.mid()) == mTracks.end()) {
|
||||
auto track = std::make_shared<Track>(std::move(description));
|
||||
mTracks.emplace(std::make_pair(track->mid(), track));
|
||||
mTrackLines.emplace_back(track);
|
||||
mTrackLines.emplace_back(track);
|
||||
triggerTrack(track);
|
||||
}
|
||||
}
|
||||
@ -1092,21 +1087,21 @@ void PeerConnection::processLocalDescription(Description description) {
|
||||
|
||||
auto reciprocated = remoteMedia->reciprocate();
|
||||
#if !RTC_ENABLE_MEDIA
|
||||
// No media support, mark as inactive
|
||||
reciprocated.setDirection(Description::Direction::Inactive);
|
||||
// No media support, mark as inactive
|
||||
reciprocated.setDirection(Description::Direction::Inactive);
|
||||
#endif
|
||||
incomingTrack(reciprocated);
|
||||
incomingTrack(reciprocated);
|
||||
|
||||
PLOG_DEBUG
|
||||
<< "Reciprocating media in local description, mid=\""
|
||||
<< reciprocated.mid() << "\", active=" << std::boolalpha
|
||||
<< (reciprocated.direction() != Description::Direction::Inactive);
|
||||
PLOG_DEBUG
|
||||
<< "Reciprocating media in local description, mid=\""
|
||||
<< reciprocated.mid() << "\", active=" << std::boolalpha
|
||||
<< (reciprocated.direction() != Description::Direction::Inactive);
|
||||
|
||||
description.addMedia(std::move(reciprocated));
|
||||
},
|
||||
},
|
||||
remote->media(i));
|
||||
}
|
||||
description.addMedia(std::move(reciprocated));
|
||||
},
|
||||
},
|
||||
remote->media(i));
|
||||
}
|
||||
|
||||
if (description.type() == Description::Type::Offer) {
|
||||
// This is an offer, add locally created data channels and tracks
|
||||
@ -1128,23 +1123,23 @@ void PeerConnection::processLocalDescription(Description description) {
|
||||
// Add media for local tracks
|
||||
|
||||
std::shared_lock lock(mTracksMutex);
|
||||
for (auto it = mTrackLines.begin(); it != mTrackLines.end(); ++it) {
|
||||
if (auto track = it->lock()) {
|
||||
if (description.hasMid(track->mid()))
|
||||
continue;
|
||||
for (auto it = mTrackLines.begin(); it != mTrackLines.end(); ++it) {
|
||||
if (auto track = it->lock()) {
|
||||
if (description.hasMid(track->mid()))
|
||||
continue;
|
||||
|
||||
auto media = track->description();
|
||||
auto media = track->description();
|
||||
#if !RTC_ENABLE_MEDIA
|
||||
// No media support, mark as inactive
|
||||
media.setDirection(Description::Direction::Inactive);
|
||||
// No media support, mark as inactive
|
||||
media.setDirection(Description::Direction::Inactive);
|
||||
#endif
|
||||
PLOG_DEBUG << "Adding media to local description, mid=\"" << media.mid()
|
||||
<< "\", active=" << std::boolalpha
|
||||
<< (media.direction() != Description::Direction::Inactive);
|
||||
PLOG_DEBUG << "Adding media to local description, mid=\"" << media.mid()
|
||||
<< "\", active=" << std::boolalpha
|
||||
<< (media.direction() != Description::Direction::Inactive);
|
||||
|
||||
description.addMedia(std::move(media));
|
||||
}
|
||||
}
|
||||
description.addMedia(std::move(media));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set local fingerprint (wait for certificate if necessary)
|
||||
|
@ -41,4 +41,3 @@ void Processor::schedule() {
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -44,8 +44,7 @@ public:
|
||||
|
||||
void join();
|
||||
|
||||
template <class F, class... Args>
|
||||
void enqueue(F &&f, Args &&... args);
|
||||
template <class F, class... Args> void enqueue(F &&f, Args &&... args);
|
||||
|
||||
protected:
|
||||
void schedule();
|
||||
|
32
src/rtcp.cpp
32
src/rtcp.cpp
@ -19,9 +19,9 @@
|
||||
|
||||
#include "rtcp.hpp"
|
||||
|
||||
#include "track.hpp"
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
#include "track.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@ -29,12 +29,9 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace rtc {
|
||||
|
||||
rtc::message_ptr RtcpReceivingSession::outgoing(rtc::message_ptr ptr) {
|
||||
return ptr;
|
||||
}
|
||||
rtc::message_ptr RtcpReceivingSession::outgoing(rtc::message_ptr ptr) { return ptr; }
|
||||
|
||||
rtc::message_ptr RtcpReceivingSession::incoming(rtc::message_ptr ptr) {
|
||||
if (ptr->type == rtc::Message::Type::Binary) {
|
||||
@ -98,7 +95,7 @@ void RtcpReceivingSession::pushREMB(unsigned int bitrate) {
|
||||
remb->preparePacket(mSsrc, 1, bitrate);
|
||||
remb->setSsrc(0, mSsrc);
|
||||
|
||||
send(msg);
|
||||
send(msg);
|
||||
}
|
||||
|
||||
void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) {
|
||||
@ -109,13 +106,13 @@ void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) {
|
||||
lastSR_delay);
|
||||
rr->log();
|
||||
|
||||
send(msg);
|
||||
send(msg);
|
||||
}
|
||||
|
||||
bool RtcpReceivingSession::send(message_ptr msg) {
|
||||
try {
|
||||
outgoingCallback(std::move(msg));
|
||||
return true;
|
||||
outgoingCallback(std::move(msg));
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
LOG_DEBUG << "RTCP tx failed: " << e.what();
|
||||
}
|
||||
@ -123,19 +120,18 @@ bool RtcpReceivingSession::send(message_ptr msg) {
|
||||
}
|
||||
|
||||
bool RtcpReceivingSession::requestKeyframe() {
|
||||
pushPLI();
|
||||
return true; // TODO Make this false when it is impossible (i.e. Opus).
|
||||
pushPLI();
|
||||
return true; // TODO Make this false when it is impossible (i.e. Opus).
|
||||
}
|
||||
|
||||
void RtcpReceivingSession::pushPLI() {
|
||||
auto msg = rtc::make_message(rtc::RTCP_PLI::size(), rtc::Message::Type::Control);
|
||||
auto *pli = (rtc::RTCP_PLI *) msg->data();
|
||||
pli->preparePacket(mSsrc);
|
||||
send(msg);
|
||||
auto msg = rtc::make_message(rtc::RTCP_PLI::size(), rtc::Message::Type::Control);
|
||||
auto *pli = (rtc::RTCP_PLI *)msg->data();
|
||||
pli->preparePacket(mSsrc);
|
||||
send(msg);
|
||||
}
|
||||
|
||||
void RtcpHandler::onOutgoing(const std::function<void(rtc::message_ptr)>& cb) {
|
||||
this->outgoingCallback = synchronized_callback<rtc::message_ptr>(cb);
|
||||
void RtcpHandler::onOutgoing(const std::function<void(rtc::message_ptr)> &cb) {
|
||||
this->outgoingCallback = synchronized_callback<rtc::message_ptr>(cb);
|
||||
}
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -100,7 +100,7 @@ private:
|
||||
|
||||
std::mutex mWriteMutex;
|
||||
std::condition_variable mWrittenCondition;
|
||||
std::atomic<bool> mWritten = false; // written outside lock
|
||||
std::atomic<bool> mWritten = false; // written outside lock
|
||||
std::atomic<bool> mWrittenOnce = false; // same
|
||||
|
||||
binary mPartialMessage, mPartialNotification;
|
||||
|
@ -75,4 +75,3 @@ std::function<void()> ThreadPool::dequeue() {
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -75,13 +75,13 @@ auto ThreadPool::enqueue(F &&f, Args &&... args) -> invoke_future_t<F, Args...>
|
||||
using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
auto task = std::make_shared<std::packaged_task<R()>>([bound = std::move(bound)]() mutable {
|
||||
try {
|
||||
return bound();
|
||||
} catch (const std::exception &e) {
|
||||
PLOG_WARNING << e.what();
|
||||
throw;
|
||||
}
|
||||
});
|
||||
try {
|
||||
return bound();
|
||||
} catch (const std::exception &e) {
|
||||
PLOG_WARNING << e.what();
|
||||
throw;
|
||||
}
|
||||
});
|
||||
std::future<R> result = task->get_future();
|
||||
|
||||
mTasks.emplace([task = std::move(task), token = Init::Token()]() { return (*task)(); });
|
||||
|
@ -127,4 +127,3 @@ bool check(SSL *ssl, int ret, const string &message) {
|
||||
} // namespace rtc::openssl
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -56,12 +56,12 @@ gnutls_datum_t make_datum(char *data, size_t size);
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#ifndef BIO_EOF
|
||||
#define BIO_EOF -1
|
||||
|
@ -62,10 +62,10 @@ TlsTransport::TlsTransport(shared_ptr<TcpTransport> lower, string host, state_ca
|
||||
gnutls::check(gnutls_priority_set_direct(mSession, priorities, &err_pos),
|
||||
"Failed to set TLS priorities");
|
||||
|
||||
PLOG_VERBOSE << "Server Name Indication: " << mHost;
|
||||
PLOG_VERBOSE << "Server Name Indication: " << mHost;
|
||||
gnutls_server_name_set(mSession, GNUTLS_NAME_DNS, mHost.data(), mHost.size());
|
||||
|
||||
gnutls_session_set_ptr(mSession, this);
|
||||
gnutls_session_set_ptr(mSession, this);
|
||||
gnutls_transport_set_ptr(mSession, this);
|
||||
gnutls_transport_set_push_function(mSession, WriteCallback);
|
||||
gnutls_transport_set_pull_function(mSession, ReadCallback);
|
||||
@ -110,7 +110,7 @@ bool TlsTransport::send(message_ptr message) {
|
||||
|
||||
PLOG_VERBOSE << "Send size=" << message->size();
|
||||
|
||||
if(message->size() == 0)
|
||||
if (message->size() == 0)
|
||||
return true;
|
||||
|
||||
ssize_t ret;
|
||||
@ -207,10 +207,10 @@ ssize_t TlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_
|
||||
message_ptr &message = t->mIncomingMessage;
|
||||
size_t &position = t->mIncomingMessagePosition;
|
||||
|
||||
if(message && position >= message->size())
|
||||
if (message && position >= message->size())
|
||||
message.reset();
|
||||
|
||||
if(!message) {
|
||||
if (!message) {
|
||||
position = 0;
|
||||
while (auto next = t->mIncomingQueue.pop()) {
|
||||
message = *next;
|
||||
@ -221,15 +221,14 @@ ssize_t TlsTransport::ReadCallback(gnutls_transport_ptr_t ptr, void *data, size_
|
||||
}
|
||||
}
|
||||
|
||||
if(message) {
|
||||
if (message) {
|
||||
size_t available = message->size() - position;
|
||||
ssize_t len = std::min(maxlen, available);
|
||||
std::memcpy(data, message->data() + position, len);
|
||||
position+= len;
|
||||
position += len;
|
||||
gnutls_transport_set_errno(t->mSession, 0);
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Closed
|
||||
gnutls_transport_set_errno(t->mSession, 0);
|
||||
return 0;
|
||||
|
@ -32,9 +32,8 @@ string Track::mid() const { return mMediaDescription.mid(); }
|
||||
|
||||
Description::Media Track::description() const { return mMediaDescription; }
|
||||
|
||||
|
||||
void Track::setDescription(Description::Media description) {
|
||||
if(description.mid() != mMediaDescription.mid())
|
||||
if (description.mid() != mMediaDescription.mid())
|
||||
throw std::logic_error("Media description mid does not match track mid");
|
||||
|
||||
mMediaDescription = std::move(description);
|
||||
@ -80,9 +79,7 @@ size_t Track::maxMessageSize() const {
|
||||
return 65535 - 12 - 4; // SRTP/UDP
|
||||
}
|
||||
|
||||
size_t Track::availableAmount() const {
|
||||
return mRecvQueue.amount();
|
||||
}
|
||||
size_t Track::availableAmount() const { return mRecvQueue.amount(); }
|
||||
|
||||
#if RTC_ENABLE_MEDIA
|
||||
void Track::open(shared_ptr<DtlsSrtpTransport> transport) {
|
||||
@ -93,34 +90,34 @@ void Track::open(shared_ptr<DtlsSrtpTransport> transport) {
|
||||
|
||||
bool Track::outgoing(message_ptr message) {
|
||||
|
||||
if (mRtcpHandler) {
|
||||
message = mRtcpHandler->outgoing(message);
|
||||
if (!message)
|
||||
return false;
|
||||
}
|
||||
if (mRtcpHandler) {
|
||||
message = mRtcpHandler->outgoing(message);
|
||||
if (!message)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto direction = mMediaDescription.direction();
|
||||
if ((direction == Description::Direction::RecvOnly ||
|
||||
direction == Description::Direction::Inactive) &&
|
||||
message->type != Message::Control) {
|
||||
PLOG_WARNING << "Track media direction does not allow transmission, dropping";
|
||||
return false;
|
||||
}
|
||||
auto direction = mMediaDescription.direction();
|
||||
if ((direction == Description::Direction::RecvOnly ||
|
||||
direction == Description::Direction::Inactive) &&
|
||||
message->type != Message::Control) {
|
||||
PLOG_WARNING << "Track media direction does not allow transmission, dropping";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mIsClosed)
|
||||
throw std::runtime_error("Track is closed");
|
||||
if (mIsClosed)
|
||||
throw std::runtime_error("Track is closed");
|
||||
|
||||
if (message->size() > maxMessageSize())
|
||||
throw std::runtime_error("Message size exceeds limit");
|
||||
if (message->size() > maxMessageSize())
|
||||
throw std::runtime_error("Message size exceeds limit");
|
||||
|
||||
#if RTC_ENABLE_MEDIA
|
||||
auto transport = mDtlsSrtpTransport.lock();
|
||||
if (!transport)
|
||||
throw std::runtime_error("Track transport is not open");
|
||||
auto transport = mDtlsSrtpTransport.lock();
|
||||
if (!transport)
|
||||
throw std::runtime_error("Track transport is not open");
|
||||
|
||||
return transport->sendMedia(message);
|
||||
return transport->sendMedia(message);
|
||||
#else
|
||||
PLOG_WARNING << "Ignoring track send (not compiled with SRTP support)";
|
||||
PLOG_WARNING << "Ignoring track send (not compiled with SRTP support)";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@ -130,10 +127,10 @@ void Track::incoming(message_ptr message) {
|
||||
return;
|
||||
|
||||
if (mRtcpHandler) {
|
||||
message = mRtcpHandler->incoming(message);
|
||||
if (!message)
|
||||
return ;
|
||||
}
|
||||
message = mRtcpHandler->incoming(message);
|
||||
if (!message)
|
||||
return;
|
||||
}
|
||||
|
||||
auto direction = mMediaDescription.direction();
|
||||
if ((direction == Description::Direction::SendOnly ||
|
||||
@ -154,30 +151,27 @@ void Track::incoming(message_ptr message) {
|
||||
void Track::setRtcpHandler(std::shared_ptr<RtcpHandler> handler) {
|
||||
mRtcpHandler = std::move(handler);
|
||||
if (mRtcpHandler) {
|
||||
mRtcpHandler->onOutgoing([&]([[maybe_unused]] const rtc::message_ptr& message) {
|
||||
#if RTC_ENABLE_MEDIA
|
||||
mRtcpHandler->onOutgoing([&]([[maybe_unused]] const rtc::message_ptr &message) {
|
||||
#if RTC_ENABLE_MEDIA
|
||||
auto transport = mDtlsSrtpTransport.lock();
|
||||
if (!transport)
|
||||
throw std::runtime_error("Track transport is not open");
|
||||
throw std::runtime_error("Track transport is not open");
|
||||
|
||||
return transport->sendMedia(message);
|
||||
#else
|
||||
#else
|
||||
PLOG_WARNING << "Ignoring track send (not compiled with SRTP support)";
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
#endif
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool Track::requestKeyframe() {
|
||||
if (mRtcpHandler)
|
||||
return mRtcpHandler->requestKeyframe();
|
||||
return false;
|
||||
if (mRtcpHandler)
|
||||
return mRtcpHandler->requestKeyframe();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<RtcpHandler> Track::getRtcpHandler() {
|
||||
return mRtcpHandler;
|
||||
}
|
||||
std::shared_ptr<RtcpHandler> Track::getRtcpHandler() { return mRtcpHandler; }
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
|
@ -36,8 +36,7 @@ public:
|
||||
using state_callback = std::function<void(State state)>;
|
||||
|
||||
Transport(std::shared_ptr<Transport> lower = nullptr, state_callback callback = nullptr)
|
||||
: mLower(std::move(lower)), mStateChangeCallback(std::move(callback)) {
|
||||
}
|
||||
: mLower(std::move(lower)), mStateChangeCallback(std::move(callback)) {}
|
||||
|
||||
virtual ~Transport() { stop(); }
|
||||
|
||||
|
@ -28,7 +28,6 @@ using std::weak_ptr;
|
||||
|
||||
namespace rtc {
|
||||
|
||||
|
||||
VerifiedTlsTransport::VerifiedTlsTransport(shared_ptr<TcpTransport> lower, string host,
|
||||
state_callback callback)
|
||||
: TlsTransport(std::move(lower), std::move(host), std::move(callback)) {
|
||||
@ -48,4 +47,3 @@ VerifiedTlsTransport::~VerifiedTlsTransport() {}
|
||||
} // namespace rtc
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -256,7 +256,8 @@ shared_ptr<TlsTransport> WebSocket::initTlsTransport() {
|
||||
if (mConfig.disableTlsVerification)
|
||||
transport = std::make_shared<TlsTransport>(lower, mHostname, stateChangeCallback);
|
||||
else
|
||||
transport = std::make_shared<VerifiedTlsTransport>(lower, mHostname, stateChangeCallback);
|
||||
transport =
|
||||
std::make_shared<VerifiedTlsTransport>(lower, mHostname, stateChangeCallback);
|
||||
#endif
|
||||
|
||||
std::atomic_store(&mTlsTransport, transport);
|
||||
|
@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
#include "wstransport.hpp"
|
||||
#include "base64.hpp"
|
||||
#include "tcptransport.hpp"
|
||||
#include "tlstransport.hpp"
|
||||
#include "base64.hpp"
|
||||
|
||||
#if RTC_ENABLE_WEBSOCKET
|
||||
|
||||
|
@ -20,11 +20,11 @@
|
||||
|
||||
#if RTC_ENABLE_WEBSOCKET
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
using namespace rtc;
|
||||
using namespace std;
|
||||
@ -56,7 +56,7 @@ void test_websocket() {
|
||||
ws->onMessage([&received, &myMessage](variant<binary, string> message) {
|
||||
if (holds_alternative<string>(message)) {
|
||||
string str = std::move(get<string>(message));
|
||||
if((received = (str == myMessage)))
|
||||
if ((received = (str == myMessage)))
|
||||
cout << "WebSocket: Received expected message" << endl;
|
||||
else
|
||||
cout << "WebSocket: Received UNEXPECTED message" << endl;
|
||||
@ -72,7 +72,7 @@ void test_websocket() {
|
||||
if (!ws->isOpen())
|
||||
throw runtime_error("WebSocket is not open");
|
||||
|
||||
if(!received)
|
||||
if (!received)
|
||||
throw runtime_error("Expected message not received");
|
||||
|
||||
ws->close();
|
||||
@ -86,4 +86,3 @@ void test_websocket() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user