diff --git a/include/uvgrtp/media_stream.hh b/include/uvgrtp/media_stream.hh index dced01d9..395629c5 100644 --- a/include/uvgrtp/media_stream.hh +++ b/include/uvgrtp/media_stream.hh @@ -5,7 +5,7 @@ #include #include #include - +#include #ifndef _WIN32 #include @@ -315,6 +315,8 @@ namespace uvgrtp { std::shared_ptr rtp_; std::shared_ptr rtcp_; + std::shared_ptr> ssrc_; + sockaddr_in remote_sockaddr_; std::string remote_address_; std::string local_address_; diff --git a/include/uvgrtp/rtcp.hh b/include/uvgrtp/rtcp.hh index 0460c82a..6dcc4080 100644 --- a/include/uvgrtp/rtcp.hh +++ b/include/uvgrtp/rtcp.hh @@ -12,6 +12,7 @@ #include #include #include +#include namespace uvgrtp { @@ -108,8 +109,8 @@ namespace uvgrtp { class rtcp { public: /// \cond DO_NOT_DOCUMENT - rtcp(std::shared_ptr rtp, std::string cname, int rce_flags); - rtcp(std::shared_ptr rtp, std::string cname, std::shared_ptr srtcp, int rce_flags); + rtcp(std::shared_ptr rtp, std::shared_ptr> ssrc, std::string cname, int rce_flags); + rtcp(std::shared_ptr rtp, std::shared_ptr> ssrc, std::string cname, std::shared_ptr srtcp, int rce_flags); ~rtcp(); /* start the RTCP runner thread @@ -512,7 +513,7 @@ namespace uvgrtp { bool initial_; /* Copy of our own current SSRC */ - const uint32_t ssrc_; + std::shared_ptr ssrc_; /* NTP timestamp associated with initial RTP timestamp (aka t = 0) */ uint64_t clock_start_; diff --git a/include/uvgrtp/util.hh b/include/uvgrtp/util.hh index a5afecdd..a34f840b 100644 --- a/include/uvgrtp/util.hh +++ b/include/uvgrtp/util.hh @@ -362,6 +362,13 @@ enum RTP_CTX_CONFIGURATION_FLAGS { * See RCC_FPS_NUMERATOR for more info. */ RCC_FPS_DENOMINATOR = 9, + + /** Set the SSRC of the stream manually + * + * By default SSRC is generated randomly + */ + RCC_SSRC = 10, + /// \cond DO_NOT_DOCUMENT RCC_LAST /// \endcond diff --git a/src/media_stream.cc b/src/media_stream.cc index d0c1264e..3befeee3 100644 --- a/src/media_stream.cc +++ b/src/media_stream.cc @@ -45,7 +45,8 @@ uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr, holepuncher_(std::unique_ptr(new uvgrtp::holepuncher(socket_))), cname_(cname), fps_numerator_(30), - fps_denominator_(1) + fps_denominator_(1), + ssrc_(std::make_shared>(uvgrtp::random::generate_32())) {} uvgrtp::media_stream::~media_stream() @@ -257,8 +258,8 @@ rtp_error_t uvgrtp::media_stream::init() reception_flow_ = std::unique_ptr (new uvgrtp::reception_flow()); - rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_)); - rtcp_ = std::shared_ptr (new uvgrtp::rtcp(rtp_, cname_, rce_flags_)); + rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_, ssrc_)); + rtcp_ = std::shared_ptr (new uvgrtp::rtcp(rtp_, ssrc_, cname_, rce_flags_)); socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec); @@ -277,7 +278,7 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr zrtp) reception_flow_ = std::unique_ptr (new uvgrtp::reception_flow()); - rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_)); + rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_, ssrc_)); bool perform_dh = !(rce_flags_ & RCE_ZRTP_MULTISTREAM_MODE); if (!perform_dh) @@ -313,7 +314,7 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr zrtp) zrtp->dh_has_finished(); // only after the DH stream has gotten its keys, do we let non-DH stream perform ZRTP - rtcp_ = std::shared_ptr (new uvgrtp::rtcp(rtp_, cname_, srtcp_, rce_flags_)); + rtcp_ = std::shared_ptr (new uvgrtp::rtcp(rtp_, ssrc_, cname_, srtcp_, rce_flags_)); socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec); socket_->install_handler(srtp_.get(), srtp_->send_packet_handler); @@ -345,7 +346,7 @@ rtp_error_t uvgrtp::media_stream::add_srtp_ctx(uint8_t *key, uint8_t *salt) reception_flow_ = std::unique_ptr (new uvgrtp::reception_flow()); - rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_)); + rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_, ssrc_)); srtp_ = std::shared_ptr (new uvgrtp::srtp(rce_flags_)); @@ -362,7 +363,7 @@ rtp_error_t uvgrtp::media_stream::add_srtp_ctx(uint8_t *key, uint8_t *salt) return free_resources(ret); } - rtcp_ = std::shared_ptr (new uvgrtp::rtcp(rtp_, cname_, srtcp_, rce_flags_)); + rtcp_ = std::shared_ptr (new uvgrtp::rtcp(rtp_, ssrc_, cname_, srtcp_, rce_flags_)); socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec); socket_->install_handler(srtp_.get(), srtp_->send_packet_handler); @@ -660,7 +661,13 @@ rtp_error_t uvgrtp::media_stream::configure_ctx(int rcc_flag, ssize_t value) media_->set_fps(fps_numerator_, fps_denominator_); break; } + case RCC_SSRC: { + if (value <= 0 || value > (ssize_t)UINT32_MAX) + return RTP_INVALID_VALUE; + *ssrc_ = (uint32_t)value; + break; + } default: return RTP_INVALID_VALUE; } @@ -685,7 +692,7 @@ uint32_t uvgrtp::media_stream::get_ssrc() const return 0; } - return rtp_->get_ssrc(); + return *ssrc_.get(); } rtp_error_t uvgrtp::media_stream::init_srtp_with_zrtp(int rce_flags, int type, std::shared_ptr srtp, diff --git a/src/rtcp.cc b/src/rtcp.cc index c6ea83d6..0b1119c4 100644 --- a/src/rtcp.cc +++ b/src/rtcp.cc @@ -37,12 +37,12 @@ constexpr int ESTIMATED_MAX_RECEPTION_TIME_MS = 10; const uint32_t MAX_SUPPORTED_PARTICIPANTS = 31; -uvgrtp::rtcp::rtcp(std::shared_ptr rtp, std::string cname, int rce_flags): - rce_flags_(rce_flags), our_role_(RECEIVER), +uvgrtp::rtcp::rtcp(std::shared_ptr rtp, std::shared_ptr ssrc, std::string cname, int rce_flags): + rce_flags_(rce_flags), our_role_(RECEIVER), ssrc_(ssrc), tp_(0), tc_(0), tn_(0), pmembers_(0), members_(0), senders_(0), rtcp_bandwidth_(0), we_sent_(false), avg_rtcp_pkt_pize_(0), rtcp_pkt_count_(0), - rtcp_pkt_sent_count_(0), initial_(true), ssrc_(rtp->get_ssrc()), + rtcp_pkt_sent_count_(0), initial_(true), num_receivers_(0), sender_hook_(nullptr), receiver_hook_(nullptr), @@ -89,9 +89,9 @@ uvgrtp::rtcp::rtcp(std::shared_ptr rtp, std::string cname, int rce_ } } -uvgrtp::rtcp::rtcp(std::shared_ptr rtp, std::string cname, +uvgrtp::rtcp::rtcp(std::shared_ptr rtp, std::shared_ptr ssrc, std::string cname, std::shared_ptr srtcp, int rce_flags): - rtcp(rtp, cname, rce_flags) + rtcp(rtp, ssrc, cname, rce_flags) { srtcp_ = srtcp; } @@ -229,7 +229,7 @@ rtp_error_t uvgrtp::rtcp::stop() } /* Send BYE packet with our SSRC to all participants */ - return uvgrtp::rtcp::send_bye_packet({ ssrc_ }); + return uvgrtp::rtcp::send_bye_packet({ *ssrc_.get() }); } void uvgrtp::rtcp::rtcp_runner(rtcp* rtcp, int interval) @@ -1515,7 +1515,7 @@ rtp_error_t uvgrtp::rtcp::send_rtcp_packet_to_participants(uint8_t* frame, uint3 rtp_error_t ret = RTP_OK; if (encrypt && srtcp_ && - (ret = srtcp_->handle_rtcp_encryption(rce_flags_, rtcp_pkt_sent_count_, ssrc_, frame, frame_size)) != RTP_OK) + (ret = srtcp_->handle_rtcp_encryption(rce_flags_, rtcp_pkt_sent_count_, *ssrc_.get(), frame, frame_size)) != RTP_OK) { UVG_LOG_DEBUG("Encryption failed. Not sending packet"); delete[] frame; @@ -1640,6 +1640,7 @@ rtp_error_t uvgrtp::rtcp::generate_report() // see https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.1 size_t write_ptr = 0; + uint32_t ssrc = *ssrc_.get(); if (sr_packet) { // sender reports have sender information in addition compared to receiver reports @@ -1662,7 +1663,7 @@ rtp_error_t uvgrtp::rtcp::generate_report() uint64_t rtp_ts = expanded_ts_start + ts_since_start; if (!construct_rtcp_header(frame, write_ptr, sender_report_size, reports, uvgrtp::frame::RTCP_FT_SR) || - !construct_ssrc(frame, write_ptr, ssrc_) || + !construct_ssrc(frame, write_ptr, ssrc) || !construct_sender_info(frame, write_ptr, ntp_ts, rtp_ts, our_stats.sent_pkts, our_stats.sent_bytes)) { UVG_LOG_ERROR("Failed to construct SR"); @@ -1675,7 +1676,7 @@ rtp_error_t uvgrtp::rtcp::generate_report() size_t receiver_report_size = get_rr_packet_size(rce_flags_, reports); if (!construct_rtcp_header(frame, write_ptr, receiver_report_size, reports, uvgrtp::frame::RTCP_FT_RR) || - !construct_ssrc(frame, write_ptr, ssrc_)) + !construct_ssrc(frame, write_ptr, ssrc)) { UVG_LOG_ERROR("Failed to construct RR"); return RTP_GENERIC_ERROR; @@ -1724,7 +1725,7 @@ rtp_error_t uvgrtp::rtcp::generate_report() // add the SDES packet after the SR/RR, mandatory, must contain CNAME if (!construct_rtcp_header(frame, write_ptr, get_sdes_packet_size(ourItems_), num_receivers_, uvgrtp::frame::RTCP_FT_SDES) || - !construct_sdes_chunk(frame, write_ptr, { ssrc_, ourItems_ })) + !construct_sdes_chunk(frame, write_ptr, { ssrc, ourItems_ })) { UVG_LOG_ERROR("Failed to add SDES packet"); delete[] frame; @@ -1750,7 +1751,7 @@ rtp_error_t uvgrtp::rtcp::generate_report() if (!construct_rtcp_header(frame, write_ptr, packet_size, secondField, uvgrtp::frame::RTCP_FT_APP) || - !construct_ssrc(frame, write_ptr, ssrc_) || + !construct_ssrc(frame, write_ptr, ssrc) || !construct_app_packet(frame, write_ptr, next_packet.name, next_packet.payload, next_packet.payload_len)) { UVG_LOG_ERROR("Failed to construct APP packet"); diff --git a/src/rtp.cc b/src/rtp.cc index 189fb6c5..64d3af1c 100644 --- a/src/rtp.cc +++ b/src/rtp.cc @@ -17,8 +17,8 @@ #define INVALID_TS UINT64_MAX -uvgrtp::rtp::rtp(rtp_format_t fmt): - ssrc_(uvgrtp::random::generate_32()), +uvgrtp::rtp::rtp(rtp_format_t fmt, std::shared_ptr> ssrc): + ssrc_(ssrc), ts_(uvgrtp::random::generate_32()), seq_(uvgrtp::random::generate_32() & 0xffff), fmt_(fmt), @@ -40,7 +40,7 @@ uvgrtp::rtp::~rtp() uint32_t uvgrtp::rtp::get_ssrc() const { - return ssrc_; + return *ssrc_.get(); } uint16_t uvgrtp::rtp::get_sequence() const @@ -145,7 +145,7 @@ void uvgrtp::rtp::fill_header(uint8_t *buffer) buffer[1] = (payload_ & 0x7f) | (0 << 7); *(uint16_t *)&buffer[2] = htons(seq_); - *(uint32_t *)&buffer[8] = htonl(ssrc_); + *(uint32_t *)&buffer[8] = htonl(*ssrc_.get()); if (timestamp_ == INVALID_TS) { diff --git a/src/rtp.hh b/src/rtp.hh index 6f1ce98a..a105a5b2 100644 --- a/src/rtp.hh +++ b/src/rtp.hh @@ -4,6 +4,8 @@ #include "uvgrtp/util.hh" #include +#include +#include namespace uvgrtp { @@ -14,7 +16,7 @@ namespace uvgrtp { class rtp { public: - rtp(rtp_format_t fmt); + rtp(rtp_format_t fmt, std::shared_ptr> ssrc); ~rtp(); uint32_t get_ssrc() const; @@ -44,7 +46,7 @@ namespace uvgrtp { void set_default_clock_rate(rtp_format_t fmt); - uint32_t ssrc_; + std::shared_ptr> ssrc_; uint32_t ts_; uint16_t seq_; rtp_format_t fmt_;