mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch 'develop' into 4.0release
This commit is contained in:
commit
e73e7e47b1
26 changed files with 879 additions and 384 deletions
|
@ -159,6 +159,7 @@ For previous versions, please read:
|
|||
|
||||
## V4 changes
|
||||
|
||||
* v4.0, 2020-08-06, RTC: Refine error check. 4.0.37
|
||||
* v4.0, 2020-07-25, RTC: Support multiple address for client. 4.0.36
|
||||
* v4.0, 2020-07-11, Refine log context with random string. 4.0.35
|
||||
* v4.0, 2020-07-04, Fix some bugs for RTC. 4.0.34
|
||||
|
|
|
@ -666,14 +666,15 @@ if [ $SRS_FFMPEG_TOOL = YES ]; then
|
|||
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg/bin/ffmpeg ]]; then
|
||||
echo "ffmpeg-4.1 is ok.";
|
||||
else
|
||||
echo "Error: no FFmpeg found at /usr/local/bin/ffmpeg";
|
||||
echo "Warning: No FFmpeg found at /usr/local/bin/ffmpeg";
|
||||
echo " please copy it from srs-docker";
|
||||
echo " or download from http://ffmpeg.org/download.html";
|
||||
echo " or disable it by --without-ffmpeg";
|
||||
exit -1;
|
||||
fi
|
||||
# Always update the links.
|
||||
(cd ${SRS_OBJS} && rm -rf ffmpeg && ln -sf ${SRS_PLATFORM}/ffmpeg)
|
||||
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg ]]; then
|
||||
(cd ${SRS_OBJS} && rm -rf ffmpeg && ln -sf ${SRS_PLATFORM}/ffmpeg)
|
||||
fi
|
||||
fi
|
||||
|
||||
#####################################################################################
|
||||
|
|
|
@ -482,24 +482,24 @@ function apply_detail_options() {
|
|||
|
||||
# if specified export single file, export project first.
|
||||
if [ $SRS_EXPORT_LIBRTMP_SINGLE != NO ]; then
|
||||
echo "Not support --export-librtmp-single"
|
||||
exit -1
|
||||
echo "Warning: Ingore --export-librtmp-single"
|
||||
SRS_EXPORT_LIBRTMP_SINGLE=NO
|
||||
fi
|
||||
|
||||
# disable almost all features for export srs-librtmp.
|
||||
if [ $SRS_EXPORT_LIBRTMP_PROJECT != NO ]; then
|
||||
echo "Not support --export-librtmp-project"
|
||||
exit -1
|
||||
echo "Warning: Ingore --export-librtmp-project"
|
||||
SRS_EXPORT_LIBRTMP_PROJECT=NO
|
||||
fi
|
||||
|
||||
if [[ $SRS_LIBRTMP != NO ]]; then
|
||||
echo "Not support --librtmp"
|
||||
exit -1
|
||||
echo "Warning: Ingore --librtmp"
|
||||
SRS_LIBRTMP=NO
|
||||
fi
|
||||
|
||||
if [[ $SRS_RESEARCH != NO ]]; then
|
||||
echo "Not support --research"
|
||||
exit -1
|
||||
echo "Warning: Ingore --research"
|
||||
SRS_RESEARCH=NO
|
||||
fi
|
||||
|
||||
if [[ $SRS_SRTP_ASM == YES && $SRS_RTC == NO ]]; then
|
||||
|
@ -583,11 +583,13 @@ function check_option_conflicts() {
|
|||
fi
|
||||
|
||||
if [[ $SRS_CROSS_BUILD == YES && ($SRS_TOOL_CC == 'gcc' || $SRS_TOOL_CXX == 'g++' || $SRS_TOOL_AR == 'ar') ]]; then
|
||||
echo "For crossbuild, must not use default toolchain, cc: $SRS_TOOL_CC, cxx: $SRS_TOOL_CXX, ar: $SRS_TOOL_AR"; exit -1
|
||||
echo "Warning: For crossbuild, must not use default toolchain, cc: $SRS_TOOL_CC, cxx: $SRS_TOOL_CXX, ar: $SRS_TOOL_AR"
|
||||
SRS_CROSS_BUILD=NO
|
||||
fi
|
||||
|
||||
if [[ $SRS_NGINX == YES ]]; then
|
||||
echo "Don't support building NGINX, please use docker https://github.com/ossrs/srs-docker"; exit -1;
|
||||
echo "Warning: Don't support building NGINX, please use docker https://github.com/ossrs/srs-docker"
|
||||
SRS_NGINX=NO
|
||||
fi
|
||||
|
||||
# For OSX, recommend to use DTrace, https://blog.csdn.net/win_lin/article/details/53503869
|
||||
|
|
|
@ -49,7 +49,7 @@ USER_DIR = .
|
|||
CPPFLAGS += -I\$(GTEST_DIR)/include
|
||||
|
||||
# Flags passed to the C++ compiler.
|
||||
CXXFLAGS += ${CXXFLAGS} -Wextra ${UTEST_EXTRA_DEFINES}
|
||||
CXXFLAGS += ${CXXFLAGS} ${UTEST_EXTRA_DEFINES} -Wno-unused-private-field -Wno-unused-command-line-argument
|
||||
|
||||
# All tests produced by this Makefile. Remember to add new tests you
|
||||
# created to the list.
|
||||
|
|
|
@ -42,7 +42,6 @@ using namespace std;
|
|||
#include <srs_app_utility.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
|
||||
|
||||
// set the max packet size.
|
||||
#define SRS_UDP_MAX_PACKET_SIZE 65535
|
||||
|
||||
|
@ -506,8 +505,8 @@ srs_error_t SrsUdpMuxListener::cycle()
|
|||
uint64_t nn_loop = 0;
|
||||
srs_utime_t time_last = srs_get_system_time();
|
||||
|
||||
SrsErrorPithyPrint* epp = new SrsErrorPithyPrint();
|
||||
SrsAutoFree(SrsErrorPithyPrint, epp);
|
||||
SrsErrorPithyPrint* pp_pkt_handler_err = new SrsErrorPithyPrint();
|
||||
SrsAutoFree(SrsErrorPithyPrint, pp_pkt_handler_err);
|
||||
|
||||
set_socket_buffer();
|
||||
|
||||
|
@ -541,9 +540,15 @@ srs_error_t SrsUdpMuxListener::cycle()
|
|||
SrsContextRestore(cid);
|
||||
err = handler->on_udp_packet(&skt);
|
||||
}
|
||||
// Use pithy print to show more smart information.
|
||||
if (err != srs_success) {
|
||||
if (epp->can_print(err)) {
|
||||
srs_warn("handle udp pkt err: %s", srs_error_desc(err).c_str());
|
||||
if (pp_pkt_handler_err->can_print(err)) {
|
||||
// Append more information.
|
||||
if (true) {
|
||||
char* data = skt.data(); int size = skt.size();
|
||||
err = srs_error_wrap(err, "size=%u, data=[%s]", size, srs_string_dumps_hex(data, size, 8).c_str());
|
||||
}
|
||||
srs_warn("handle udp pkt, count=%u, err: %s", pp_pkt_handler_err->nn_count, srs_error_desc(err).c_str());
|
||||
}
|
||||
srs_freep(err);
|
||||
}
|
||||
|
|
|
@ -116,6 +116,7 @@ SrsStageInfo* SrsStageManager::fetch_or_create(int stage_id, bool* pnew)
|
|||
|
||||
SrsErrorPithyPrint::SrsErrorPithyPrint()
|
||||
{
|
||||
nn_count = 0;
|
||||
}
|
||||
|
||||
SrsErrorPithyPrint::~SrsErrorPithyPrint()
|
||||
|
@ -125,6 +126,12 @@ SrsErrorPithyPrint::~SrsErrorPithyPrint()
|
|||
bool SrsErrorPithyPrint::can_print(srs_error_t err)
|
||||
{
|
||||
int error_code = srs_error_code(err);
|
||||
return can_print(error_code);
|
||||
}
|
||||
|
||||
bool SrsErrorPithyPrint::can_print(int error_code)
|
||||
{
|
||||
nn_count++;
|
||||
|
||||
bool new_stage = false;
|
||||
SrsStageInfo* stage = stages.fetch_or_create(error_code, &new_stage);
|
||||
|
|
|
@ -68,6 +68,9 @@ public:
|
|||
// For example, we use it for error pithy print for each UDP packet processing.
|
||||
class SrsErrorPithyPrint
|
||||
{
|
||||
public:
|
||||
// The number of call of can_print().
|
||||
uint32_t nn_count;
|
||||
private:
|
||||
SrsStageManager stages;
|
||||
std::map<int, srs_utime_t> ticks;
|
||||
|
@ -77,6 +80,8 @@ public:
|
|||
public:
|
||||
// Whether specified stage is ready for print.
|
||||
bool can_print(srs_error_t err);
|
||||
// We also support int error code.
|
||||
bool can_print(int err);
|
||||
};
|
||||
|
||||
// The stage is used for a collection of object to do print,
|
||||
|
|
|
@ -195,6 +195,8 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
}
|
||||
|
||||
string local_sdp_str = os.str();
|
||||
// Filter the \r\n to \\r\\n for JSON.
|
||||
local_sdp_str = srs_string_replace(local_sdp_str.c_str(), "\r\n", "\\r\\n");
|
||||
|
||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
res->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id()));
|
||||
|
@ -207,7 +209,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
srs_trace("RTC username=%s, offer=%dB, answer=%dB", session->username().c_str(),
|
||||
remote_sdp_str.length(), local_sdp_str.length());
|
||||
srs_trace("RTC remote offer: %s", srs_string_replace(remote_sdp_str.c_str(), "\r\n", "\\r\\n").c_str());
|
||||
srs_trace("RTC local answer: %s", srs_string_replace(local_sdp_str.c_str(), "\r\n", "\\r\\n").c_str());
|
||||
srs_trace("RTC local answer: %s", local_sdp_str.c_str());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -545,6 +547,8 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt
|
|||
}
|
||||
|
||||
string local_sdp_str = os.str();
|
||||
// Filter the \r\n to \\r\\n for JSON.
|
||||
local_sdp_str = srs_string_replace(local_sdp_str.c_str(), "\r\n", "\\r\\n");
|
||||
|
||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||
res->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id()));
|
||||
|
@ -557,7 +561,7 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt
|
|||
srs_trace("RTC username=%s, offer=%dB, answer=%dB", session->username().c_str(),
|
||||
remote_sdp_str.length(), local_sdp_str.length());
|
||||
srs_trace("RTC remote offer: %s", srs_string_replace(remote_sdp_str.c_str(), "\r\n", "\\r\\n").c_str());
|
||||
srs_trace("RTC local answer: %s", srs_string_replace(local_sdp_str.c_str(), "\r\n", "\\r\\n").c_str());
|
||||
srs_trace("RTC local answer: %s", local_sdp_str.c_str());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ using namespace std;
|
|||
#include <srs_app_rtc_source.hpp>
|
||||
#include <srs_protocol_utility.hpp>
|
||||
|
||||
#define SRS_TICKID_RTCP 0
|
||||
|
||||
SrsSecurityTransport::SrsSecurityTransport(SrsRtcConnection* s)
|
||||
{
|
||||
session_ = s;
|
||||
|
@ -87,10 +89,13 @@ srs_error_t SrsSecurityTransport::start_active_handshake()
|
|||
srs_error_t SrsSecurityTransport::write_dtls_data(void* data, int size)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
if (size) {
|
||||
if ((err = session_->sendonly_skt->sendto(data, size, 0)) != srs_success) {
|
||||
return srs_error_wrap(err, "send dtls packet");
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = session_->sendonly_skt->sendto(data, size, 0)) != srs_success) {
|
||||
return srs_error_wrap(err, "send dtls packet");
|
||||
}
|
||||
|
||||
if (_srs_blackhole->blackhole) {
|
||||
|
@ -112,13 +117,13 @@ srs_error_t SrsSecurityTransport::on_dtls_handshake_done()
|
|||
if (handshake_done) {
|
||||
return err;
|
||||
}
|
||||
handshake_done = true;
|
||||
|
||||
// TODO: FIXME: Add cost for DTLS.
|
||||
srs_trace("RTC: DTLS handshake done.");
|
||||
|
||||
handshake_done = true;
|
||||
if ((err = srtp_initialize()) != srs_success) {
|
||||
return srs_error_wrap(err, "srtp init failed");
|
||||
return srs_error_wrap(err, "srtp init");
|
||||
}
|
||||
|
||||
return session_->on_connection_established();
|
||||
|
@ -145,7 +150,7 @@ srs_error_t SrsSecurityTransport::srtp_initialize()
|
|||
}
|
||||
|
||||
if ((err = srtp_->initialize(recv_key, send_key)) != srs_success) {
|
||||
return srs_error_wrap(err, "srtp init failed");
|
||||
return srs_error_wrap(err, "srtp init");
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -153,56 +158,32 @@ srs_error_t SrsSecurityTransport::srtp_initialize()
|
|||
|
||||
srs_error_t SrsSecurityTransport::protect_rtp(const char* plaintext, char* cipher, int& nb_cipher)
|
||||
{
|
||||
if (!srtp_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed");
|
||||
}
|
||||
|
||||
return srtp_->protect_rtp(plaintext, cipher, nb_cipher);
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::protect_rtcp(const char* plaintext, char* cipher, int& nb_cipher)
|
||||
{
|
||||
if (!srtp_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed");
|
||||
}
|
||||
|
||||
return srtp_->protect_rtcp(plaintext, cipher, nb_cipher);
|
||||
}
|
||||
|
||||
// TODO: FIXME: Merge with protect_rtp.
|
||||
srs_error_t SrsSecurityTransport::protect_rtp2(void* rtp_hdr, int* len_ptr)
|
||||
{
|
||||
if (!srtp_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect");
|
||||
}
|
||||
|
||||
return srtp_->protect_rtp2(rtp_hdr, len_ptr);
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::unprotect_rtp(const char* cipher, char* plaintext, int& nb_plaintext)
|
||||
{
|
||||
if (!srtp_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed");
|
||||
}
|
||||
|
||||
return srtp_->unprotect_rtp(cipher, plaintext, nb_plaintext);
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::unprotect_rtcp(const char* cipher, char* plaintext, int& nb_plaintext)
|
||||
{
|
||||
if (!srtp_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed");
|
||||
}
|
||||
|
||||
return srtp_->unprotect_rtcp(cipher, plaintext, nb_plaintext);
|
||||
}
|
||||
|
||||
SrsRtcPlayStreamStatistic::SrsRtcPlayStreamStatistic()
|
||||
{
|
||||
#if defined(SRS_DEBUG)
|
||||
debug_id = 0;
|
||||
#endif
|
||||
|
||||
nn_rtp_pkts = 0;
|
||||
nn_audios = nn_extras = 0;
|
||||
nn_videos = nn_samples = 0;
|
||||
|
@ -227,6 +208,7 @@ SrsRtcPlayStream::SrsRtcPlayStream(SrsRtcConnection* s, SrsContextId parent_cid)
|
|||
nack_enabled_ = false;
|
||||
|
||||
_srs_config->subscribe(this);
|
||||
timer_ = new SrsHourGlass(this, 1000 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
SrsRtcPlayStream::~SrsRtcPlayStream()
|
||||
|
@ -234,6 +216,7 @@ SrsRtcPlayStream::~SrsRtcPlayStream()
|
|||
_srs_config->unsubscribe(this);
|
||||
|
||||
srs_freep(trd);
|
||||
srs_freep(timer_);
|
||||
|
||||
if (true) {
|
||||
std::map<uint32_t, SrsRtcAudioSendTrack*>::iterator it;
|
||||
|
@ -321,6 +304,10 @@ srs_error_t SrsRtcPlayStream::start()
|
|||
return srs_error_wrap(err, "rtc_sender");
|
||||
}
|
||||
|
||||
if ((err = timer_->start()) != srs_success) {
|
||||
return srs_error_wrap(err, "start timer");
|
||||
}
|
||||
|
||||
if (_srs_rtc_hijacker) {
|
||||
if ((err = _srs_rtc_hijacker->on_start_play(session_, this, session_->req)) != srs_success) {
|
||||
return srs_error_wrap(err, "on start play");
|
||||
|
@ -345,18 +332,18 @@ srs_error_t SrsRtcPlayStream::cycle()
|
|||
SrsRequest* req = session_->req;
|
||||
|
||||
if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) {
|
||||
return srs_error_wrap(err, "rtc fetch source failed");
|
||||
return srs_error_wrap(err, "fetch source");
|
||||
}
|
||||
|
||||
SrsRtcConsumer* consumer = NULL;
|
||||
SrsAutoFree(SrsRtcConsumer, consumer);
|
||||
if ((err = source->create_consumer(consumer)) != srs_success) {
|
||||
return srs_error_wrap(err, "rtc create consumer, source url=%s", req->get_stream_url().c_str());
|
||||
return srs_error_wrap(err, "create consumer, source=%s", req->get_stream_url().c_str());
|
||||
}
|
||||
|
||||
// TODO: FIXME: Dumps the SPS/PPS from gop cache, without other frames.
|
||||
if ((err = source->consumer_dumps(consumer)) != srs_success) {
|
||||
return srs_error_wrap(err, "dumps consumer, source url=%s", req->get_stream_url().c_str());
|
||||
return srs_error_wrap(err, "dumps consumer, url=%s", req->get_stream_url().c_str());
|
||||
}
|
||||
|
||||
realtime = _srs_config->get_realtime_enabled(req->vhost, true);
|
||||
|
@ -439,11 +426,6 @@ srs_error_t SrsRtcPlayStream::send_packets(SrsRtcStream* source, const vector<Sr
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS is not OK, drop all messages.
|
||||
if (!session_->transport_) {
|
||||
return err;
|
||||
}
|
||||
|
||||
vector<SrsRtpPacket2*> send_pkts;
|
||||
// Covert kernel messages to RTP packets.
|
||||
for (int i = 0; i < (int)pkts.size(); i++) {
|
||||
|
@ -483,8 +465,13 @@ void SrsRtcPlayStream::nack_fetch(vector<SrsRtpPacket2*>& pkts, uint32_t ssrc, u
|
|||
if (true) {
|
||||
std::map<uint32_t, SrsRtcAudioSendTrack*>::iterator it;
|
||||
for (it = audio_tracks_.begin(); it != audio_tracks_.end(); ++it) {
|
||||
if (it->second->has_ssrc(ssrc)) {
|
||||
SrsRtpPacket2* pkt = it->second->fetch_rtp_packet(seq);
|
||||
SrsRtcAudioSendTrack* track = it->second;
|
||||
|
||||
if (track->has_ssrc(ssrc)) {
|
||||
// update recv nack statistic
|
||||
track->on_recv_nack();
|
||||
|
||||
SrsRtpPacket2* pkt = track->fetch_rtp_packet(seq);
|
||||
if (pkt != NULL) {
|
||||
pkts.push_back(pkt);
|
||||
}
|
||||
|
@ -496,8 +483,13 @@ void SrsRtcPlayStream::nack_fetch(vector<SrsRtpPacket2*>& pkts, uint32_t ssrc, u
|
|||
if (true) {
|
||||
std::map<uint32_t, SrsRtcVideoSendTrack*>::iterator it;
|
||||
for (it = video_tracks_.begin(); it != video_tracks_.end(); ++it) {
|
||||
if (it->second->has_ssrc(ssrc)) {
|
||||
SrsRtpPacket2* pkt = it->second->fetch_rtp_packet(seq);
|
||||
SrsRtcVideoSendTrack* track = it->second;
|
||||
|
||||
if (track->has_ssrc(ssrc)) {
|
||||
// update recv nack statistic
|
||||
track->on_recv_nack();
|
||||
|
||||
SrsRtpPacket2* pkt = track->fetch_rtp_packet(seq);
|
||||
if (pkt != NULL) {
|
||||
pkts.push_back(pkt);
|
||||
}
|
||||
|
@ -507,12 +499,54 @@ void SrsRtcPlayStream::nack_fetch(vector<SrsRtpPacket2*>& pkts, uint32_t ssrc, u
|
|||
}
|
||||
}
|
||||
|
||||
void SrsRtcPlayStream::set_all_tracks_status(bool status)
|
||||
{
|
||||
std::ostringstream merged_log;
|
||||
|
||||
// set video track status
|
||||
if (true) {
|
||||
std::map<uint32_t, SrsRtcVideoSendTrack*>::iterator it;
|
||||
for (it = video_tracks_.begin(); it != video_tracks_.end(); ++it) {
|
||||
SrsRtcVideoSendTrack* track = it->second;
|
||||
|
||||
bool previous = track->set_track_status(status);
|
||||
merged_log << "{track: " << track->get_track_id() << ", is_active: " << previous << "=>" << status << "},";
|
||||
}
|
||||
}
|
||||
|
||||
// set audio track status
|
||||
if (true) {
|
||||
std::map<uint32_t, SrsRtcAudioSendTrack*>::iterator it;
|
||||
for (it = audio_tracks_.begin(); it != audio_tracks_.end(); ++it) {
|
||||
SrsRtcAudioSendTrack* track = it->second;
|
||||
|
||||
bool previous = track->set_track_status(status);
|
||||
merged_log << "{track: " << track->get_track_id() << ", is_active: " << previous << "=>" << status << "},";
|
||||
}
|
||||
}
|
||||
|
||||
srs_trace("RTC: Init tracks %s ok", merged_log.str().c_str());
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcPlayStream::notify(int type, srs_utime_t interval, srs_utime_t tick)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!is_started) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcPlayStream::on_rtcp(char* data, int nb_data)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// TODO: Use SrsBuffer to parse it.
|
||||
char* ph = data;
|
||||
int nb_left = nb_data;
|
||||
|
||||
while (nb_left) {
|
||||
uint8_t payload_type = ph[1];
|
||||
uint16_t length_4bytes = (((uint16_t)ph[2]) << 8) | ph[3];
|
||||
|
@ -520,7 +554,8 @@ srs_error_t SrsRtcPlayStream::on_rtcp(char* data, int nb_data)
|
|||
int length = (length_4bytes + 1) * 4;
|
||||
|
||||
if (length > nb_data) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "invalid rtcp packet, length=%u", length);
|
||||
return srs_error_new(ERROR_RTC_RTCP, "invalid length=%u/%u, left=%u, bytes=%s",
|
||||
length, nb_data, nb_left, srs_string_dumps_hex(ph, nb_left, 8).c_str());
|
||||
}
|
||||
|
||||
srs_verbose("on rtcp, payload_type=%u", payload_type);
|
||||
|
@ -562,7 +597,7 @@ srs_error_t SrsRtcPlayStream::on_rtcp(char* data, int nb_data)
|
|||
}
|
||||
|
||||
if (err != srs_success) {
|
||||
return srs_error_wrap(err, "rtcp");
|
||||
return srs_error_wrap(err, "rtcp left=%u, bytes=%s", nb_left, srs_string_dumps_hex(ph, nb_left, 8).c_str());
|
||||
}
|
||||
|
||||
ph += length;
|
||||
|
@ -760,11 +795,12 @@ uint32_t SrsRtcPlayStream::get_video_publish_ssrc(uint32_t play_ssrc)
|
|||
|
||||
SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection* session)
|
||||
{
|
||||
report_timer = new SrsHourGlass(this, 200 * SRS_UTIME_MILLISECONDS);
|
||||
timer_ = new SrsHourGlass(this, 200 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
session_ = session;
|
||||
request_keyframe_ = false;
|
||||
|
||||
req = NULL;
|
||||
source = NULL;
|
||||
nn_simulate_nack_drop = 0;
|
||||
nack_enabled_ = false;
|
||||
|
@ -772,7 +808,6 @@ SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection* session)
|
|||
|
||||
nn_audio_frames = 0;
|
||||
twcc_id_ = 0;
|
||||
last_twcc_feedback_time_ = 0;
|
||||
twcc_fb_count_ = 0;
|
||||
}
|
||||
|
||||
|
@ -785,7 +820,7 @@ SrsRtcPublishStream::~SrsRtcPublishStream()
|
|||
}
|
||||
|
||||
srs_freep(req);
|
||||
srs_freep(report_timer);
|
||||
srs_freep(timer_);
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcStreamDescription* stream_desc)
|
||||
|
@ -795,7 +830,7 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcStreamDescripti
|
|||
req = r->copy();
|
||||
|
||||
audio_tracks_.push_back(new SrsRtcAudioRecvTrack(session_, stream_desc->audio_track_desc_));
|
||||
for (int i = 0; i < stream_desc->video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||
SrsRtcTrackDescription* desc = stream_desc->video_track_descs_.at(i);
|
||||
video_tracks_.push_back(new SrsRtcVideoRecvTrack(session_, desc));
|
||||
}
|
||||
|
@ -804,7 +839,7 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcStreamDescripti
|
|||
uint32_t media_ssrc = 0;
|
||||
// because audio_track_desc have not twcc id, for example, h5demo
|
||||
// fetch twcc_id from video track description,
|
||||
for (int i = 0; i < stream_desc->video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||
SrsRtcTrackDescription* desc = stream_desc->video_track_descs_.at(i);
|
||||
twcc_id = desc->get_rtp_extension_id(kTWCCExt);
|
||||
media_ssrc = desc->ssrc_;
|
||||
|
@ -831,17 +866,16 @@ srs_error_t SrsRtcPublishStream::start()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If report_timer started, we think the publisher is started.
|
||||
if (is_started) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = report_timer->tick(0 * SRS_UTIME_MILLISECONDS)) != srs_success) {
|
||||
return srs_error_wrap(err, "hourglass tick");
|
||||
if ((err = timer_->tick(SRS_TICKID_RTCP, 200 * SRS_UTIME_MILLISECONDS)) != srs_success) {
|
||||
return srs_error_wrap(err, "rtcp tick");
|
||||
}
|
||||
|
||||
if ((err = report_timer->start()) != srs_success) {
|
||||
return srs_error_wrap(err, "start report_timer");
|
||||
if ((err = timer_->start()) != srs_success) {
|
||||
return srs_error_wrap(err, "start timer");
|
||||
}
|
||||
|
||||
if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) {
|
||||
|
@ -865,18 +899,51 @@ srs_error_t SrsRtcPublishStream::start()
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsRtcPublishStream::set_all_tracks_status(bool status)
|
||||
{
|
||||
std::ostringstream merged_log;
|
||||
|
||||
// set video track status
|
||||
if (true) {
|
||||
std::vector<SrsRtcVideoRecvTrack*>::iterator it;
|
||||
for (it = video_tracks_.begin(); it != video_tracks_.end(); ++it) {
|
||||
SrsRtcVideoRecvTrack* track = *it;
|
||||
|
||||
bool previous = track->set_track_status(status);
|
||||
merged_log << "{track: " << track->get_track_id() << ", is_active: " << previous << "=>" << status << "},";
|
||||
}
|
||||
}
|
||||
|
||||
// set audio track status
|
||||
if (true) {
|
||||
std::vector<SrsRtcAudioRecvTrack*>::iterator it;
|
||||
for (it = audio_tracks_.begin(); it != audio_tracks_.end(); ++it) {
|
||||
SrsRtcAudioRecvTrack* track = *it;
|
||||
|
||||
bool previous = track->set_track_status(status);
|
||||
merged_log << "{track: " << track->get_track_id() << ", is_active: " << previous << "=>" << status << "},";
|
||||
}
|
||||
}
|
||||
|
||||
srs_trace("RTC: Init tracks %s ok", merged_log.str().c_str());
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcPublishStream::send_rtcp_rr()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
for (int i = 0; i < video_tracks_.size(); ++i) {
|
||||
for (int i = 0; i < (int)video_tracks_.size(); ++i) {
|
||||
SrsRtcVideoRecvTrack* track = video_tracks_.at(i);
|
||||
track->send_rtcp_rr();
|
||||
if ((err = track->send_rtcp_rr()) != srs_success) {
|
||||
return srs_error_wrap(err, "track=%s", track->get_track_id().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < audio_tracks_.size(); ++i) {
|
||||
for (int i = 0; i < (int)audio_tracks_.size(); ++i) {
|
||||
SrsRtcAudioRecvTrack* track = audio_tracks_.at(i);
|
||||
track->send_rtcp_rr();
|
||||
if ((err = track->send_rtcp_rr()) != srs_success) {
|
||||
return srs_error_wrap(err, "track=%s", track->get_track_id().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
session_->stat_->nn_rr++;
|
||||
|
@ -888,14 +955,18 @@ srs_error_t SrsRtcPublishStream::send_rtcp_xr_rrtr()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
for (int i = 0; i < video_tracks_.size(); ++i) {
|
||||
for (int i = 0; i < (int)video_tracks_.size(); ++i) {
|
||||
SrsRtcVideoRecvTrack* track = video_tracks_.at(i);
|
||||
track->send_rtcp_xr_rrtr();
|
||||
if ((err = track->send_rtcp_xr_rrtr()) != srs_success) {
|
||||
return srs_error_wrap(err, "track=%s", track->get_track_id().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < audio_tracks_.size(); ++i) {
|
||||
for (int i = 0; i < (int)audio_tracks_.size(); ++i) {
|
||||
SrsRtcAudioRecvTrack* track = audio_tracks_.at(i);
|
||||
track->send_rtcp_xr_rrtr();
|
||||
if ((err = track->send_rtcp_xr_rrtr()) != srs_success) {
|
||||
return srs_error_wrap(err, "track=%s", track->get_track_id().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
session_->stat_->nn_xr++;
|
||||
|
@ -974,8 +1045,24 @@ srs_error_t SrsRtcPublishStream::on_rtp(char* data, int nb_data)
|
|||
_srs_blackhole->sendto(unprotected_buf, nb_unprotected_buf);
|
||||
}
|
||||
|
||||
char* buf = unprotected_buf;
|
||||
int nb_buf = nb_unprotected_buf;
|
||||
// Handle the plaintext RTP packet.
|
||||
if ((err = do_on_rtp(unprotected_buf, nb_unprotected_buf)) != srs_success) {
|
||||
int nb_header = h.nb_bytes();
|
||||
const char* body = unprotected_buf + nb_header;
|
||||
int nb_body = nb_unprotected_buf - nb_header;
|
||||
return srs_error_wrap(err, "cipher=%u, plaintext=%u, body=%s", nb_data, nb_unprotected_buf,
|
||||
srs_string_dumps_hex(body, nb_body, 8).c_str());
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcPublishStream::do_on_rtp(char* plaintext, int nb_plaintext)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
char* buf = plaintext;
|
||||
int nb_buf = nb_plaintext;
|
||||
|
||||
// Decode the RTP packet from buffer.
|
||||
SrsRtpPacket2* pkt = new SrsRtpPacket2();
|
||||
|
@ -1045,30 +1132,25 @@ void SrsRtcPublishStream::on_before_decode_payload(SrsRtpPacket2* pkt, SrsBuffer
|
|||
srs_error_t SrsRtcPublishStream::send_periodic_twcc()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
srs_utime_t now = srs_get_system_time();
|
||||
if(0 == last_twcc_feedback_time_) {
|
||||
last_twcc_feedback_time_ = now;
|
||||
return err;
|
||||
}
|
||||
srs_utime_t diff = now - last_twcc_feedback_time_;
|
||||
if( diff >= 50 * SRS_UTIME_MILLISECONDS) {
|
||||
last_twcc_feedback_time_ = now;
|
||||
char pkt[kRtcpPacketSize];
|
||||
SrsBuffer *buffer = new SrsBuffer(pkt, sizeof(pkt));
|
||||
SrsAutoFree(SrsBuffer, buffer);
|
||||
rtcp_twcc_.set_feedback_count(twcc_fb_count_);
|
||||
twcc_fb_count_++;
|
||||
if((err = rtcp_twcc_.encode(buffer)) != srs_success) {
|
||||
return srs_error_wrap(err, "fail to generate twcc feedback packet");
|
||||
}
|
||||
int nb_protected_buf = buffer->pos();
|
||||
char protected_buf[kRtpPacketSize];
|
||||
if (session_->transport_->protect_rtcp(pkt, protected_buf, nb_protected_buf) == srs_success) {
|
||||
session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
}
|
||||
|
||||
char pkt[kRtcpPacketSize];
|
||||
SrsBuffer *buffer = new SrsBuffer(pkt, sizeof(pkt));
|
||||
SrsAutoFree(SrsBuffer, buffer);
|
||||
|
||||
rtcp_twcc_.set_feedback_count(twcc_fb_count_);
|
||||
twcc_fb_count_++;
|
||||
|
||||
if((err = rtcp_twcc_.encode(buffer)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode, count=%u", twcc_fb_count_);
|
||||
}
|
||||
|
||||
return err;
|
||||
int nb_protected_buf = buffer->pos();
|
||||
char protected_buf[kRtpPacketSize];
|
||||
if ((err = session_->transport_->protect_rtcp(pkt, protected_buf, nb_protected_buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "protect rtcp, size=%u", nb_protected_buf);
|
||||
}
|
||||
|
||||
return session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcPublishStream::on_rtcp(char* data, int nb_data)
|
||||
|
@ -1427,14 +1509,28 @@ srs_error_t SrsRtcPublishStream::notify(int type, srs_utime_t interval, srs_utim
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// TODO: FIXME: Check error.
|
||||
send_rtcp_rr();
|
||||
send_rtcp_xr_rrtr();
|
||||
if (!is_started) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO: FIXME: Check error.
|
||||
// We should not depends on the received packet,
|
||||
// instead we should send feedback every Nms.
|
||||
send_periodic_twcc();
|
||||
if (type == SRS_TICKID_RTCP) {
|
||||
if ((err = send_rtcp_rr()) != srs_success) {
|
||||
srs_warn("RR err %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
}
|
||||
|
||||
if ((err = send_rtcp_xr_rrtr()) != srs_success) {
|
||||
srs_warn("XR err %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
}
|
||||
|
||||
// We should not depends on the received packet,
|
||||
// instead we should send feedback every Nms.
|
||||
if ((err = send_periodic_twcc()) != srs_success) {
|
||||
srs_warn("TWCC err %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -1455,7 +1551,7 @@ void SrsRtcPublishStream::simulate_drop_packet(SrsRtpHeader* h, int nn_bytes)
|
|||
|
||||
SrsRtcVideoRecvTrack* SrsRtcPublishStream::get_video_track(uint32_t ssrc)
|
||||
{
|
||||
for (int i = 0; i < video_tracks_.size(); ++i) {
|
||||
for (int i = 0; i < (int)video_tracks_.size(); ++i) {
|
||||
SrsRtcVideoRecvTrack* track = video_tracks_.at(i);
|
||||
if (track->has_ssrc(ssrc)) {
|
||||
return track;
|
||||
|
@ -1467,7 +1563,7 @@ SrsRtcVideoRecvTrack* SrsRtcPublishStream::get_video_track(uint32_t ssrc)
|
|||
|
||||
SrsRtcAudioRecvTrack* SrsRtcPublishStream::get_audio_track(uint32_t ssrc)
|
||||
{
|
||||
for (int i = 0; i < audio_tracks_.size(); ++i) {
|
||||
for (int i = 0; i < (int)audio_tracks_.size(); ++i) {
|
||||
SrsRtcAudioRecvTrack* track = audio_tracks_.at(i);
|
||||
if (track->has_ssrc(ssrc)) {
|
||||
return track;
|
||||
|
@ -1555,6 +1651,7 @@ SrsRtcConnection::SrsRtcConnection(SrsRtcServer* s, SrsContextId context_id)
|
|||
encrypt = true;
|
||||
cid = context_id;
|
||||
stat_ = new SrsRtcConnectionStatistic();
|
||||
timer_ = new SrsHourGlass(this, 1000 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
source_ = NULL;
|
||||
publisher_ = NULL;
|
||||
|
@ -1570,10 +1667,12 @@ SrsRtcConnection::SrsRtcConnection(SrsRtcServer* s, SrsContextId context_id)
|
|||
|
||||
twcc_id_ = 0;
|
||||
nn_simulate_player_nack_drop = 0;
|
||||
pp_address_change = new SrsErrorPithyPrint();
|
||||
}
|
||||
|
||||
SrsRtcConnection::~SrsRtcConnection()
|
||||
{
|
||||
srs_freep(timer_);
|
||||
srs_freep(player_);
|
||||
srs_freep(publisher_);
|
||||
srs_freep(transport_);
|
||||
|
@ -1587,6 +1686,8 @@ SrsRtcConnection::~SrsRtcConnection()
|
|||
SrsUdpMuxSocket* addr = it->second;
|
||||
srs_freep(addr);
|
||||
}
|
||||
|
||||
srs_freep(pp_address_change);
|
||||
}
|
||||
|
||||
SrsSdp* SrsRtcConnection::get_local_sdp()
|
||||
|
@ -1775,6 +1876,10 @@ srs_error_t SrsRtcConnection::initialize(SrsRtcStream* source, SrsRequest* r, bo
|
|||
return srs_error_wrap(err, "init");
|
||||
}
|
||||
|
||||
if ((err = timer_->start()) != srs_success) {
|
||||
return srs_error_wrap(err, "start timer");
|
||||
}
|
||||
|
||||
// TODO: FIXME: Support reload.
|
||||
session_timeout = _srs_config->get_rtc_stun_timeout(req->vhost);
|
||||
last_stun_time = srs_get_system_time();
|
||||
|
@ -1820,14 +1925,10 @@ srs_error_t SrsRtcConnection::on_rtcp(char* data, int nb_data)
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (transport_ == NULL) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done");
|
||||
}
|
||||
|
||||
char unprotected_buf[kRtpPacketSize];
|
||||
int nb_unprotected_buf = nb_data;
|
||||
if ((err = transport_->unprotect_rtcp(data, unprotected_buf, nb_unprotected_buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "rtcp unprotect failed");
|
||||
return srs_error_wrap(err, "rtcp unprotect");
|
||||
}
|
||||
|
||||
if (_srs_blackhole->blackhole) {
|
||||
|
@ -1835,11 +1936,16 @@ srs_error_t SrsRtcConnection::on_rtcp(char* data, int nb_data)
|
|||
}
|
||||
|
||||
if (player_) {
|
||||
return player_->on_rtcp(unprotected_buf, nb_unprotected_buf);
|
||||
err = player_->on_rtcp(unprotected_buf, nb_unprotected_buf);
|
||||
}
|
||||
|
||||
if (publisher_) {
|
||||
return publisher_->on_rtcp(unprotected_buf, nb_unprotected_buf);
|
||||
err = publisher_->on_rtcp(unprotected_buf, nb_unprotected_buf);
|
||||
}
|
||||
|
||||
if (err != srs_success) {
|
||||
return srs_error_wrap(err, "cipher=%u, plaintext=%u, bytes=%s", nb_data, nb_unprotected_buf,
|
||||
srs_string_dumps_hex(unprotected_buf, nb_unprotected_buf, 8).c_str());
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -1853,11 +1959,7 @@ srs_error_t SrsRtcConnection::on_rtcp_feedback(char* data, int nb_data)
|
|||
srs_error_t SrsRtcConnection::on_rtp(char* data, int nb_data)
|
||||
{
|
||||
if (publisher_ == NULL) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "rtc publisher null");
|
||||
}
|
||||
|
||||
if (transport_ == NULL) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done");
|
||||
return srs_error_new(ERROR_RTC_RTCP, "no publisher");
|
||||
}
|
||||
|
||||
//TODO: FIXME: add unprotect_rtcp.
|
||||
|
@ -1924,14 +2026,6 @@ void SrsRtcConnection::update_sendonly_socket(SrsUdpMuxSocket* skt)
|
|||
return;
|
||||
}
|
||||
|
||||
// Detect address change.
|
||||
if (prev_peer_id.empty()) {
|
||||
srs_trace("RTC: session address init %s", peer_id.c_str());
|
||||
} else {
|
||||
srs_trace("RTC: session address changed, update %s -> %s, total %u", prev_peer_id.c_str(),
|
||||
peer_id.c_str(), peer_addresses_.size());
|
||||
}
|
||||
|
||||
// Find object from cache.
|
||||
SrsUdpMuxSocket* addr_cache = NULL;
|
||||
if (true) {
|
||||
|
@ -1941,6 +2035,14 @@ void SrsRtcConnection::update_sendonly_socket(SrsUdpMuxSocket* skt)
|
|||
}
|
||||
}
|
||||
|
||||
// Show address change log.
|
||||
if (prev_peer_id.empty()) {
|
||||
srs_trace("RTC: session address init %s", peer_id.c_str());
|
||||
} else if (pp_address_change->can_print(skt->get_peer_port())) {
|
||||
srs_trace("RTC: session address change %s -> %s, cached=%d, nn_change=%u, nn_address=%u", prev_peer_id.c_str(),
|
||||
peer_id.c_str(), (addr_cache? 1:0), pp_address_change->nn_count, peer_addresses_.size());
|
||||
}
|
||||
|
||||
// If no cache, build cache and setup the relations in connection.
|
||||
if (!addr_cache) {
|
||||
peer_addresses_[peer_id] = addr_cache = skt->copy_sendonly();
|
||||
|
@ -1951,13 +2053,14 @@ void SrsRtcConnection::update_sendonly_socket(SrsUdpMuxSocket* skt)
|
|||
sendonly_skt = addr_cache;
|
||||
}
|
||||
|
||||
void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc)
|
||||
srs_error_t SrsRtcConnection::notify(int type, srs_utime_t interval, srs_utime_t tick)
|
||||
{
|
||||
// If DTLS is not OK, drop all messages.
|
||||
if (!transport_) {
|
||||
return;
|
||||
}
|
||||
srs_error_t err = srs_success;
|
||||
return err;
|
||||
}
|
||||
|
||||
void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc, uint32_t& sent_nacks)
|
||||
{
|
||||
// @see: https://tools.ietf.org/html/rfc4585#section-6.1
|
||||
vector<uint16_t> nack_seqs;
|
||||
nack->get_nack_seqs(nack_seqs);
|
||||
|
@ -1996,6 +2099,7 @@ void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ss
|
|||
}
|
||||
|
||||
++iter;
|
||||
++sent_nacks;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2003,11 +2107,6 @@ srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS is not OK, drop all messages.
|
||||
if (!transport_) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// @see https://tools.ietf.org/html/rfc3550#section-6.4.2
|
||||
char buf[kRtpPacketSize];
|
||||
SrsBuffer stream(buf, sizeof(buf));
|
||||
|
@ -2016,8 +2115,6 @@ srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_
|
|||
stream.write_2bytes(7);
|
||||
stream.write_4bytes(ssrc); // TODO: FIXME: Should be 1?
|
||||
|
||||
// TODO: FIXME: Implements it.
|
||||
// TODO: FIXME: See https://github.com/ossrs/srs/blob/f81d35d20f04ebec01915cb78a882e45b7ee8800/trunk/src/app/srs_app_rtc_queue.cpp
|
||||
uint8_t fraction_lost = 0;
|
||||
uint32_t cumulative_number_of_packets_lost = 0 & 0x7FFFFF;
|
||||
uint32_t extended_highest_sequence = rtp_queue->get_extended_highest_sequence();
|
||||
|
@ -2040,7 +2137,7 @@ srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_
|
|||
stream.write_4bytes(rr_lsr);
|
||||
stream.write_4bytes(rr_dlsr);
|
||||
|
||||
srs_verbose("RR ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, extended_highest_sequence=%u, interarrival_jitter=%u",
|
||||
srs_info("RR ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, extended_highest_sequence=%u, interarrival_jitter=%u",
|
||||
ssrc, fraction_lost, cumulative_number_of_packets_lost, extended_highest_sequence, interarrival_jitter);
|
||||
|
||||
char protected_buf[kRtpPacketSize];
|
||||
|
@ -2049,20 +2146,13 @@ srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_
|
|||
return srs_error_wrap(err, "protect rtcp rr");
|
||||
}
|
||||
|
||||
// TDOO: FIXME: Check error.
|
||||
sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
return err;
|
||||
return sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcConnection::send_rtcp_xr_rrtr(uint32_t ssrc)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS is not OK, drop all messages.
|
||||
if (!transport_) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-2
|
||||
|
||||
|
@ -2109,21 +2199,13 @@ srs_error_t SrsRtcConnection::send_rtcp_xr_rrtr(uint32_t ssrc)
|
|||
return srs_error_wrap(err, "protect rtcp xr");
|
||||
}
|
||||
|
||||
// TDOO: FIXME: Check error.
|
||||
sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
|
||||
return err;
|
||||
return sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcConnection::send_rtcp_fb_pli(uint32_t ssrc)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS is not OK, drop all messages.
|
||||
if (!transport_) {
|
||||
return err;
|
||||
}
|
||||
|
||||
char buf[kRtpPacketSize];
|
||||
SrsBuffer stream(buf, sizeof(buf));
|
||||
stream.write_1bytes(0x81);
|
||||
|
@ -2144,10 +2226,7 @@ srs_error_t SrsRtcConnection::send_rtcp_fb_pli(uint32_t ssrc)
|
|||
return srs_error_wrap(err, "protect rtcp psfb pli");
|
||||
}
|
||||
|
||||
// TDOO: FIXME: Check error.
|
||||
sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
|
||||
return err;
|
||||
return sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||
}
|
||||
|
||||
void SrsRtcConnection::simulate_nack_drop(int nn)
|
||||
|
@ -2226,6 +2305,17 @@ srs_error_t SrsRtcConnection::do_send_packets(const std::vector<SrsRtpPacket2*>&
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsRtcConnection::set_all_tracks_status(bool status)
|
||||
{
|
||||
if (player_) {
|
||||
player_->set_all_tracks_status(status);
|
||||
}
|
||||
|
||||
if (publisher_) {
|
||||
publisher_->set_all_tracks_status(status);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SRS_OSX
|
||||
// These functions are similar to the older byteorder(3) family of functions.
|
||||
// For example, be32toh() is identical to ntohl().
|
||||
|
@ -2430,7 +2520,7 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRequest* req, cons
|
|||
track_desc->create_auxiliary_payload(remote_media_desc.find_media_with_encoding_name("ulpfec"));
|
||||
|
||||
std::string track_id;
|
||||
for (int i = 0; i < remote_media_desc.ssrc_infos_.size(); ++i) {
|
||||
for (int i = 0; i < (int)remote_media_desc.ssrc_infos_.size(); ++i) {
|
||||
SrsSSRCInfo ssrc_info = remote_media_desc.ssrc_infos_.at(i);
|
||||
// ssrc have same track id, will be description in the same track description.
|
||||
if(track_id != ssrc_info.msid_tracker_) {
|
||||
|
@ -2449,7 +2539,7 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRequest* req, cons
|
|||
}
|
||||
|
||||
// set track fec_ssrc and rtx_ssrc
|
||||
for (int i = 0; i < remote_media_desc.ssrc_groups_.size(); ++i) {
|
||||
for (int i = 0; i < (int)remote_media_desc.ssrc_groups_.size(); ++i) {
|
||||
SrsSSRCGroup ssrc_group = remote_media_desc.ssrc_groups_.at(i);
|
||||
SrsRtcTrackDescription* track_desc = stream_desc->find_track_description_by_ssrc(ssrc_group.ssrcs_[0]);
|
||||
if (!track_desc) {
|
||||
|
@ -2526,7 +2616,7 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp
|
|||
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
|
||||
}
|
||||
|
||||
for (int i = 0; i < stream_desc->video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||
SrsRtcTrackDescription* video_track = stream_desc->video_track_descs_.at(i);
|
||||
|
||||
local_sdp.media_descs_.push_back(SrsMediaDesc("video"));
|
||||
|
@ -2622,7 +2712,7 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRequest* req, const S
|
|||
track_descs = source->get_track_desc("video", "H264");
|
||||
}
|
||||
|
||||
for (int i = 0; i < track_descs.size(); ++i) {
|
||||
for (int i = 0; i < (int)track_descs.size(); ++i) {
|
||||
SrsRtcTrackDescription* track = track_descs[i]->copy();
|
||||
track->mid_ = remote_media_desc.mid_;
|
||||
uint32_t publish_ssrc = track->ssrc_;
|
||||
|
@ -2678,7 +2768,7 @@ srs_error_t SrsRtcConnection::fetch_source_capability(SrsRequest* req, std::map<
|
|||
std::vector<SrsRtcTrackDescription*> video_track_desc = source->get_track_desc("video", "H264");
|
||||
|
||||
track_descs.insert(track_descs.end(), video_track_desc.begin(), video_track_desc.end());
|
||||
for (int i = 0; i < track_descs.size(); ++i) {
|
||||
for (int i = 0; i < (int)track_descs.size(); ++i) {
|
||||
SrsRtcTrackDescription* track = track_descs[i]->copy();
|
||||
uint32_t publish_ssrc = track->ssrc_;
|
||||
|
||||
|
@ -2802,7 +2892,7 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& l
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < stream_desc->video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||
SrsRtcTrackDescription* track = stream_desc->video_track_descs_[i];
|
||||
|
||||
// for plan b, we only add one m=
|
||||
|
|
|
@ -59,6 +59,7 @@ class SrsRtpRingBuffer;
|
|||
class SrsRtcConsumer;
|
||||
class SrsRtcAudioSendTrack;
|
||||
class SrsRtcVideoSendTrack;
|
||||
class SrsErrorPithyPrint;
|
||||
|
||||
const uint8_t kSR = 200;
|
||||
const uint8_t kRR = 201;
|
||||
|
@ -130,11 +131,6 @@ private:
|
|||
// A group of RTP packets for outgoing(send to players).
|
||||
class SrsRtcPlayStreamStatistic
|
||||
{
|
||||
public:
|
||||
#if defined(SRS_DEBUG)
|
||||
// Debug id.
|
||||
uint32_t debug_id;
|
||||
#endif
|
||||
public:
|
||||
// The total bytes of AVFrame packets.
|
||||
int nn_bytes;
|
||||
|
@ -165,13 +161,14 @@ public:
|
|||
};
|
||||
|
||||
// A RTC play stream, client pull and play stream from SRS.
|
||||
class SrsRtcPlayStream : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
|
||||
class SrsRtcPlayStream : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler, virtual public ISrsHourGlass
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
SrsContextId _parent_cid;
|
||||
SrsCoroutine* trd;
|
||||
SrsRtcConnection* session_;
|
||||
private:
|
||||
SrsHourGlass* timer_;
|
||||
// key: publish_ssrc, value: send track to process rtp/rtcp
|
||||
std::map<uint32_t, SrsRtcAudioSendTrack*> audio_tracks_;
|
||||
std::map<uint32_t, SrsRtcVideoSendTrack*> video_tracks_;
|
||||
|
@ -206,6 +203,11 @@ private:
|
|||
srs_error_t send_packets(SrsRtcStream* source, const std::vector<SrsRtpPacket2*>& pkts, SrsRtcPlayStreamStatistic& info);
|
||||
public:
|
||||
void nack_fetch(std::vector<SrsRtpPacket2*>& pkts, uint32_t ssrc, uint16_t seq);
|
||||
// Directly set the status of track, generally for init to set the default value.
|
||||
void set_all_tracks_status(bool status);
|
||||
// interface ISrsHourGlass
|
||||
public:
|
||||
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick);
|
||||
public:
|
||||
srs_error_t on_rtcp(char* data, int nb_data);
|
||||
private:
|
||||
|
@ -221,7 +223,7 @@ private:
|
|||
class SrsRtcPublishStream : virtual public ISrsHourGlass, virtual public ISrsRtpPacketDecodeHandler, virtual public ISrsRtcPublishStream
|
||||
{
|
||||
private:
|
||||
SrsHourGlass* report_timer;
|
||||
SrsHourGlass* timer_;
|
||||
uint64_t nn_audio_frames;
|
||||
private:
|
||||
SrsRtcConnection* session_;
|
||||
|
@ -240,7 +242,6 @@ private:
|
|||
std::vector<SrsRtcAudioRecvTrack*> audio_tracks_;
|
||||
std::vector<SrsRtcVideoRecvTrack*> video_tracks_;
|
||||
private:
|
||||
srs_utime_t last_twcc_feedback_time_;
|
||||
int twcc_id_;
|
||||
uint8_t twcc_fb_count_;
|
||||
SrsRtcpTWCC rtcp_twcc_;
|
||||
|
@ -252,12 +253,16 @@ public:
|
|||
public:
|
||||
srs_error_t initialize(SrsRequest* req, SrsRtcStreamDescription* stream_desc);
|
||||
srs_error_t start();
|
||||
// Directly set the status of track, generally for init to set the default value.
|
||||
void set_all_tracks_status(bool status);
|
||||
private:
|
||||
void check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc);
|
||||
srs_error_t send_rtcp_rr();
|
||||
srs_error_t send_rtcp_xr_rrtr();
|
||||
public:
|
||||
srs_error_t on_rtp(char* buf, int nb_buf);
|
||||
private:
|
||||
srs_error_t do_on_rtp(char* plaintext, int nb_plaintext);
|
||||
public:
|
||||
virtual void on_before_decode_payload(SrsRtpPacket2* pkt, SrsBuffer* buf, ISrsRtpPayloader** ppayload);
|
||||
private:
|
||||
srs_error_t send_periodic_twcc();
|
||||
|
@ -305,7 +310,7 @@ public:
|
|||
};
|
||||
|
||||
// A RTC Peer Connection, SDP level object.
|
||||
class SrsRtcConnection
|
||||
class SrsRtcConnection : virtual public ISrsHourGlass
|
||||
{
|
||||
friend class SrsSecurityTransport;
|
||||
friend class SrsRtcPlayStream;
|
||||
|
@ -320,6 +325,7 @@ private:
|
|||
SrsRtcPlayStream* player_;
|
||||
SrsRtcPublishStream* publisher_;
|
||||
bool is_publisher_;
|
||||
SrsHourGlass* timer_;
|
||||
private:
|
||||
// The local:remote username, such as m5x0n128:jvOm where local name is m5x0n128.
|
||||
std::string username_;
|
||||
|
@ -348,6 +354,8 @@ private:
|
|||
int twcc_id_;
|
||||
// Simulators.
|
||||
int nn_simulate_player_nack_drop;
|
||||
// Pithy print for address change, use port as error code.
|
||||
SrsErrorPithyPrint* pp_address_change;
|
||||
public:
|
||||
SrsRtcConnection(SrsRtcServer* s, SrsContextId context_id);
|
||||
virtual ~SrsRtcConnection();
|
||||
|
@ -388,9 +396,12 @@ public:
|
|||
srs_error_t start_publish();
|
||||
bool is_stun_timeout();
|
||||
void update_sendonly_socket(SrsUdpMuxSocket* skt);
|
||||
// interface ISrsHourGlass
|
||||
public:
|
||||
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick);
|
||||
public:
|
||||
// send rtcp
|
||||
void check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc);
|
||||
void check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc, uint32_t& sent_nacks);
|
||||
srs_error_t send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_queue, const uint64_t& last_send_systime, const SrsNtp& last_send_ntp);
|
||||
srs_error_t send_rtcp_xr_rrtr(uint32_t ssrc);
|
||||
srs_error_t send_rtcp_fb_pli(uint32_t ssrc);
|
||||
|
@ -399,6 +410,8 @@ public:
|
|||
void simulate_nack_drop(int nn);
|
||||
void simulate_player_drop_packet(SrsRtpHeader* h, int nn_bytes);
|
||||
srs_error_t do_send_packets(const std::vector<SrsRtpPacket2*>& pkts, SrsRtcPlayStreamStatistic& info);
|
||||
// Directly set the status of play track, generally for init to set the default value.
|
||||
void set_all_tracks_status(bool status);
|
||||
private:
|
||||
srs_error_t on_binding_request(SrsStunPacket* r);
|
||||
// publish media capabilitiy negotiate
|
||||
|
|
|
@ -35,6 +35,7 @@ using namespace std;
|
|||
|
||||
#include <srtp2/srtp.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
// The return value of verify_callback controls the strategy of the further verification process. If verify_callback
|
||||
// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is
|
||||
|
@ -161,7 +162,7 @@ srs_error_t SrsDtlsCertificate::initialize()
|
|||
int serial = rand();
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(dtls_cert), serial);
|
||||
|
||||
const std::string& aor = "ossrs.net";
|
||||
const std::string& aor = RTMP_SIG_SRS_DOMAIN;
|
||||
X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *) aor.data(), aor.size(), -1, 0);
|
||||
|
||||
X509_set_issuer_name(dtls_cert, subject);
|
||||
|
@ -385,10 +386,6 @@ srs_error_t SrsDtls::do_handshake()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!callback) {
|
||||
return srs_error_new(ERROR_RTC_DTLS, "no callback");
|
||||
}
|
||||
|
||||
int ret = SSL_do_handshake(dtls);
|
||||
|
||||
unsigned char *out_bio_data;
|
||||
|
@ -419,7 +416,7 @@ srs_error_t SrsDtls::do_handshake()
|
|||
|
||||
if (out_bio_len) {
|
||||
if ((err = callback->write_dtls_data(out_bio_data, out_bio_len)) != srs_success) {
|
||||
return srs_error_wrap(err, "dtls send");
|
||||
return srs_error_wrap(err, "dtls send size=%u", out_bio_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,7 +447,7 @@ srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
|
|||
|
||||
if (nb > 0 && callback) {
|
||||
if ((err = callback->on_dtls_application_data(dtls_read_buf, nb)) != srs_success) {
|
||||
return srs_error_wrap(err, "dtls application data process");
|
||||
return srs_error_wrap(err, "on DTLS data, size=%u", nb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +474,7 @@ srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key)
|
|||
unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server
|
||||
static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp";
|
||||
if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL_export_keying_material failed");
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL export key r0=%u", ERR_get_error());
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
|
@ -544,8 +541,9 @@ srs_error_t SrsSRTP::initialize(string recv_key, std::string send_key)
|
|||
memcpy(rkey, recv_key.data(), recv_key.size());
|
||||
policy.key = rkey;
|
||||
|
||||
if (srtp_create(&recv_ctx_, &policy) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create recv failed");
|
||||
srtp_err_status_t r0 = srtp_err_status_ok;
|
||||
if ((r0 = srtp_create(&recv_ctx_, &policy)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp create r0=%u", r0);
|
||||
}
|
||||
|
||||
policy.ssrc.type = ssrc_any_outbound;
|
||||
|
@ -554,8 +552,8 @@ srs_error_t SrsSRTP::initialize(string recv_key, std::string send_key)
|
|||
memcpy(skey, send_key.data(), send_key.size());
|
||||
policy.key = skey;
|
||||
|
||||
if (srtp_create(&send_ctx_, &policy) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create recv failed");
|
||||
if ((r0 = srtp_create(&send_ctx_, &policy)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp create r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -565,10 +563,16 @@ srs_error_t SrsSRTP::protect_rtp(const char* plaintext, char* cipher, int& nb_ci
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS/SRTP is not ready, fail.
|
||||
if (!send_ctx_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "not ready");
|
||||
}
|
||||
|
||||
memcpy(cipher, plaintext, nb_cipher);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect(send_ctx_, cipher, &nb_cipher) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed");
|
||||
|
||||
srtp_err_status_t r0 = srtp_err_status_ok;
|
||||
if ((r0 = srtp_protect(send_ctx_, cipher, &nb_cipher)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -578,10 +582,16 @@ srs_error_t SrsSRTP::protect_rtcp(const char* plaintext, char* cipher, int& nb_c
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS/SRTP is not ready, fail.
|
||||
if (!send_ctx_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "not ready");
|
||||
}
|
||||
|
||||
memcpy(cipher, plaintext, nb_cipher);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect_rtcp(send_ctx_, cipher, &nb_cipher) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed");
|
||||
|
||||
srtp_err_status_t r0 = srtp_err_status_ok;
|
||||
if ((r0 = srtp_protect_rtcp(send_ctx_, cipher, &nb_cipher)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -591,9 +601,14 @@ srs_error_t SrsSRTP::protect_rtp2(void* rtp_hdr, int* len_ptr)
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect(send_ctx_, rtp_hdr, len_ptr) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect");
|
||||
// If DTLS/SRTP is not ready, fail.
|
||||
if (!send_ctx_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "not ready");
|
||||
}
|
||||
|
||||
srtp_err_status_t r0 = srtp_err_status_ok;
|
||||
if ((r0 = srtp_protect(send_ctx_, rtp_hdr, len_ptr)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -603,10 +618,16 @@ srs_error_t SrsSRTP::unprotect_rtp(const char* cipher, char* plaintext, int& nb_
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS/SRTP is not ready, fail.
|
||||
if (!recv_ctx_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "not ready");
|
||||
}
|
||||
|
||||
memcpy(plaintext, cipher, nb_plaintext);
|
||||
srtp_err_status_t r0 = srtp_unprotect(recv_ctx_, plaintext, &nb_plaintext);
|
||||
if (r0 != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "unprotect r0=%u", r0);
|
||||
|
||||
srtp_err_status_t r0 = srtp_err_status_ok;
|
||||
if ((r0 = srtp_unprotect(recv_ctx_, plaintext, &nb_plaintext)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -616,11 +637,18 @@ srs_error_t SrsSRTP::unprotect_rtcp(const char* cipher, char* plaintext, int& nb
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// If DTLS/SRTP is not ready, fail.
|
||||
if (!recv_ctx_) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "not ready");
|
||||
}
|
||||
|
||||
memcpy(plaintext, cipher, nb_plaintext);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_unprotect_rtcp(recv_ctx_, plaintext, &nb_plaintext) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed");
|
||||
|
||||
srtp_err_status_t r0 = srtp_err_status_ok;
|
||||
if ((r0 = srtp_unprotect_rtcp(recv_ctx_, plaintext, &nb_plaintext)) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ using namespace std;
|
|||
#include <srs_kernel_log.hpp>
|
||||
|
||||
// TODO: FIXME: Maybe we should use json.encode to escape it?
|
||||
const std::string kCRLF = "\\r\\n";
|
||||
const std::string kCRLF = "\r\n";
|
||||
|
||||
#define FETCH(is,word) \
|
||||
if (!(is >> word)) {\
|
||||
|
|
|
@ -97,6 +97,7 @@ void SrsRtcBlackhole::sendto(void* data, int len)
|
|||
return;
|
||||
}
|
||||
|
||||
// For blackhole, we ignore any error.
|
||||
srs_sendto(blackhole_stfd, data, len, (sockaddr*)blackhole_addr, sizeof(sockaddr_in), SRS_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
|
@ -105,24 +106,32 @@ SrsRtcBlackhole* _srs_blackhole = new SrsRtcBlackhole();
|
|||
// @global dtls certficate for rtc module.
|
||||
SrsDtlsCertificate* _srs_rtc_dtls_certificate = new SrsDtlsCertificate();
|
||||
|
||||
static bool is_stun(const uint8_t* data, const int size)
|
||||
// TODO: Should support error response.
|
||||
// For STUN packet, 0x00 is binding request, 0x01 is binding success response.
|
||||
bool srs_is_stun(const uint8_t* data, size_t size)
|
||||
{
|
||||
return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1);
|
||||
return size > 0 && (data[0] == 0 || data[0] == 1);
|
||||
}
|
||||
|
||||
static bool is_dtls(const uint8_t* data, size_t len)
|
||||
// change_cipher_spec(20), alert(21), handshake(22), application_data(23)
|
||||
// @see https://tools.ietf.org/html/rfc2246#section-6.2.1
|
||||
bool srs_is_dtls(const uint8_t* data, size_t len)
|
||||
{
|
||||
return (len >= 13 && (data[0] > 19 && data[0] < 64));
|
||||
return (len >= 13 && (data[0] > 19 && data[0] < 64));
|
||||
}
|
||||
|
||||
static bool is_rtp_or_rtcp(const uint8_t* data, size_t len)
|
||||
// For RTP or RTCP, the V=2 which is in the high 2bits, 0xC0 (1100 0000)
|
||||
bool srs_is_rtp_or_rtcp(const uint8_t* data, size_t len)
|
||||
{
|
||||
return (len >= 12 && (data[0] & 0xC0) == 0x80);
|
||||
return (len >= 12 && (data[0] & 0xC0) == 0x80);
|
||||
}
|
||||
|
||||
static bool is_rtcp(const uint8_t* data, size_t len)
|
||||
// For RTCP, PT is [128, 223] (or without marker [0, 95]).
|
||||
// Literally, RTCP starts from 64 not 0, so PT is [192, 223] (or without marker [64, 95]).
|
||||
// @note For RTP, the PT is [96, 127], or [224, 255] with marker.
|
||||
bool srs_is_rtcp(const uint8_t* data, size_t len)
|
||||
{
|
||||
return (len >= 12) && (data[0] & 0x80) && (data[1] >= 200 && data[1] <= 209);
|
||||
return (len >= 12) && (data[0] & 0x80) && (data[1] >= 192 && data[1] <= 223);
|
||||
}
|
||||
|
||||
static std::vector<std::string> get_candidate_ips()
|
||||
|
@ -301,7 +310,7 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt)
|
|||
}
|
||||
|
||||
// For STUN, the peer address may change.
|
||||
if (is_stun((uint8_t*)data, size)) {
|
||||
if (srs_is_stun((uint8_t*)data, size)) {
|
||||
SrsStunPacket ping;
|
||||
if ((err = ping.decode(data, size)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode stun packet failed");
|
||||
|
@ -309,7 +318,6 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt)
|
|||
srs_info("recv stun packet from %s, use-candidate=%d, ice-controlled=%d, ice-controlling=%d",
|
||||
peer_id.c_str(), ping.get_use_candidate(), ping.get_ice_controlled(), ping.get_ice_controlling());
|
||||
|
||||
// TODO: FIXME: For ICE trickle, we may get STUN packets before SDP answer, so maybe should response it.
|
||||
if (!session) {
|
||||
session = find_session_by_username(ping.get_username());
|
||||
|
||||
|
@ -318,8 +326,10 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt)
|
|||
session->switch_to_context();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: FIXME: For ICE trickle, we may get STUN packets before SDP answer, so maybe should response it.
|
||||
if (!session) {
|
||||
return srs_error_new(ERROR_RTC_STUN, "can not find session, stun username=%s, peer_id=%s",
|
||||
return srs_error_new(ERROR_RTC_STUN, "no session, stun username=%s, peer_id=%s",
|
||||
ping.get_username().c_str(), peer_id.c_str());
|
||||
}
|
||||
|
||||
|
@ -328,19 +338,19 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt)
|
|||
|
||||
// For DTLS, RTCP or RTP, which does not support peer address changing.
|
||||
if (!session) {
|
||||
return srs_error_new(ERROR_RTC_STUN, "can not find session, peer_id=%s", peer_id.c_str());
|
||||
return srs_error_new(ERROR_RTC_STUN, "no session, peer_id=%s", peer_id.c_str());
|
||||
}
|
||||
|
||||
if (is_dtls((uint8_t*)data, size)) {
|
||||
if (srs_is_dtls((uint8_t*)data, size)) {
|
||||
return session->on_dtls(data, size);
|
||||
} else if (is_rtp_or_rtcp((uint8_t*)data, size)) {
|
||||
if (is_rtcp((uint8_t*)data, size)) {
|
||||
} else if (srs_is_rtp_or_rtcp((uint8_t*)data, size)) {
|
||||
if (srs_is_rtcp((uint8_t*)data, size)) {
|
||||
return session->on_rtcp(data, size);
|
||||
}
|
||||
return session->on_rtp(data, size);
|
||||
}
|
||||
|
||||
return srs_error_new(ERROR_RTC_UDP, "unknown udp packet type");
|
||||
return srs_error_new(ERROR_RTC_UDP, "unknown packet");
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcServer::listen_api()
|
||||
|
@ -415,6 +425,9 @@ srs_error_t SrsRtcServer::do_create_session(
|
|||
}
|
||||
}
|
||||
|
||||
// All tracks default as inactive, so we must enable them.
|
||||
session->set_all_tracks_status(true);
|
||||
|
||||
std::string local_pwd = srs_random_str(32);
|
||||
std::string local_ufrag = "";
|
||||
// TODO: FIXME: Rename for a better name, it's not an username.
|
||||
|
|
|
@ -1349,7 +1349,7 @@ SrsRtcTrackDescription::SrsRtcTrackDescription()
|
|||
ssrc_ = 0;
|
||||
rtx_ssrc_ = 0;
|
||||
fec_ssrc_ = 0;
|
||||
is_active_ = true;
|
||||
is_active_ = false;
|
||||
|
||||
media_ = NULL;
|
||||
red_ = NULL;
|
||||
|
@ -1374,6 +1374,7 @@ bool SrsRtcTrackDescription::has_ssrc(uint32_t ssrc)
|
|||
if (ssrc == ssrc_ || ssrc == rtx_ssrc_ || ssrc == fec_ssrc_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1468,7 +1469,7 @@ SrsRtcStreamDescription::~SrsRtcStreamDescription()
|
|||
{
|
||||
srs_freep(audio_track_desc_);
|
||||
|
||||
for (int i = 0; i < video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)video_track_descs_.size(); ++i) {
|
||||
srs_freep(video_track_descs_.at(i));
|
||||
}
|
||||
video_track_descs_.clear();
|
||||
|
@ -1482,7 +1483,7 @@ SrsRtcStreamDescription* SrsRtcStreamDescription::copy()
|
|||
stream_desc->audio_track_desc_ = audio_track_desc_->copy();
|
||||
}
|
||||
|
||||
for (int i = 0; i < video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)video_track_descs_.size(); ++i) {
|
||||
stream_desc->video_track_descs_.push_back(video_track_descs_.at(i)->copy());
|
||||
}
|
||||
|
||||
|
@ -1495,7 +1496,7 @@ SrsRtcTrackDescription* SrsRtcStreamDescription::find_track_description_by_ssrc(
|
|||
return audio_track_desc_;
|
||||
}
|
||||
|
||||
for (int i = 0; i < video_track_descs_.size(); ++i) {
|
||||
for (int i = 0; i < (int)video_track_descs_.size(); ++i) {
|
||||
if (video_track_descs_.at(i)->has_ssrc(ssrc)) {
|
||||
return video_track_descs_.at(i);
|
||||
}
|
||||
|
@ -1504,10 +1505,30 @@ SrsRtcTrackDescription* SrsRtcStreamDescription::find_track_description_by_ssrc(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
SrsRtcTrackStatistic::SrsRtcTrackStatistic()
|
||||
{
|
||||
packets = 0;
|
||||
last_packets = 0;
|
||||
bytes = 0;
|
||||
last_bytes = 0;
|
||||
nacks = 0;
|
||||
last_nacks = 0;
|
||||
padding_packets = 0;
|
||||
last_padding_packets = 0;
|
||||
padding_bytes = 0;
|
||||
last_padding_bytes = 0;
|
||||
replay_packets = 0;
|
||||
last_replay_packets = 0;
|
||||
replay_bytes = 0;
|
||||
last_replay_bytes = 0;
|
||||
}
|
||||
|
||||
SrsRtcRecvTrack::SrsRtcRecvTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc, bool is_audio)
|
||||
{
|
||||
session_ = session;
|
||||
track_desc_ = track_desc->copy();
|
||||
statistic_ = new SrsRtcTrackStatistic();
|
||||
|
||||
if (is_audio) {
|
||||
rtp_queue_ = new SrsRtpRingBuffer(100);
|
||||
nack_receiver_ = new SrsRtpNackForReceiver(rtp_queue_, 100 * 2 / 3);
|
||||
|
@ -1522,22 +1543,17 @@ SrsRtcRecvTrack::~SrsRtcRecvTrack()
|
|||
srs_freep(rtp_queue_);
|
||||
srs_freep(nack_receiver_);
|
||||
srs_freep(track_desc_);
|
||||
srs_freep(statistic_);
|
||||
}
|
||||
|
||||
bool SrsRtcRecvTrack::has_ssrc(uint32_t ssrc)
|
||||
{
|
||||
if (track_desc_) {
|
||||
return track_desc_->has_ssrc(ssrc);
|
||||
}
|
||||
|
||||
return false;
|
||||
return track_desc_->has_ssrc(ssrc);
|
||||
}
|
||||
|
||||
void SrsRtcRecvTrack::update_rtt(int rtt)
|
||||
{
|
||||
if (nack_receiver_) {
|
||||
nack_receiver_->update_rtt(rtt);
|
||||
}
|
||||
nack_receiver_->update_rtt(rtt);
|
||||
}
|
||||
|
||||
void SrsRtcRecvTrack::update_send_report_time(const SrsNtp& ntp)
|
||||
|
@ -1550,8 +1566,10 @@ srs_error_t SrsRtcRecvTrack::send_rtcp_rr()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (session_) {
|
||||
return session_->send_rtcp_rr(track_desc_->ssrc_, rtp_queue_, last_sender_report_sys_time, last_sender_report_ntp);
|
||||
uint32_t ssrc = track_desc_->ssrc_;
|
||||
const uint64_t& last_time = last_sender_report_sys_time;
|
||||
if ((err = session_->send_rtcp_rr(ssrc, rtp_queue_, last_time, last_sender_report_ntp)) != srs_success) {
|
||||
return srs_error_wrap(err, "ssrc=%u, last_time=%" PRId64, ssrc, last_time);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -1561,13 +1579,30 @@ srs_error_t SrsRtcRecvTrack::send_rtcp_xr_rrtr()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (track_desc_) {
|
||||
return session_->send_rtcp_xr_rrtr(track_desc_->ssrc_);
|
||||
if ((err = session_->send_rtcp_xr_rrtr(track_desc_->ssrc_)) != srs_success) {
|
||||
return srs_error_wrap(err, "ssrc=%u", track_desc_->ssrc_);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool SrsRtcRecvTrack::set_track_status(bool active)
|
||||
{
|
||||
bool previous_status = track_desc_->is_active_;
|
||||
track_desc_->is_active_ = active;
|
||||
return previous_status;
|
||||
}
|
||||
|
||||
bool SrsRtcRecvTrack::get_track_status()
|
||||
{
|
||||
return track_desc_->is_active_;
|
||||
}
|
||||
|
||||
std::string SrsRtcRecvTrack::get_track_id()
|
||||
{
|
||||
return track_desc_->id_;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcRecvTrack::on_nack(SrsRtpPacket2* pkt)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
@ -1597,17 +1632,15 @@ srs_error_t SrsRtcRecvTrack::on_nack(SrsRtpPacket2* pkt)
|
|||
|
||||
// insert into video_queue and audio_queue
|
||||
rtp_queue_->set(seq, pkt->copy());
|
||||
|
||||
// send_nack
|
||||
session_->check_send_nacks(nack_receiver_, ssrc);
|
||||
uint32_t sent_nacks = 0;
|
||||
session_->check_send_nacks(nack_receiver_, ssrc, sent_nacks);
|
||||
statistic_->nacks += sent_nacks;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcRecvTrack::on_rtp(SrsRtcStream* source, SrsRtpPacket2* pkt)
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
SrsRtcAudioRecvTrack::SrsRtcAudioRecvTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc)
|
||||
: SrsRtcRecvTrack(session, track_desc, true)
|
||||
{
|
||||
|
@ -1621,10 +1654,15 @@ srs_error_t SrsRtcAudioRecvTrack::on_rtp(SrsRtcStream* source, SrsRtpPacket2* pk
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (source) {
|
||||
if ((err = source->on_rtp(pkt)) != srs_success) {
|
||||
return srs_error_wrap(err, "source on rtp");
|
||||
}
|
||||
// connection level statistic
|
||||
session_->stat_->nn_in_audios++;
|
||||
|
||||
// track level statistic
|
||||
statistic_->packets++;
|
||||
statistic_->bytes += pkt->nb_bytes();
|
||||
|
||||
if ((err = source->on_rtp(pkt)) != srs_success) {
|
||||
return srs_error_wrap(err, "source on rtp");
|
||||
}
|
||||
|
||||
// For NACK to handle packet.
|
||||
|
@ -1632,8 +1670,6 @@ srs_error_t SrsRtcAudioRecvTrack::on_rtp(SrsRtcStream* source, SrsRtpPacket2* pk
|
|||
return srs_error_wrap(err, "on nack");
|
||||
}
|
||||
|
||||
session_->stat_->nn_in_audios++;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1651,20 +1687,28 @@ srs_error_t SrsRtcVideoRecvTrack::on_rtp(SrsRtcStream* source, SrsRtpPacket2* pk
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// connection level statistic
|
||||
session_->stat_->nn_in_videos++;
|
||||
|
||||
// track level statistic
|
||||
statistic_->packets++;
|
||||
statistic_->bytes += pkt->nb_bytes();
|
||||
|
||||
pkt->frame_type = SrsFrameTypeVideo;
|
||||
|
||||
if (source) {
|
||||
if ((err = source->on_rtp(pkt)) != srs_success) {
|
||||
return srs_error_wrap(err, "source on rtp");
|
||||
}
|
||||
if ((err = source->on_rtp(pkt)) != srs_success) {
|
||||
return srs_error_wrap(err, "source on rtp");
|
||||
}
|
||||
|
||||
// TODO: FIXME: add rtp process
|
||||
if (request_key_frame_) {
|
||||
// TODO: FIXME: add coroutine to request key frame.
|
||||
request_key_frame_ = false;
|
||||
// TODO: FIXME: Check error.
|
||||
session_->send_rtcp_fb_pli(track_desc_->ssrc_);
|
||||
|
||||
if ((err = session_->send_rtcp_fb_pli(track_desc_->ssrc_)) != srs_success) {
|
||||
srs_warn("PLI err %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
}
|
||||
}
|
||||
|
||||
// For NACK to handle packet.
|
||||
|
@ -1672,8 +1716,6 @@ srs_error_t SrsRtcVideoRecvTrack::on_rtp(SrsRtcStream* source, SrsRtpPacket2* pk
|
|||
return srs_error_wrap(err, "on nack");
|
||||
}
|
||||
|
||||
session_->stat_->nn_in_videos++;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1687,25 +1729,25 @@ SrsRtcSendTrack::SrsRtcSendTrack(SrsRtcConnection* session, SrsRtcTrackDescripti
|
|||
{
|
||||
session_ = session;
|
||||
track_desc_ = track_desc->copy();
|
||||
statistic_ = new SrsRtcTrackStatistic();
|
||||
|
||||
if (is_audio) {
|
||||
rtp_queue_ = new SrsRtpRingBuffer(100);
|
||||
} else {
|
||||
rtp_queue_ = new SrsRtpRingBuffer(1000);
|
||||
}
|
||||
}
|
||||
|
||||
SrsRtcSendTrack::~SrsRtcSendTrack()
|
||||
{
|
||||
srs_freep(rtp_queue_);
|
||||
srs_freep(track_desc_);
|
||||
srs_freep(statistic_);
|
||||
}
|
||||
|
||||
bool SrsRtcSendTrack::has_ssrc(uint32_t ssrc)
|
||||
{
|
||||
if (track_desc_) {
|
||||
return track_desc_->has_ssrc(ssrc);
|
||||
}
|
||||
|
||||
return false;
|
||||
return track_desc_->has_ssrc(ssrc);
|
||||
}
|
||||
|
||||
SrsRtpPacket2* SrsRtcSendTrack::fetch_rtp_packet(uint16_t seq)
|
||||
|
@ -1718,9 +1760,16 @@ SrsRtpPacket2* SrsRtcSendTrack::fetch_rtp_packet(uint16_t seq)
|
|||
}
|
||||
|
||||
// TODO: FIXME: Should refine logs, set tracks in a time.
|
||||
void SrsRtcSendTrack::set_track_status(bool active)
|
||||
bool SrsRtcSendTrack::set_track_status(bool active)
|
||||
{
|
||||
bool previous_status = track_desc_->is_active_;
|
||||
track_desc_->is_active_ = active;
|
||||
return previous_status;
|
||||
}
|
||||
|
||||
bool SrsRtcSendTrack::get_track_status()
|
||||
{
|
||||
return track_desc_->is_active_;
|
||||
}
|
||||
|
||||
std::string SrsRtcSendTrack::get_track_id()
|
||||
|
@ -1728,14 +1777,11 @@ std::string SrsRtcSendTrack::get_track_id()
|
|||
return track_desc_->id_;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcSendTrack::on_rtp(SrsRtpPacket2* pkt, SrsRtcPlayStreamStatistic& info)
|
||||
void SrsRtcSendTrack::on_recv_nack()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
SrsRtcTrackStatistic* statistic = statistic_;
|
||||
|
||||
srs_error_t SrsRtcSendTrack::on_rtcp(SrsRtpPacket2* pkt)
|
||||
{
|
||||
return srs_success;
|
||||
statistic->nacks++;
|
||||
}
|
||||
|
||||
SrsRtcAudioSendTrack::SrsRtcAudioSendTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc)
|
||||
|
@ -1755,7 +1801,6 @@ srs_error_t SrsRtcAudioSendTrack::on_rtp(SrsRtpPacket2* pkt, SrsRtcPlayStreamSta
|
|||
return err;
|
||||
}
|
||||
|
||||
std::vector<SrsRtpPacket2*> pkts;
|
||||
pkt->header.set_ssrc(track_desc_->ssrc_);
|
||||
|
||||
// Put rtp packet to NACK/ARQ queue
|
||||
|
@ -1764,15 +1809,22 @@ srs_error_t SrsRtcAudioSendTrack::on_rtp(SrsRtpPacket2* pkt, SrsRtcPlayStreamSta
|
|||
rtp_queue_->set(nack->header.get_sequence(), nack);
|
||||
}
|
||||
|
||||
pkts.push_back(pkt);
|
||||
|
||||
// Update stats.
|
||||
info.nn_bytes += pkt->nb_bytes();
|
||||
info.nn_audios++;
|
||||
session_->stat_->nn_out_audios++;
|
||||
|
||||
if ((err = session_->do_send_packets(pkts, info)) != srs_success) {
|
||||
return srs_error_wrap(err, "raw send");
|
||||
// track level statistic
|
||||
statistic_->packets++;
|
||||
statistic_->bytes += pkt->nb_bytes();
|
||||
|
||||
if (true) {
|
||||
std::vector<SrsRtpPacket2*> pkts;
|
||||
pkts.push_back(pkt);
|
||||
|
||||
if ((err = session_->do_send_packets(pkts, info)) != srs_success) {
|
||||
return srs_error_wrap(err, "raw send");
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -1801,24 +1853,33 @@ srs_error_t SrsRtcVideoSendTrack::on_rtp(SrsRtpPacket2* pkt, SrsRtcPlayStreamSta
|
|||
if (!track_desc_->is_active_) {
|
||||
return err;
|
||||
}
|
||||
|
||||
std::vector<SrsRtpPacket2*> pkts;
|
||||
|
||||
SrsRtcTrackStatistic* statistic = statistic_;
|
||||
|
||||
pkt->header.set_ssrc(track_desc_->ssrc_);
|
||||
|
||||
// Put rtp packet to NACK/ARQ queue
|
||||
if (true) {
|
||||
SrsRtpPacket2* nack = pkt->copy();
|
||||
rtp_queue_->set(nack->header.get_sequence(), nack);
|
||||
}
|
||||
|
||||
pkts.push_back(pkt);
|
||||
// Update stats.
|
||||
info.nn_bytes += pkt->nb_bytes();
|
||||
info.nn_videos++;
|
||||
session_->stat_->nn_out_videos++;
|
||||
|
||||
if ((err = session_->do_send_packets(pkts, info)) != srs_success) {
|
||||
return srs_error_wrap(err, "raw send");
|
||||
// track level statistic
|
||||
statistic->packets++;
|
||||
statistic->bytes += pkt->nb_bytes();
|
||||
|
||||
if (true) {
|
||||
std::vector<SrsRtpPacket2*> pkts;
|
||||
pkts.push_back(pkt);
|
||||
|
||||
if ((err = session_->do_send_packets(pkts, info)) != srs_success) {
|
||||
return srs_error_wrap(err, "raw send");
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -404,10 +404,50 @@ public:
|
|||
SrsRtcTrackDescription* find_track_description_by_ssrc(uint32_t ssrc);
|
||||
};
|
||||
|
||||
class SrsRtcTrackStatistic
|
||||
{
|
||||
public:
|
||||
// packets received or sent.
|
||||
uint32_t packets;
|
||||
// packets received or sent at last statistic time.
|
||||
uint32_t last_packets;
|
||||
// bytes received or sent.
|
||||
uint64_t bytes;
|
||||
// bytes received or sent at last statistic time.
|
||||
uint32_t last_bytes;
|
||||
|
||||
// nacks received or sent.
|
||||
uint32_t nacks;
|
||||
// nacks received or sent at last statistic time.
|
||||
uint32_t last_nacks;
|
||||
|
||||
// padding packets received or sent.
|
||||
uint32_t padding_packets;
|
||||
// padding packets received or sent at last statistic time.
|
||||
uint32_t last_padding_packets;
|
||||
// padding bytes received or sent.
|
||||
uint32_t padding_bytes;
|
||||
// padding bytes received or sent at last statistic time.
|
||||
uint32_t last_padding_bytes;
|
||||
|
||||
// replay packets received or sent.
|
||||
uint32_t replay_packets;
|
||||
// replay packets received or sent at last statistic time.
|
||||
uint32_t last_replay_packets;
|
||||
// replay bytes received or sent.
|
||||
uint64_t replay_bytes;
|
||||
// replay bytes received or sent at last statistic time.
|
||||
uint64_t last_replay_bytes;
|
||||
|
||||
public:
|
||||
SrsRtcTrackStatistic();
|
||||
};
|
||||
|
||||
class SrsRtcRecvTrack
|
||||
{
|
||||
protected:
|
||||
SrsRtcTrackDescription* track_desc_;
|
||||
SrsRtcTrackStatistic* statistic_;
|
||||
|
||||
SrsRtcConnection* session_;
|
||||
SrsRtpRingBuffer* rtp_queue_;
|
||||
|
@ -425,10 +465,13 @@ public:
|
|||
void update_send_report_time(const SrsNtp& ntp);
|
||||
srs_error_t send_rtcp_rr();
|
||||
srs_error_t send_rtcp_xr_rrtr();
|
||||
bool set_track_status(bool active);
|
||||
bool get_track_status();
|
||||
std::string get_track_id();
|
||||
protected:
|
||||
srs_error_t on_nack(SrsRtpPacket2* pkt);
|
||||
public:
|
||||
virtual srs_error_t on_rtp(SrsRtcStream* source, SrsRtpPacket2* pkt);
|
||||
virtual srs_error_t on_rtp(SrsRtcStream* source, SrsRtpPacket2* pkt) = 0;
|
||||
};
|
||||
|
||||
class SrsRtcAudioRecvTrack : public SrsRtcRecvTrack
|
||||
|
@ -458,7 +501,9 @@ class SrsRtcSendTrack
|
|||
protected:
|
||||
// send track description
|
||||
SrsRtcTrackDescription* track_desc_;
|
||||
SrsRtcTrackStatistic* statistic_;
|
||||
|
||||
// The owner connection for this track.
|
||||
SrsRtcConnection* session_;
|
||||
// NACK ARQ ring buffer.
|
||||
SrsRtpRingBuffer* rtp_queue_;
|
||||
|
@ -468,11 +513,13 @@ public:
|
|||
public:
|
||||
bool has_ssrc(uint32_t ssrc);
|
||||
SrsRtpPacket2* fetch_rtp_packet(uint16_t seq);
|
||||
void set_track_status(bool active);
|
||||
bool set_track_status(bool active);
|
||||
bool get_track_status();
|
||||
std::string get_track_id();
|
||||
public:
|
||||
virtual srs_error_t on_rtp(SrsRtpPacket2* pkt, SrsRtcPlayStreamStatistic& info);
|
||||
virtual srs_error_t on_rtcp(SrsRtpPacket2* pkt);
|
||||
virtual srs_error_t on_rtp(SrsRtpPacket2* pkt, SrsRtcPlayStreamStatistic& info) = 0;
|
||||
virtual srs_error_t on_rtcp(SrsRtpPacket2* pkt) = 0;
|
||||
virtual void on_recv_nack();
|
||||
};
|
||||
|
||||
class SrsRtcAudioSendTrack : public SrsRtcSendTrack
|
||||
|
|
|
@ -1281,37 +1281,51 @@ void srs_api_dump_summaries(SrsJsonObject* obj)
|
|||
sys->set("conn_srs", SrsJsonAny::integer(nrs->nb_conn_srs));
|
||||
}
|
||||
|
||||
string srs_string_dumps_hex(const std::string& str, const int& limit)
|
||||
string srs_string_dumps_hex(const std::string& str)
|
||||
{
|
||||
return srs_string_dumps_hex(str.c_str(), str.size(), limit);
|
||||
return srs_string_dumps_hex(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
string srs_string_dumps_hex(const char* buf, const int length, const int& limit)
|
||||
string srs_string_dumps_hex(const char* str, int length)
|
||||
{
|
||||
string ret;
|
||||
return srs_string_dumps_hex(str, length, INT_MAX);
|
||||
}
|
||||
|
||||
char tmp_buf[1024*16];
|
||||
tmp_buf[0] = '\n';
|
||||
int len = 1;
|
||||
|
||||
for (int i = 0; i < length && i < limit; ++i) {
|
||||
int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]);
|
||||
if (nb <= 0)
|
||||
string srs_string_dumps_hex(const char* str, int length, int limit)
|
||||
{
|
||||
return srs_string_dumps_hex(str, length, limit, ' ', 128, '\n');
|
||||
}
|
||||
|
||||
string srs_string_dumps_hex(const char* str, int length, int limit, char seperator, int line_limit, char newline)
|
||||
{
|
||||
const int LIMIT = 1024*16;
|
||||
static char buf[LIMIT];
|
||||
|
||||
int len = 0;
|
||||
for (int i = 0; i < length && i < limit && i < LIMIT; ++i) {
|
||||
int nb = snprintf(buf + len, LIMIT - len, "%02x", (uint8_t)str[i]);
|
||||
if (nb < 0 || nb > LIMIT - len) {
|
||||
break;
|
||||
}
|
||||
len += nb;
|
||||
|
||||
len += nb;
|
||||
// Only append seperator and newline when not last byte.
|
||||
if (i < length - 1 && i < limit - 1 && i < LIMIT - 1) {
|
||||
if (seperator && len < LIMIT) {
|
||||
buf[len++] = seperator;
|
||||
}
|
||||
|
||||
if (i % 48 == 47) {
|
||||
tmp_buf[len++] = '\n';
|
||||
ret.append(tmp_buf, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
tmp_buf[len] = '\0';
|
||||
ret.append(tmp_buf, len);
|
||||
|
||||
return ret;
|
||||
if (newline && line_limit && i > 0 && ((i + 1) % line_limit) == 0 && len < LIMIT) {
|
||||
buf[len++] = newline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty string.
|
||||
if (len <= 0) {
|
||||
return "";
|
||||
}
|
||||
return string(buf, len);
|
||||
}
|
||||
|
||||
string srs_getenv(string key)
|
||||
|
|
|
@ -652,8 +652,11 @@ extern bool srs_is_boolean(std::string str);
|
|||
extern void srs_api_dump_summaries(SrsJsonObject* obj);
|
||||
|
||||
// Dump string(str in length) to hex, it will process min(limit, length) chars.
|
||||
extern std::string srs_string_dumps_hex(const std::string& str, const int& limit = INT_MAX);
|
||||
extern std::string srs_string_dumps_hex(const char* str, const int length, const int& limit = INT_MAX);
|
||||
// Append seperator between each elem, and newline when exceed line_limit, '\0' to ignore.
|
||||
extern std::string srs_string_dumps_hex(const std::string& str);
|
||||
extern std::string srs_string_dumps_hex(const char* str, int length);
|
||||
extern std::string srs_string_dumps_hex(const char* str, int length, int limit);
|
||||
extern std::string srs_string_dumps_hex(const char* str, int length, int limit, char seperator, int line_limit, char newline);
|
||||
|
||||
// Get ENV variable, which may starts with $.
|
||||
// srs_getenv("EIP") === srs_getenv("$EIP")
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#define RTMP_SIG_SRS_AUTHORS "Winlin,Wenjie,Runner365,John,B.P.Y,Lixin"
|
||||
#define RTMP_SIG_SRS_VERSION SRS_XSTR(VERSION_MAJOR) "." SRS_XSTR(VERSION_MINOR) "." SRS_XSTR(VERSION_REVISION)
|
||||
#define RTMP_SIG_SRS_SERVER RTMP_SIG_SRS_KEY "/" RTMP_SIG_SRS_VERSION "(" RTMP_SIG_SRS_CODE ")"
|
||||
#define RTMP_SIG_SRS_DOMAIN "ossrs.net"
|
||||
|
||||
// The current stable release.
|
||||
#define VERSION_STABLE 3
|
||||
|
|
|
@ -24,6 +24,6 @@
|
|||
#ifndef SRS_CORE_VERSION4_HPP
|
||||
#define SRS_CORE_VERSION4_HPP
|
||||
|
||||
#define SRS_VERSION4_REVISION 36
|
||||
#define SRS_VERSION4_REVISION 37
|
||||
|
||||
#endif
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
#define ERROR_RTC_STREM_STARTED 5025
|
||||
#define ERROR_RTC_STREAM_DESC 5026
|
||||
#define ERROR_RTC_TRACK_CODEC 5027
|
||||
#define ERROR_RTC_NO_PLAYER 5028
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// GB28181 API error.
|
||||
|
|
|
@ -37,7 +37,7 @@ SrsRtcpCommon::~SrsRtcpCommon()
|
|||
{
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpCommon::type() const
|
||||
uint8_t SrsRtcpCommon::type() const
|
||||
{
|
||||
return header_.type;
|
||||
}
|
||||
|
@ -90,27 +90,27 @@ SrsRtcpApp::~SrsRtcpApp()
|
|||
{
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpApp::type() const
|
||||
uint8_t SrsRtcpApp::type() const
|
||||
{
|
||||
return SrsRtcpType_app;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpApp::get_ssrc() const
|
||||
uint32_t SrsRtcpApp::get_ssrc() const
|
||||
{
|
||||
return ssrc_;
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpApp::get_subtype() const
|
||||
uint8_t SrsRtcpApp::get_subtype() const
|
||||
{
|
||||
return header_.rc;
|
||||
}
|
||||
|
||||
const string SrsRtcpApp::get_name() const
|
||||
string SrsRtcpApp::get_name() const
|
||||
{
|
||||
return string((char*)name_);
|
||||
}
|
||||
|
||||
const srs_error_t SrsRtcpApp::get_payload(uint8_t*& payload, int& len)
|
||||
srs_error_t SrsRtcpApp::get_payload(uint8_t*& payload, int& len)
|
||||
{
|
||||
len = payload_len_;
|
||||
payload = payload_;
|
||||
|
@ -213,37 +213,37 @@ SrsRtcpSR::~SrsRtcpSR()
|
|||
{
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpSR::get_rc() const
|
||||
uint8_t SrsRtcpSR::get_rc() const
|
||||
{
|
||||
return header_.rc;
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpSR::type() const
|
||||
uint8_t SrsRtcpSR::type() const
|
||||
{
|
||||
return SrsRtcpType_sr;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpSR::get_sender_ssrc() const
|
||||
uint32_t SrsRtcpSR::get_sender_ssrc() const
|
||||
{
|
||||
return sender_ssrc_;
|
||||
}
|
||||
|
||||
const uint64_t SrsRtcpSR::get_ntp() const
|
||||
uint64_t SrsRtcpSR::get_ntp() const
|
||||
{
|
||||
return ntp_;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpSR::get_rtp_ts() const
|
||||
uint32_t SrsRtcpSR::get_rtp_ts() const
|
||||
{
|
||||
return rtp_ts_;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpSR::get_rtp_send_packets() const
|
||||
uint32_t SrsRtcpSR::get_rtp_send_packets() const
|
||||
{
|
||||
return send_rtp_packets_;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpSR::get_rtp_send_bytes() const
|
||||
uint32_t SrsRtcpSR::get_rtp_send_bytes() const
|
||||
{
|
||||
return send_rtp_bytes_;
|
||||
}
|
||||
|
@ -334,42 +334,42 @@ SrsRtcpRR::~SrsRtcpRR()
|
|||
{
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpRR::type() const
|
||||
uint8_t SrsRtcpRR::type() const
|
||||
{
|
||||
return SrsRtcpType_rr;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpRR::get_rb_ssrc() const
|
||||
uint32_t SrsRtcpRR::get_rb_ssrc() const
|
||||
{
|
||||
return rb_.ssrc;
|
||||
}
|
||||
|
||||
const float SrsRtcpRR::get_lost_rate() const
|
||||
float SrsRtcpRR::get_lost_rate() const
|
||||
{
|
||||
return rb_.fraction_lost / 256;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpRR::get_lost_packets() const
|
||||
uint32_t SrsRtcpRR::get_lost_packets() const
|
||||
{
|
||||
return rb_.lost_packets;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpRR::get_highest_sn() const
|
||||
uint32_t SrsRtcpRR::get_highest_sn() const
|
||||
{
|
||||
return rb_.highest_sn;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpRR::get_jitter() const
|
||||
uint32_t SrsRtcpRR::get_jitter() const
|
||||
{
|
||||
return rb_.jitter;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpRR::get_lsr() const
|
||||
uint32_t SrsRtcpRR::get_lsr() const
|
||||
{
|
||||
return rb_.lsr;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpRR::get_dlsr() const
|
||||
uint32_t SrsRtcpRR::get_dlsr() const
|
||||
{
|
||||
return rb_.dlsr;
|
||||
}
|
||||
|
@ -493,36 +493,36 @@ void SrsRtcpTWCC::clear()
|
|||
recv_sns_.clear();
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpTWCC::get_media_ssrc() const
|
||||
uint32_t SrsRtcpTWCC::get_media_ssrc() const
|
||||
{
|
||||
return media_ssrc_;
|
||||
}
|
||||
const uint16_t SrsRtcpTWCC::get_base_sn() const
|
||||
uint16_t SrsRtcpTWCC::get_base_sn() const
|
||||
{
|
||||
return base_sn_;
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpTWCC::get_reference_time() const
|
||||
uint32_t SrsRtcpTWCC::get_reference_time() const
|
||||
{
|
||||
return reference_time_;
|
||||
}
|
||||
|
||||
const uint8_t SrsRtcpTWCC::get_feedback_count() const
|
||||
uint8_t SrsRtcpTWCC::get_feedback_count() const
|
||||
{
|
||||
return fb_pkt_count_;
|
||||
}
|
||||
|
||||
const uint16_t SrsRtcpTWCC::get_packet_status_count() const
|
||||
uint16_t SrsRtcpTWCC::get_packet_status_count() const
|
||||
{
|
||||
return packet_count_;
|
||||
}
|
||||
|
||||
const vector<uint16_t> SrsRtcpTWCC::get_packet_chucks() const
|
||||
vector<uint16_t> SrsRtcpTWCC::get_packet_chucks() const
|
||||
{
|
||||
return encoded_chucks_;
|
||||
}
|
||||
|
||||
const vector<uint16_t> SrsRtcpTWCC::get_recv_deltas() const
|
||||
vector<uint16_t> SrsRtcpTWCC::get_recv_deltas() const
|
||||
{
|
||||
return pkt_deltas_;
|
||||
}
|
||||
|
@ -887,12 +887,12 @@ SrsRtcpNack::~SrsRtcpNack()
|
|||
{
|
||||
}
|
||||
|
||||
const uint32_t SrsRtcpNack::get_media_ssrc() const
|
||||
uint32_t SrsRtcpNack::get_media_ssrc() const
|
||||
{
|
||||
return media_ssrc_;
|
||||
}
|
||||
|
||||
const vector<uint16_t> SrsRtcpNack::get_lost_sns() const
|
||||
vector<uint16_t> SrsRtcpNack::get_lost_sns() const
|
||||
{
|
||||
vector<uint16_t> sn;
|
||||
for(set<uint16_t, SrsSeqCompareLess>::iterator it = lost_sns_.begin(); it != lost_sns_.end(); ++it) {
|
||||
|
|
|
@ -73,7 +73,7 @@ protected:
|
|||
public:
|
||||
SrsRtcpCommon();
|
||||
virtual ~SrsRtcpCommon();
|
||||
virtual const uint8_t type() const;
|
||||
virtual uint8_t type() const;
|
||||
// interface ISrsCodec
|
||||
public:
|
||||
virtual srs_error_t decode(SrsBuffer *buffer);
|
||||
|
@ -93,12 +93,12 @@ public:
|
|||
SrsRtcpApp();
|
||||
virtual ~SrsRtcpApp();
|
||||
|
||||
virtual const uint8_t type() const;
|
||||
virtual uint8_t type() const;
|
||||
|
||||
const uint32_t get_ssrc() const;
|
||||
const uint8_t get_subtype() const;
|
||||
const std::string get_name() const;
|
||||
const srs_error_t get_payload(uint8_t*& payload, int& len);
|
||||
uint32_t get_ssrc() const;
|
||||
uint8_t get_subtype() const;
|
||||
std::string get_name() const;
|
||||
srs_error_t get_payload(uint8_t*& payload, int& len);
|
||||
|
||||
void set_ssrc(uint32_t ssrc);
|
||||
srs_error_t set_subtype(uint8_t type);
|
||||
|
@ -134,14 +134,14 @@ public:
|
|||
SrsRtcpSR();
|
||||
virtual ~SrsRtcpSR();
|
||||
|
||||
const uint8_t get_rc() const;
|
||||
uint8_t get_rc() const;
|
||||
// overload SrsRtcpCommon
|
||||
virtual const uint8_t type() const;
|
||||
const uint32_t get_sender_ssrc() const;
|
||||
const uint64_t get_ntp() const;
|
||||
const uint32_t get_rtp_ts() const;
|
||||
const uint32_t get_rtp_send_packets() const;
|
||||
const uint32_t get_rtp_send_bytes() const;
|
||||
virtual uint8_t type() const;
|
||||
uint32_t get_sender_ssrc() const;
|
||||
uint64_t get_ntp() const;
|
||||
uint32_t get_rtp_ts() const;
|
||||
uint32_t get_rtp_send_packets() const;
|
||||
uint32_t get_rtp_send_bytes() const;
|
||||
|
||||
void set_sender_ssrc(uint32_t ssrc);
|
||||
void set_ntp(uint64_t ntp);
|
||||
|
@ -165,15 +165,15 @@ public:
|
|||
virtual ~SrsRtcpRR();
|
||||
|
||||
// overload SrsRtcpCommon
|
||||
virtual const uint8_t type() const;
|
||||
virtual uint8_t type() const;
|
||||
|
||||
const uint32_t get_rb_ssrc() const;
|
||||
const float get_lost_rate() const;
|
||||
const uint32_t get_lost_packets() const;
|
||||
const uint32_t get_highest_sn() const;
|
||||
const uint32_t get_jitter() const;
|
||||
const uint32_t get_lsr() const;
|
||||
const uint32_t get_dlsr() const;
|
||||
uint32_t get_rb_ssrc() const;
|
||||
float get_lost_rate() const;
|
||||
uint32_t get_lost_packets() const;
|
||||
uint32_t get_highest_sn() const;
|
||||
uint32_t get_jitter() const;
|
||||
uint32_t get_lsr() const;
|
||||
uint32_t get_dlsr() const;
|
||||
|
||||
void set_rb_ssrc(uint32_t ssrc);
|
||||
void set_lost_rate(float rate);
|
||||
|
@ -271,13 +271,13 @@ public:
|
|||
SrsRtcpTWCC(uint32_t sender_ssrc = 0);
|
||||
virtual ~SrsRtcpTWCC();
|
||||
|
||||
const uint32_t get_media_ssrc() const;
|
||||
const uint16_t get_base_sn() const;
|
||||
const uint16_t get_packet_status_count() const;
|
||||
const uint32_t get_reference_time() const;
|
||||
const uint8_t get_feedback_count() const;
|
||||
const std::vector<uint16_t> get_packet_chucks() const;
|
||||
const std::vector<uint16_t> get_recv_deltas() const;
|
||||
uint32_t get_media_ssrc() const;
|
||||
uint16_t get_base_sn() const;
|
||||
uint16_t get_packet_status_count() const;
|
||||
uint32_t get_reference_time() const;
|
||||
uint8_t get_feedback_count() const;
|
||||
std::vector<uint16_t> get_packet_chucks() const;
|
||||
std::vector<uint16_t> get_recv_deltas() const;
|
||||
|
||||
void set_media_ssrc(uint32_t ssrc);
|
||||
void set_base_sn(uint16_t sn);
|
||||
|
@ -313,8 +313,8 @@ public:
|
|||
SrsRtcpNack(uint32_t sender_ssrc = 0);
|
||||
virtual ~SrsRtcpNack();
|
||||
|
||||
const uint32_t get_media_ssrc() const;
|
||||
const std::vector<uint16_t> get_lost_sns() const;
|
||||
uint32_t get_media_ssrc() const;
|
||||
std::vector<uint16_t> get_lost_sns() const;
|
||||
|
||||
void set_media_ssrc(uint32_t ssrc);
|
||||
void add_lost_sn(uint16_t sn);
|
||||
|
|
|
@ -1576,7 +1576,7 @@ string escape(string v)
|
|||
{
|
||||
stringstream ss;
|
||||
|
||||
for (int i = 0; i < v.length(); i++) {
|
||||
for (int i = 0; i < (int)v.length(); i++) {
|
||||
if (v.at(i) == '"') {
|
||||
ss << '\\';
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ srs_utime_t _srs_tmp_timeout = (100 * SRS_UTIME_MILLISECONDS);
|
|||
ISrsLog* _srs_log = new MockEmptyLog(SrsLogLevelDisabled);
|
||||
ISrsContext* _srs_context = new SrsThreadContext();
|
||||
// app module.
|
||||
SrsConfig* _srs_config = NULL;
|
||||
SrsConfig* _srs_config = new SrsConfig();
|
||||
SrsServer* _srs_server = NULL;
|
||||
bool _srs_in_docker = false;
|
||||
|
||||
|
|
|
@ -24,6 +24,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#ifndef SRS_UTEST_PUBLIC_SHARED_HPP
|
||||
#define SRS_UTEST_PUBLIC_SHARED_HPP
|
||||
|
||||
// Before define the private/protected, we must include some system header files.
|
||||
// Or it may fail with:
|
||||
// redeclared with different access struct __xfer_bufptrs
|
||||
// @see https://stackoverflow.com/questions/47839718/sstream-redeclared-with-public-access-compiler-error
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Public all private and protected members.
|
||||
#define private public
|
||||
#define protected public
|
||||
|
@ -33,7 +39,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
*/
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
|
|
|
@ -25,7 +25,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_app_rtc_queue.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_kernel_rtc_rtp.hpp>
|
||||
#include <srs_app_rtc_source.hpp>
|
||||
#include <srs_app_rtc_conn.hpp>
|
||||
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
VOID TEST(KernelRTCTest, SequenceCompare)
|
||||
{
|
||||
|
@ -123,3 +129,191 @@ VOID TEST(KernelRTCTest, SequenceCompare)
|
|||
}
|
||||
}
|
||||
|
||||
VOID TEST(KernelRTCTest, DumpsHexToString)
|
||||
{
|
||||
if (true) {
|
||||
EXPECT_STREQ("", srs_string_dumps_hex(NULL, 0).c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
uint8_t data[] = {0, 0, 0, 0};
|
||||
EXPECT_STREQ("00 00 00 00", srs_string_dumps_hex((const char*)data, sizeof(data)).c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
uint8_t data[] = {0, 1, 2, 3};
|
||||
EXPECT_STREQ("00 01 02 03", srs_string_dumps_hex((const char*)data, sizeof(data)).c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
uint8_t data[] = {0xa, 3, 0xf, 3};
|
||||
EXPECT_STREQ("0a 03 0f 03", srs_string_dumps_hex((const char*)data, sizeof(data)).c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
uint8_t data[] = {0xa, 3, 0xf, 3};
|
||||
EXPECT_STREQ("0a,03,0f,03", srs_string_dumps_hex((const char*)data, sizeof(data), INT_MAX, ',', 0, 0).c_str());
|
||||
EXPECT_STREQ("0a030f03", srs_string_dumps_hex((const char*)data, sizeof(data), INT_MAX, '\0', 0, 0).c_str());
|
||||
EXPECT_STREQ("0a,03,\n0f,03", srs_string_dumps_hex((const char*)data, sizeof(data), INT_MAX, ',', 2, '\n').c_str());
|
||||
EXPECT_STREQ("0a,03,0f,03", srs_string_dumps_hex((const char*)data, sizeof(data), INT_MAX, ',', 2,'\0').c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
uint8_t data[] = {0xa, 3, 0xf};
|
||||
EXPECT_STREQ("0a 03", srs_string_dumps_hex((const char*)data, sizeof(data), 2).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
extern bool srs_is_stun(const uint8_t* data, size_t size);
|
||||
extern bool srs_is_dtls(const uint8_t* data, size_t len);
|
||||
extern bool srs_is_rtp_or_rtcp(const uint8_t* data, size_t len);
|
||||
extern bool srs_is_rtcp(const uint8_t* data, size_t len);
|
||||
|
||||
#define mock_arr_push(arr, elem) arr.push_back(vector<uint8_t>(elem, elem + sizeof(elem)))
|
||||
|
||||
VOID TEST(KernelRTCTest, TestPacketType)
|
||||
{
|
||||
// DTLS packet.
|
||||
vector< vector<uint8_t> > dtlss;
|
||||
if (true) { uint8_t data[13] = {20}; mock_arr_push(dtlss, data); } // change_cipher_spec(20)
|
||||
if (true) { uint8_t data[13] = {21}; mock_arr_push(dtlss, data); } // alert(21)
|
||||
if (true) { uint8_t data[13] = {22}; mock_arr_push(dtlss, data); } // handshake(22)
|
||||
if (true) { uint8_t data[13] = {23}; mock_arr_push(dtlss, data); } // application_data(23)
|
||||
for (int i = 0; i < (int)dtlss.size(); i++) {
|
||||
vector<uint8_t> elem = dtlss.at(i);
|
||||
EXPECT_TRUE(srs_is_dtls(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)dtlss.size(); i++) {
|
||||
vector<uint8_t> elem = dtlss.at(i);
|
||||
EXPECT_FALSE(srs_is_dtls(&elem[0], 1));
|
||||
|
||||
// All DTLS should not be other packets.
|
||||
EXPECT_FALSE(srs_is_stun(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_TRUE(srs_is_dtls(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_rtp_or_rtcp(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_rtcp(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
// STUN packet.
|
||||
vector< vector<uint8_t> > stuns;
|
||||
if (true) { uint8_t data[1] = {0}; mock_arr_push(stuns, data); } // binding request.
|
||||
if (true) { uint8_t data[1] = {1}; mock_arr_push(stuns, data); } // binding success response.
|
||||
for (int i = 0; i < (int)stuns.size(); i++) {
|
||||
vector<uint8_t> elem = stuns.at(i);
|
||||
EXPECT_TRUE(srs_is_stun(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)stuns.size(); i++) {
|
||||
vector<uint8_t> elem = stuns.at(i);
|
||||
EXPECT_FALSE(srs_is_stun(&elem[0], 0));
|
||||
|
||||
// All STUN should not be other packets.
|
||||
EXPECT_TRUE(srs_is_stun(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_dtls(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_rtp_or_rtcp(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_rtcp(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
// RTCP packet.
|
||||
vector< vector<uint8_t> > rtcps;
|
||||
if (true) { uint8_t data[12] = {0x80, 192}; mock_arr_push(rtcps, data); }
|
||||
if (true) { uint8_t data[12] = {0x80, 200}; mock_arr_push(rtcps, data); } // SR
|
||||
if (true) { uint8_t data[12] = {0x80, 201}; mock_arr_push(rtcps, data); } // RR
|
||||
if (true) { uint8_t data[12] = {0x80, 202}; mock_arr_push(rtcps, data); } // SDES
|
||||
if (true) { uint8_t data[12] = {0x80, 203}; mock_arr_push(rtcps, data); } // BYE
|
||||
if (true) { uint8_t data[12] = {0x80, 204}; mock_arr_push(rtcps, data); } // APP
|
||||
if (true) { uint8_t data[12] = {0x80, 223}; mock_arr_push(rtcps, data); }
|
||||
for (int i = 0; i < (int)rtcps.size(); i++) {
|
||||
vector<uint8_t> elem = rtcps.at(i);
|
||||
EXPECT_TRUE(srs_is_rtcp(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)rtcps.size(); i++) {
|
||||
vector<uint8_t> elem = rtcps.at(i);
|
||||
EXPECT_FALSE(srs_is_rtcp(&elem[0], 2));
|
||||
|
||||
// All RTCP should not be other packets.
|
||||
EXPECT_FALSE(srs_is_stun(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_dtls(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_TRUE(srs_is_rtp_or_rtcp(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_TRUE(srs_is_rtcp(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
// RTP packet.
|
||||
vector< vector<uint8_t> > rtps;
|
||||
if (true) { uint8_t data[12] = {0x80, 96}; mock_arr_push(rtps, data); }
|
||||
if (true) { uint8_t data[12] = {0x80, 127}; mock_arr_push(rtps, data); }
|
||||
if (true) { uint8_t data[12] = {0x80, 224}; mock_arr_push(rtps, data); }
|
||||
if (true) { uint8_t data[12] = {0x80, 255}; mock_arr_push(rtps, data); }
|
||||
for (int i = 0; i < (int)rtps.size(); i++) {
|
||||
vector<uint8_t> elem = rtps.at(i);
|
||||
EXPECT_TRUE(srs_is_rtp_or_rtcp(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_rtcp(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)rtps.size(); i++) {
|
||||
vector<uint8_t> elem = rtps.at(i);
|
||||
EXPECT_FALSE(srs_is_rtp_or_rtcp(&elem[0], 2));
|
||||
|
||||
// All RTP should not be other packets.
|
||||
EXPECT_FALSE(srs_is_stun(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_dtls(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_TRUE(srs_is_rtp_or_rtcp(&elem[0], (size_t)elem.size()));
|
||||
EXPECT_FALSE(srs_is_rtcp(&elem[0], (size_t)elem.size()));
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(KernelRTCTest, DefaultTrackStatus)
|
||||
{
|
||||
// By default, track is disabled.
|
||||
if (true) {
|
||||
SrsRtcTrackDescription td;
|
||||
|
||||
// The track must default to disable, that is, the active is false.
|
||||
EXPECT_FALSE(td.is_active_);
|
||||
}
|
||||
|
||||
// Enable it by player.
|
||||
if (true) {
|
||||
SrsRtcConnection s(NULL, SrsContextId()); SrsRtcPlayStream play(&s, SrsContextId());
|
||||
SrsRtcAudioSendTrack* audio; SrsRtcVideoSendTrack *video;
|
||||
|
||||
if (true) {
|
||||
SrsRtcTrackDescription ds; ds.type_ = "audio"; ds.id_ = "NSNWOn19NDn12o8nNeji2"; ds.ssrc_ = 100;
|
||||
play.audio_tracks_[ds.ssrc_] = audio = new SrsRtcAudioSendTrack(&s, &ds);
|
||||
}
|
||||
if (true) {
|
||||
SrsRtcTrackDescription ds; ds.type_ = "video"; ds.id_ = "VMo22nfLDn122nfnDNL2"; ds.ssrc_ = 200;
|
||||
play.video_tracks_[ds.ssrc_] = video = new SrsRtcVideoSendTrack(&s, &ds);
|
||||
}
|
||||
EXPECT_FALSE(audio->get_track_status());
|
||||
EXPECT_FALSE(video->get_track_status());
|
||||
|
||||
play.set_all_tracks_status(true);
|
||||
EXPECT_TRUE(audio->get_track_status());
|
||||
EXPECT_TRUE(video->get_track_status());
|
||||
}
|
||||
|
||||
// Enable it by publisher.
|
||||
if (true) {
|
||||
SrsRtcConnection s(NULL, SrsContextId()); SrsRtcPublishStream publish(&s);
|
||||
SrsRtcAudioRecvTrack* audio; SrsRtcVideoRecvTrack *video;
|
||||
|
||||
if (true) {
|
||||
SrsRtcTrackDescription ds; ds.type_ = "audio"; ds.id_ = "NSNWOn19NDn12o8nNeji2"; ds.ssrc_ = 100;
|
||||
audio = new SrsRtcAudioRecvTrack(&s, &ds); publish.audio_tracks_.push_back(audio);
|
||||
}
|
||||
if (true) {
|
||||
SrsRtcTrackDescription ds; ds.type_ = "video"; ds.id_ = "VMo22nfLDn122nfnDNL2"; ds.ssrc_ = 200;
|
||||
video = new SrsRtcVideoRecvTrack(&s, &ds); publish.video_tracks_.push_back(video);
|
||||
}
|
||||
EXPECT_FALSE(audio->get_track_status());
|
||||
EXPECT_FALSE(video->get_track_status());
|
||||
|
||||
publish.set_all_tracks_status(true);
|
||||
EXPECT_TRUE(audio->get_track_status());
|
||||
EXPECT_TRUE(video->get_track_status());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue