mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
merge upstream feature/rtc, solve conflict
This commit is contained in:
commit
749503a12e
28 changed files with 1173 additions and 439 deletions
8
trunk/3rdparty/st-srs/README.md
vendored
8
trunk/3rdparty/st-srs/README.md
vendored
|
@ -22,6 +22,8 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche
|
|||
- [x] Patch [st.osx10.14.build.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/6.st.osx10.14.build.patch), for osx 10.14 build.
|
||||
- [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8).
|
||||
- [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9).
|
||||
- [x] Support OSX for Apple Darwin, macOS, [#11](https://github.com/ossrs/state-threads/issues/11).
|
||||
- [x] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12).
|
||||
|
||||
## Docs
|
||||
|
||||
|
@ -85,4 +87,10 @@ Important cli options:
|
|||
1. `--track-origins=<yes|no> [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem.
|
||||
1. `--show-reachable=<yes|no> , --show-possibly-lost=<yes|no>`, to show the using memory.
|
||||
|
||||
## Analysis
|
||||
|
||||
1. About setjmp and longjmp, read [setjmp](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-setjmp.jpg).
|
||||
1. About the stack structure, read [stack](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-stack.jpg)
|
||||
1. About asm code comments, read [#91d530e](https://github.com/ossrs/state-threads/commit/91d530e#diff-ed9428b14ff6afda0e9ab04cc91d4445R25).
|
||||
|
||||
Winlin 2016
|
||||
|
|
|
@ -84,15 +84,6 @@ function Ubuntu_prepare()
|
|||
echo "The unzip is installed."
|
||||
fi
|
||||
|
||||
if [[ $SRS_NASM == YES ]]; then
|
||||
nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
echo "Installing nasm."
|
||||
require_sudoer "sudo apt-get install -y --force-yes nasm"
|
||||
sudo apt-get install -y --force-yes nasm; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi
|
||||
echo "The nasm is installed."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $SRS_VALGRIND == YES ]]; then
|
||||
valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
echo "Installing valgrind."
|
||||
|
@ -171,13 +162,6 @@ function Centos_prepare()
|
|||
echo "The unzip is installed."
|
||||
fi
|
||||
|
||||
nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
echo "Installing nasm."
|
||||
require_sudoer "sudo yum install -y nasm"
|
||||
sudo yum install -y nasm; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi
|
||||
echo "The nasm is installed."
|
||||
fi
|
||||
|
||||
if [[ $SRS_VALGRIND == YES ]]; then
|
||||
valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
echo "Installing valgrind."
|
||||
|
@ -230,15 +214,16 @@ function OSX_prepare()
|
|||
fi
|
||||
|
||||
OS_IS_OSX=YES
|
||||
echo "OSX detected, install tools if needed"
|
||||
# requires the osx when os
|
||||
if [ $OS_IS_OSX = YES ]; then
|
||||
if [ $SRS_OSX = NO ]; then
|
||||
echo "OSX detected, must specifies the --osx"
|
||||
echo "OSX detected, please use: ./configure --osx"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "OSX detected, install tools if needed"
|
||||
|
||||
brew --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
echo "install brew"
|
||||
echo "ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\""
|
||||
|
@ -281,6 +266,10 @@ function OSX_prepare()
|
|||
echo "install unzip success"
|
||||
fi
|
||||
|
||||
pkg-config --version >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
echo "Please install pkg-config"; exit -1;
|
||||
fi
|
||||
|
||||
echo "OSX install tools success"
|
||||
return 0
|
||||
}
|
||||
|
@ -614,9 +603,16 @@ fi
|
|||
#####################################################################################
|
||||
if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then
|
||||
FFMPEG_OPTIONS=""
|
||||
|
||||
# If disable nasm, disable all ASMs.
|
||||
if [[ $SRS_NASM == NO ]]; then
|
||||
FFMPEG_OPTIONS="--disable-asm --disable-x86asm --disable-inline-asm"
|
||||
fi
|
||||
# If no nasm, we disable the x86asm.
|
||||
nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
|
||||
FFMPEG_OPTIONS="--disable-x86asm"
|
||||
fi
|
||||
|
||||
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg/lib/libavcodec.a ]]; then
|
||||
echo "The ffmpeg-4.2-fit is ok.";
|
||||
else
|
||||
|
|
|
@ -569,6 +569,7 @@ function apply_user_detail_options() {
|
|||
|
||||
# Detect whether has sendmmsg.
|
||||
# @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
|
||||
mkdir -p ${SRS_OBJS} &&
|
||||
echo "#include <sys/socket.h>" > ${SRS_OBJS}/_tmp_sendmmsg_detect.c
|
||||
echo "int main(int argc, char** argv) {" >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
|
||||
echo " struct mmsghdr hdr;" >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
|
||||
|
|
|
@ -443,6 +443,21 @@ rtc_server {
|
|||
# @remark Linux 4.18+ only, for other OS always disabled.
|
||||
# default: on
|
||||
gso on;
|
||||
# Whether pad first packet for GSO for padding bytes.
|
||||
# If 0, disable padding for GSO.
|
||||
# @remark The max padding size is 0x7f(127).
|
||||
# default: 127
|
||||
padding 127;
|
||||
# Whether enable the perf stat at http://localhost:1985/api/v1/perf
|
||||
# default: on
|
||||
perf_stat on;
|
||||
# The queue length, in number of mmsghdr, in messages.
|
||||
# For example, 30 means we will cache 30K messages at most.
|
||||
# If exceed, we will drop messages.
|
||||
# @remark Each reuseport use a dedicated queue, if queue is 2000, reuseport is 4,
|
||||
# then system queue is 2000*4 = 8k, user can incrase reuseport to incrase the queue.
|
||||
# default: 2000
|
||||
queue_length 2000;
|
||||
}
|
||||
|
||||
vhost rtc.vhost.srs.com {
|
||||
|
@ -469,12 +484,17 @@ vhost rtc.vhost.srs.com {
|
|||
stun_strict_check on;
|
||||
}
|
||||
# whether enable min delay mode for vhost.
|
||||
# For RTC, we recommend to set to on.
|
||||
# default: on, for RTC.
|
||||
min_latency on;
|
||||
play {
|
||||
# set the MW(merged-write) latency in ms.
|
||||
# For RTC, we recommend lower value, such as 0.
|
||||
# @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config.
|
||||
# default: 0 (For WebRTC)
|
||||
mw_latency 0;
|
||||
# Set the MW(merged-write) min messages.
|
||||
# default: 0 (For Real-Time, min_latency on)
|
||||
# default: 1 (For WebRTC, min_latency off)
|
||||
mw_msgs 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,10 +721,17 @@ vhost play.srs.com {
|
|||
# SRS always set mw on, so we just set the latency value.
|
||||
# the latency of stream >= mw_latency + mr_latency
|
||||
# the value recomment is [300, 1800]
|
||||
# default: 350 (for RTMP/HTTP-FLV)
|
||||
# default: 0 (for WebRTC)
|
||||
# @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config.
|
||||
# default: 350 (For RTMP/HTTP-FLV)
|
||||
# default: 0 (For WebRTC)
|
||||
mw_latency 350;
|
||||
|
||||
# Set the MW(merged-write) min messages.
|
||||
# default: 0 (For Real-Time, min_latency on)
|
||||
# default: 1 (For WebRTC, min_latency off)
|
||||
# default: 8 (For RTMP/HTTP-FLV, min_latency off).
|
||||
mw_msgs 8;
|
||||
|
||||
# the minimal packets send interval in ms,
|
||||
# used to control the ndiff of stream by srs_rtmp_dump,
|
||||
# for example, some device can only accept some stream which
|
||||
|
@ -761,6 +788,7 @@ vhost mrw.srs.com {
|
|||
# @see play.srs.com
|
||||
play {
|
||||
mw_latency 350;
|
||||
mw_msgs 8;
|
||||
}
|
||||
|
||||
# @see publish.srs.com
|
||||
|
@ -780,6 +808,7 @@ vhost min.delay.com {
|
|||
# @see play.srs.com
|
||||
play {
|
||||
mw_latency 100;
|
||||
mw_msgs 4;
|
||||
gop_cache off;
|
||||
queue_length 10;
|
||||
}
|
||||
|
@ -808,6 +837,7 @@ vhost stream.control.com {
|
|||
# @see play.srs.com
|
||||
play {
|
||||
mw_latency 100;
|
||||
mw_msgs 4;
|
||||
queue_length 10;
|
||||
send_min_interval 10.0;
|
||||
reduce_sequence_header on;
|
||||
|
|
|
@ -41,8 +41,15 @@ print "Repsonse %s"%(s)
|
|||
|
||||
obj = json.loads(s)
|
||||
|
||||
print ""
|
||||
p = obj['data']['dropped']
|
||||
print('Frame-Dropped: %.1f%s'%(10000.0 * p['rtc_dropeed'] / p['rtc_frames'], '%%'))
|
||||
p = obj['data']['bytes']
|
||||
print('Padding-Overload: %.1f%s %dMB'%(10000.0 * p['rtc_padding'] / p['rtc_bytes'], '%%', p['rtc_padding']/1024/1024))
|
||||
|
||||
# 2, 3, 5, 9, 16, 32, 64, 128, 256
|
||||
keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256']
|
||||
print("\n----------- 1 2 [3,4] [5,8] [9,15] [16,31] [32,63] [64,127] [128,255] [256,+) Packets"),
|
||||
|
||||
print ""
|
||||
print("AV---Frames"),
|
||||
|
|
|
@ -3618,7 +3618,8 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
|
||||
string n = conf->at(i)->name;
|
||||
if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa"
|
||||
&& n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus") {
|
||||
&& n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus"
|
||||
&& n != "padding" && n != "perf_stat" && n != "queue_length") {
|
||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -3784,7 +3785,8 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "time_jitter" && m != "mix_correct" && m != "atc" && m != "atc_auto" && m != "mw_latency"
|
||||
&& m != "gop_cache" && m != "queue_length" && m != "send_min_interval" && m != "reduce_sequence_header") {
|
||||
&& m != "gop_cache" && m != "queue_length" && m != "send_min_interval" && m != "reduce_sequence_header"
|
||||
&& m != "mw_msgs") {
|
||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.play.%s of %s", m.c_str(), vhost->arg0().c_str());
|
||||
}
|
||||
}
|
||||
|
@ -4840,6 +4842,57 @@ bool SrsConfig::get_rtc_server_gso2()
|
|||
return SRS_CONF_PERFER_TRUE(conf->arg0());
|
||||
}
|
||||
|
||||
int SrsConfig::get_rtc_server_padding()
|
||||
{
|
||||
static int DEFAULT = 127;
|
||||
|
||||
SrsConfDirective* conf = root->get("rtc_server");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("padding");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return srs_min(127, ::atoi(conf->arg0().c_str()));
|
||||
}
|
||||
|
||||
bool SrsConfig::get_rtc_server_perf_stat()
|
||||
{
|
||||
static bool DEFAULT = true;
|
||||
|
||||
SrsConfDirective* conf = root->get("rtc_server");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("perf_stat");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return SRS_CONF_PERFER_TRUE(conf->arg0());
|
||||
}
|
||||
|
||||
int SrsConfig::get_rtc_server_queue_length()
|
||||
{
|
||||
static int DEFAULT = 2000;
|
||||
|
||||
SrsConfDirective* conf = root->get("rtc_server");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("queue_length");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_rtc(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost(vhost);
|
||||
|
@ -5367,8 +5420,48 @@ srs_utime_t SrsConfig::get_mw_sleep(string vhost, bool is_rtc)
|
|||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
int v = ::atoi(conf->arg0().c_str());
|
||||
if (is_rtc && v > 0) {
|
||||
srs_warn("For RTC, we ignore mw_latency");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS);
|
||||
return (srs_utime_t)(v * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
int SrsConfig::get_mw_msgs(string vhost, bool is_realtime, bool is_rtc)
|
||||
{
|
||||
int DEFAULT = SRS_PERF_MW_MIN_MSGS;
|
||||
if (is_rtc) {
|
||||
DEFAULT = SRS_PERF_MW_MIN_MSGS_FOR_RTC;
|
||||
}
|
||||
if (is_realtime) {
|
||||
DEFAULT = SRS_PERF_MW_MIN_MSGS_REALTIME;
|
||||
}
|
||||
|
||||
SrsConfDirective* conf = get_vhost(vhost);
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("play");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("mw_msgs");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
int v = ::atoi(conf->arg0().c_str());
|
||||
if (v > SRS_PERF_MW_MSGS) {
|
||||
srs_warn("reset mw_msgs %d to max %d", v, SRS_PERF_MW_MSGS);
|
||||
v = SRS_PERF_MW_MSGS;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool SrsConfig::get_realtime_enabled(string vhost, bool is_rtc)
|
||||
|
|
|
@ -535,6 +535,11 @@ public:
|
|||
virtual bool get_rtc_server_gso();
|
||||
private:
|
||||
virtual bool get_rtc_server_gso2();
|
||||
public:
|
||||
virtual int get_rtc_server_padding();
|
||||
virtual bool get_rtc_server_perf_stat();
|
||||
virtual int get_rtc_server_queue_length();
|
||||
|
||||
public:
|
||||
SrsConfDirective* get_rtc(std::string vhost);
|
||||
bool get_rtc_enabled(std::string vhost);
|
||||
|
@ -625,6 +630,10 @@ public:
|
|||
// @param vhost, the vhost to get the mw sleep time.
|
||||
// TODO: FIXME: add utest for mw config.
|
||||
virtual srs_utime_t get_mw_sleep(std::string vhost, bool is_rtc = false);
|
||||
// Get the mw_msgs, mw wait time in packets for vhost.
|
||||
// @param vhost, the vhost to get the mw sleep msgs.
|
||||
// TODO: FIXME: add utest for mw config.
|
||||
virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc = false);
|
||||
// Whether min latency mode enabled.
|
||||
// @param vhost, the vhost to get the min_latency.
|
||||
// TODO: FIXME: add utest for min_latency.
|
||||
|
|
|
@ -869,6 +869,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
api = prop->to_str();
|
||||
}
|
||||
|
||||
// TODO: FIXME: Parse vhost.
|
||||
// Parse app and stream from streamurl.
|
||||
string app;
|
||||
string stream_name;
|
||||
|
@ -909,6 +910,13 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
request.app = app;
|
||||
request.stream = stream_name;
|
||||
|
||||
// TODO: FIXME: Parse vhost.
|
||||
// discovery vhost, resolve the vhost from config
|
||||
SrsConfDirective* parsed_vhost = _srs_config->get_vhost("");
|
||||
if (parsed_vhost) {
|
||||
request.vhost = parsed_vhost->arg0();
|
||||
}
|
||||
|
||||
// TODO: FIXME: Maybe need a better name?
|
||||
// TODO: FIXME: When server enabled, but vhost disabled, should report error.
|
||||
SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp, eip);
|
||||
|
@ -1615,14 +1623,23 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
|
||||
string target = r->query_get("target");
|
||||
srs_trace("query target=%s", target.c_str());
|
||||
string reset = r->query_get("reset");
|
||||
srs_trace("query target=%s, reset=%s, rtc_stat_enabled=%d", target.c_str(), reset.c_str(),
|
||||
_srs_config->get_rtc_server_perf_stat());
|
||||
|
||||
if (true) {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("query", p);
|
||||
|
||||
p->set("target", SrsJsonAny::str(target.c_str()));
|
||||
p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg"));
|
||||
p->set("reset", SrsJsonAny::str(reset.c_str()));
|
||||
p->set("help", SrsJsonAny::str("?target=avframes|rtc|rtp|gso|writev_iovs|sendmmsg|bytes|dropped"));
|
||||
p->set("help2", SrsJsonAny::str("?reset=all"));
|
||||
}
|
||||
|
||||
if (!reset.empty()) {
|
||||
stat->reset_perf();
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
|
||||
if (target.empty() || target == "avframes") {
|
||||
|
@ -1679,6 +1696,24 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
|
|||
}
|
||||
}
|
||||
|
||||
if (target.empty() || target == "bytes") {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("bytes", p);
|
||||
if ((err = stat->dumps_perf_bytes(p)) != srs_success) {
|
||||
int code = srs_error_code(err); srs_error_reset(err);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
}
|
||||
|
||||
if (target.empty() || target == "dropped") {
|
||||
SrsJsonObject* p = SrsJsonAny::object();
|
||||
data->set("dropped", p);
|
||||
if ((err = stat->dumps_perf_dropped(p)) != srs_success) {
|
||||
int code = srs_error_code(err); srs_error_reset(err);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
|
||||
|
|
|
@ -660,7 +660,8 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
if ((err = consumer->dump_packets(&msgs, count)) != srs_success) {
|
||||
return srs_error_wrap(err, "consumer dump packets");
|
||||
}
|
||||
|
||||
|
||||
// TODO: FIXME: Support merged-write wait.
|
||||
if (count <= 0) {
|
||||
// Directly use sleep, donot use consumer wait, because we couldn't awake consumer.
|
||||
srs_usleep(mw_sleep);
|
||||
|
|
|
@ -141,6 +141,11 @@ public:
|
|||
virtual srs_error_t fetch(mmsghdr** pphdr) = 0;
|
||||
// Notify the sender to send out the msg.
|
||||
virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0;
|
||||
// Whether sender exceed the max queue, that is, overflow.
|
||||
virtual bool overflow() = 0;
|
||||
// Set the queue extra ratio, for example, when mw_msgs > 0, we need larger queue.
|
||||
// For r, 100 means x1, 200 means x2.
|
||||
virtual void set_extra_ratio(int r) = 0;
|
||||
};
|
||||
|
||||
class SrsUdpMuxSocket
|
||||
|
|
|
@ -195,15 +195,19 @@ srs_error_t SrsRtpOpusMuxer::transcode(SrsSharedPtrMessage* shared_audio, char*
|
|||
return err;
|
||||
}
|
||||
|
||||
int nn_max_extra_payload = 0;
|
||||
SrsSample samples[nn_opus_packets];
|
||||
for (int i = 0; i < nn_opus_packets; i++) {
|
||||
SrsSample* p = samples + i;
|
||||
p->size = opus_sizes[i];
|
||||
p->bytes = new char[p->size];
|
||||
memcpy(p->bytes, opus_payloads[i], p->size);
|
||||
|
||||
nn_max_extra_payload = srs_max(nn_max_extra_payload, p->size);
|
||||
}
|
||||
|
||||
shared_audio->set_extra_payloads(samples, nn_opus_packets);
|
||||
shared_audio->set_max_extra_payload(nn_max_extra_payload);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -50,6 +50,7 @@ class SrsRtcSession;
|
|||
class SrsSharedPtrMessage;
|
||||
class SrsSource;
|
||||
class SrsRtpPacket2;
|
||||
class ISrsUdpSender;
|
||||
|
||||
const uint8_t kSR = 200;
|
||||
const uint8_t kRR = 201;
|
||||
|
@ -124,8 +125,18 @@ public:
|
|||
bool use_gso;
|
||||
bool should_merge_nalus;
|
||||
public:
|
||||
// The total bytes of RTP packets.
|
||||
#if defined(SRS_DEBUG)
|
||||
// Debug id.
|
||||
uint32_t debug_id;
|
||||
#endif
|
||||
public:
|
||||
// The total bytes of AVFrame packets.
|
||||
int nn_bytes;
|
||||
// The total bytes of RTP packets.
|
||||
int nn_rtp_bytes;
|
||||
// The total padded bytes.
|
||||
int nn_padding_bytes;
|
||||
public:
|
||||
// The RTP packets send out by sendmmsg or sendmsg. Note that if many packets group to
|
||||
// one msghdr by GSO, it's only one RTP packet, because we only send once.
|
||||
int nn_rtp_pkts;
|
||||
|
@ -138,11 +149,24 @@ public:
|
|||
int nn_audios;
|
||||
// The original video messages.
|
||||
int nn_videos;
|
||||
// The number of padded packet.
|
||||
int nn_paddings;
|
||||
// The number of dropped messages.
|
||||
int nn_dropped;
|
||||
private:
|
||||
int cursor;
|
||||
int nn_cache;
|
||||
SrsRtpPacket2* cache;
|
||||
public:
|
||||
std::vector<SrsRtpPacket2*> packets;
|
||||
public:
|
||||
SrsRtcPackets(bool gso, bool merge_nalus);
|
||||
SrsRtcPackets(int nn_cache_max);
|
||||
virtual ~SrsRtcPackets();
|
||||
public:
|
||||
void reset(bool gso, bool merge_nalus);
|
||||
SrsRtpPacket2* fetch();
|
||||
SrsRtpPacket2* back();
|
||||
int size();
|
||||
int capacity();
|
||||
SrsRtpPacket2* at(int index);
|
||||
};
|
||||
|
||||
class SrsRtcSenderThread : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
|
||||
|
@ -164,8 +188,16 @@ private:
|
|||
uint16_t video_sequence;
|
||||
public:
|
||||
SrsUdpMuxSocket* sendonly_ukt;
|
||||
private:
|
||||
ISrsUdpSender* sender;
|
||||
private:
|
||||
bool merge_nalus;
|
||||
bool gso;
|
||||
int max_padding;
|
||||
private:
|
||||
srs_utime_t mw_sleep;
|
||||
int mw_msgs;
|
||||
bool realtime;
|
||||
public:
|
||||
SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid);
|
||||
virtual ~SrsRtcSenderThread();
|
||||
|
@ -174,6 +206,8 @@ public:
|
|||
// interface ISrsReloadHandler
|
||||
public:
|
||||
virtual srs_error_t on_reload_rtc_server();
|
||||
virtual srs_error_t on_reload_vhost_play(std::string vhost);
|
||||
virtual srs_error_t on_reload_vhost_realtime(std::string vhost);
|
||||
public:
|
||||
virtual int cid();
|
||||
public:
|
||||
|
@ -185,17 +219,17 @@ public:
|
|||
public:
|
||||
virtual srs_error_t cycle();
|
||||
private:
|
||||
srs_error_t send_messages(SrsUdpMuxSocket* skt, SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets);
|
||||
srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets);
|
||||
srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcPackets& packets);
|
||||
srs_error_t send_packets(SrsUdpMuxSocket* skt, SrsRtcPackets& packets);
|
||||
srs_error_t send_packets_gso(SrsUdpMuxSocket* skt, SrsRtcPackets& packets);
|
||||
srs_error_t send_packets(SrsRtcPackets& packets);
|
||||
srs_error_t send_packets_gso(SrsRtcPackets& packets);
|
||||
private:
|
||||
srs_error_t packet_opus(SrsSample* sample, SrsRtpPacket2** ppacket);
|
||||
srs_error_t packet_opus(SrsSample* sample, SrsRtcPackets& packets, int nn_max_payload);
|
||||
private:
|
||||
srs_error_t packet_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcPackets& packets);
|
||||
srs_error_t packet_nalus(SrsSharedPtrMessage* msg, SrsRtcPackets& packets);
|
||||
srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtpPacket2** ppacket);
|
||||
srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtpPacket2** ppacket);
|
||||
srs_error_t packet_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtcPackets& packets);
|
||||
srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtcPackets& packets);
|
||||
};
|
||||
|
||||
class SrsRtcSession
|
||||
|
@ -274,6 +308,9 @@ private:
|
|||
private:
|
||||
srs_cond_t cond;
|
||||
bool waiting_msgs;
|
||||
bool gso;
|
||||
int nn_senders;
|
||||
private:
|
||||
// Hotspot msgs, we are working on it.
|
||||
// @remark We will wait util all messages are ready.
|
||||
std::vector<mmsghdr> hotspot;
|
||||
|
@ -282,16 +319,24 @@ private:
|
|||
int cache_pos;
|
||||
// The max number of messages for sendmmsg. If 1, we use sendmsg to send.
|
||||
int max_sendmmsg;
|
||||
// The total queue length, for each sender.
|
||||
int queue_length;
|
||||
// The extra queue ratio.
|
||||
int extra_ratio;
|
||||
int extra_queue;
|
||||
public:
|
||||
SrsUdpMuxSender(SrsRtcServer* s);
|
||||
virtual ~SrsUdpMuxSender();
|
||||
public:
|
||||
virtual srs_error_t initialize(srs_netfd_t fd);
|
||||
virtual srs_error_t initialize(srs_netfd_t fd, int senders);
|
||||
private:
|
||||
void free_mhdrs(std::vector<mmsghdr>& mhdrs);
|
||||
public:
|
||||
virtual srs_error_t fetch(mmsghdr** pphdr);
|
||||
virtual srs_error_t sendmmsg(mmsghdr* hdr);
|
||||
virtual bool overflow();
|
||||
virtual void set_extra_ratio(int r);
|
||||
public:
|
||||
virtual srs_error_t cycle();
|
||||
// interface ISrsReloadHandler
|
||||
public:
|
||||
|
|
|
@ -116,7 +116,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* svr, srs_netfd_t c, string cip) : SrsConnect
|
|||
wakable = NULL;
|
||||
|
||||
mw_sleep = SRS_PERF_MW_SLEEP;
|
||||
mw_enabled = false;
|
||||
mw_msgs = 0;
|
||||
realtime = SRS_PERF_MIN_LATENCY_ENABLED;
|
||||
send_min_interval = 0;
|
||||
tcp_nodelay = false;
|
||||
|
@ -264,6 +264,10 @@ srs_error_t SrsRtmpConn::on_reload_vhost_play(string vhost)
|
|||
send_min_interval = v;
|
||||
}
|
||||
}
|
||||
|
||||
mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime);
|
||||
mw_sleep = _srs_config->get_mw_sleep(req->vhost);
|
||||
set_socket_buffer(mw_sleep);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -298,6 +302,10 @@ srs_error_t SrsRtmpConn::on_reload_vhost_realtime(string vhost)
|
|||
srs_trace("realtime changed %d=>%d", realtime, realtime_enabled);
|
||||
realtime = realtime_enabled;
|
||||
}
|
||||
|
||||
mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime);
|
||||
mw_sleep = _srs_config->get_mw_sleep(req->vhost);
|
||||
set_socket_buffer(mw_sleep);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -689,18 +697,19 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr
|
|||
SrsMessageArray msgs(SRS_PERF_MW_MSGS);
|
||||
bool user_specified_duration_to_stop = (req->duration > 0);
|
||||
int64_t starttime = -1;
|
||||
|
||||
|
||||
// setup the realtime.
|
||||
realtime = _srs_config->get_realtime_enabled(req->vhost);
|
||||
// setup the mw config.
|
||||
// when mw_sleep changed, resize the socket send buffer.
|
||||
mw_enabled = true;
|
||||
change_mw_sleep(_srs_config->get_mw_sleep(req->vhost));
|
||||
mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime);
|
||||
mw_sleep = _srs_config->get_mw_sleep(req->vhost);
|
||||
set_socket_buffer(mw_sleep);
|
||||
// initialize the send_min_interval
|
||||
send_min_interval = _srs_config->get_send_min_interval(req->vhost);
|
||||
|
||||
srs_trace("start play smi=%dms, mw_sleep=%d, mw_enabled=%d, realtime=%d, tcp_nodelay=%d",
|
||||
srsu2msi(send_min_interval), srsu2msi(mw_sleep), mw_enabled, realtime, tcp_nodelay);
|
||||
srs_trace("start play smi=%dms, mw_sleep=%d, mw_msgs=%d, realtime=%d, tcp_nodelay=%d",
|
||||
srsu2msi(send_min_interval), srsu2msi(mw_sleep), mw_msgs, realtime, tcp_nodelay);
|
||||
|
||||
while (true) {
|
||||
// when source is set to expired, disconnect it.
|
||||
|
@ -730,13 +739,7 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr
|
|||
// wait for message to incoming.
|
||||
// @see https://github.com/ossrs/srs/issues/251
|
||||
// @see https://github.com/ossrs/srs/issues/257
|
||||
if (realtime) {
|
||||
// for realtime, min required msgs is 0, send when got one+ msgs.
|
||||
consumer->wait(SRS_PERF_MW_MIN_MSGS_REALTIME, mw_sleep);
|
||||
} else {
|
||||
// for no-realtime, got some msgs then send.
|
||||
consumer->wait(SRS_PERF_MW_MIN_MSGS, mw_sleep);
|
||||
}
|
||||
consumer->wait(mw_msgs, mw_sleep);
|
||||
#endif
|
||||
|
||||
// get messages from consumer.
|
||||
|
@ -750,9 +753,9 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr
|
|||
// reportable
|
||||
if (pprint->can_print()) {
|
||||
kbps->sample();
|
||||
srs_trace("-> " SRS_CONSTS_LOG_PLAY " time=%d, msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d, mw=%d",
|
||||
srs_trace("-> " SRS_CONSTS_LOG_PLAY " time=%d, msgs=%d, okbps=%d,%d,%d, ikbps=%d,%d,%d, mw=%d/%d",
|
||||
(int)pprint->age(), count, kbps->get_send_kbps(), kbps->get_send_kbps_30s(), kbps->get_send_kbps_5m(),
|
||||
kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m(), srsu2msi(mw_sleep));
|
||||
kbps->get_recv_kbps(), kbps->get_recv_kbps_30s(), kbps->get_recv_kbps_5m(), srsu2msi(mw_sleep), mw_msgs);
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
|
@ -1114,16 +1117,6 @@ srs_error_t SrsRtmpConn::process_play_control_msg(SrsConsumer* consumer, SrsComm
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsRtmpConn::change_mw_sleep(srs_utime_t sleep_v)
|
||||
{
|
||||
if (!mw_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_socket_buffer(sleep_v);
|
||||
mw_sleep = sleep_v;
|
||||
}
|
||||
|
||||
void SrsRtmpConn::set_sock_options()
|
||||
{
|
||||
SrsRequest* req = info->req;
|
||||
|
|
|
@ -102,8 +102,7 @@ private:
|
|||
srs_utime_t duration;
|
||||
// The MR(merged-write) sleep time in srs_utime_t.
|
||||
srs_utime_t mw_sleep;
|
||||
// The MR(merged-write) only enabled for play.
|
||||
int mw_enabled;
|
||||
int mw_msgs;
|
||||
// For realtime
|
||||
// @see https://github.com/ossrs/srs/issues/257
|
||||
bool realtime;
|
||||
|
@ -149,7 +148,6 @@ private:
|
|||
virtual srs_error_t handle_publish_message(SrsSource* source, SrsCommonMessage* msg);
|
||||
virtual srs_error_t process_publish_message(SrsSource* source, SrsCommonMessage* msg);
|
||||
virtual srs_error_t process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg);
|
||||
virtual void change_mw_sleep(srs_utime_t sleep_v);
|
||||
virtual void set_sock_options();
|
||||
private:
|
||||
virtual srs_error_t check_edge_token_traverse_auth();
|
||||
|
|
|
@ -269,9 +269,17 @@ void SrsMessageQueue::set_queue_size(srs_utime_t queue_size)
|
|||
max_queue_size = queue_size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow)
|
||||
srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow, bool pass_timestamp)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
msgs.push_back(msg);
|
||||
|
||||
// For RTC, we never care about the timestamp and duration, so we never shrink queue here,
|
||||
// but we will drop messages in each consumer coroutine.
|
||||
if (pass_timestamp) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (msg->is_av()) {
|
||||
if (av_start_time == -1) {
|
||||
|
@ -281,8 +289,6 @@ srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow
|
|||
av_end_time = srs_utime_t(msg->timestamp * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
msgs.push_back(msg);
|
||||
|
||||
while (av_end_time - av_start_time > max_queue_size) {
|
||||
// notice the caller queue already overflow and shrinked.
|
||||
if (is_overflow) {
|
||||
|
@ -295,7 +301,7 @@ srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count)
|
||||
srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count, bool pass_timestamp)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
@ -308,13 +314,15 @@ srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** p
|
|||
count = srs_min(max_count, nb_msgs);
|
||||
|
||||
SrsSharedPtrMessage** omsgs = msgs.data();
|
||||
for (int i = 0; i < count; i++) {
|
||||
pmsgs[i] = omsgs[i];
|
||||
memcpy(pmsgs, omsgs, count * sizeof(SrsSharedPtrMessage*));
|
||||
|
||||
// For RTC, we enable pass_timestamp mode, which never care about the timestamp and duration,
|
||||
// so we do not have to update the start time here.
|
||||
if (!pass_timestamp) {
|
||||
SrsSharedPtrMessage* last = omsgs[count - 1];
|
||||
av_start_time = srs_utime_t(last->timestamp * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
SrsSharedPtrMessage* last = omsgs[count - 1];
|
||||
av_start_time = srs_utime_t(last->timestamp * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
if (count >= nb_msgs) {
|
||||
// the pmsgs is big enough and clear msgs at most time.
|
||||
msgs.clear();
|
||||
|
@ -433,6 +441,8 @@ SrsConsumer::SrsConsumer(SrsSource* s, SrsConnection* c)
|
|||
mw_duration = 0;
|
||||
mw_waiting = false;
|
||||
#endif
|
||||
|
||||
pass_timestamp = false;
|
||||
}
|
||||
|
||||
SrsConsumer::~SrsConsumer()
|
||||
|
@ -466,20 +476,35 @@ srs_error_t SrsConsumer::enqueue(SrsSharedPtrMessage* shared_msg, bool atc, SrsR
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
SrsSharedPtrMessage* msg = shared_msg->copy();
|
||||
|
||||
if (!atc) {
|
||||
|
||||
// For RTC, we enable pass_timestamp mode, which never correct or depends on monotonic increasing of
|
||||
// timestamp. And in RTC, the audio and video timebase can be different, so we ignore time_jitter here.
|
||||
if (!pass_timestamp && !atc) {
|
||||
if ((err = jitter->correct(msg, ag)) != srs_success) {
|
||||
return srs_error_wrap(err, "consume message");
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = queue->enqueue(msg, NULL)) != srs_success) {
|
||||
|
||||
// Put message in queue, here we may enable pass_timestamp mode.
|
||||
if ((err = queue->enqueue(msg, NULL, pass_timestamp)) != srs_success) {
|
||||
return srs_error_wrap(err, "enqueue message");
|
||||
}
|
||||
|
||||
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
||||
// fire the mw when msgs is enough.
|
||||
if (mw_waiting) {
|
||||
// For RTC, we use pass_timestamp mode, we don't care about the timestamp in queue,
|
||||
// so we only check the messages in queue.
|
||||
if (pass_timestamp) {
|
||||
if (queue->size() > mw_min_msgs) {
|
||||
srs_cond_signal(mw_wait);
|
||||
mw_waiting = false;
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// For RTMP, we wait for messages and duration.
|
||||
srs_utime_t duration = queue->duration();
|
||||
bool match_min_msgs = queue->size() > mw_min_msgs;
|
||||
|
||||
|
@ -529,7 +554,7 @@ srs_error_t SrsConsumer::dump_packets(SrsMessageArray* msgs, int& count)
|
|||
}
|
||||
|
||||
// pump msgs from queue.
|
||||
if ((err = queue->dump_packets(max, msgs->msgs, count)) != srs_success) {
|
||||
if ((err = queue->dump_packets(max, msgs->msgs, count, pass_timestamp)) != srs_success) {
|
||||
return srs_error_wrap(err, "dump packets");
|
||||
}
|
||||
|
||||
|
|
|
@ -151,12 +151,13 @@ public:
|
|||
// Enqueue the message, the timestamp always monotonically.
|
||||
// @param msg, the msg to enqueue, user never free it whatever the return code.
|
||||
// @param is_overflow, whether overflow and shrinked. NULL to ignore.
|
||||
virtual srs_error_t enqueue(SrsSharedPtrMessage* msg, bool* is_overflow = NULL);
|
||||
// @remark If pass_timestamp, we never shrink and never care about the timestamp or duration.
|
||||
virtual srs_error_t enqueue(SrsSharedPtrMessage* msg, bool* is_overflow = NULL, bool pass_timestamp = false);
|
||||
// Get packets in consumer queue.
|
||||
// @pmsgs SrsSharedPtrMessage*[], used to store the msgs, user must alloc it.
|
||||
// @count the count in array, output param.
|
||||
// @max_count the max count to dequeue, must be positive.
|
||||
virtual srs_error_t dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count);
|
||||
virtual srs_error_t dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count, bool pass_timestamp = false);
|
||||
// Dumps packets to consumer, use specified args.
|
||||
// @remark the atc/tba/tbv/ag are same to SrsConsumer.enqueue().
|
||||
virtual srs_error_t dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag);
|
||||
|
@ -203,10 +204,17 @@ private:
|
|||
int mw_min_msgs;
|
||||
srs_utime_t mw_duration;
|
||||
#endif
|
||||
private:
|
||||
// For RTC, we never use jitter to correct timestamp.
|
||||
// But we should not change the atc or time_jitter for source or RTMP.
|
||||
// @remark In this mode, we also never check the queue by timstamp, but only by count.
|
||||
bool pass_timestamp;
|
||||
public:
|
||||
SrsConsumer(SrsSource* s, SrsConnection* c);
|
||||
virtual ~SrsConsumer();
|
||||
public:
|
||||
// Use pass timestamp mode.
|
||||
void enable_pass_timestamp() { pass_timestamp = true; }
|
||||
// Set the size of queue.
|
||||
virtual void set_queue_size(srs_utime_t queue_size);
|
||||
// when source id changed, notice client to print.
|
||||
|
|
|
@ -271,6 +271,8 @@ SrsStatistic::SrsStatistic()
|
|||
perf_gso = new SrsStatisticCategory();
|
||||
perf_rtp = new SrsStatisticCategory();
|
||||
perf_rtc = new SrsStatisticCategory();
|
||||
perf_bytes = new SrsStatisticCategory();
|
||||
perf_dropped = new SrsStatisticCategory();
|
||||
}
|
||||
|
||||
SrsStatistic::~SrsStatistic()
|
||||
|
@ -311,6 +313,8 @@ SrsStatistic::~SrsStatistic()
|
|||
srs_freep(perf_gso);
|
||||
srs_freep(perf_rtp);
|
||||
srs_freep(perf_rtc);
|
||||
srs_freep(perf_bytes);
|
||||
srs_freep(perf_dropped);
|
||||
}
|
||||
|
||||
SrsStatistic* SrsStatistic::instance()
|
||||
|
@ -641,7 +645,7 @@ srs_error_t SrsStatistic::dumps_perf_writev_iovs(SrsJsonObject* obj)
|
|||
return dumps_perf(perf_iovs, obj);
|
||||
}
|
||||
|
||||
void SrsStatistic::perf_sendmmsg_on_packets(int nb_packets)
|
||||
void SrsStatistic::perf_on_sendmmsg_packets(int nb_packets)
|
||||
{
|
||||
perf_on_packets(perf_sendmmsg, nb_packets);
|
||||
}
|
||||
|
@ -651,6 +655,73 @@ srs_error_t SrsStatistic::dumps_perf_sendmmsg(SrsJsonObject* obj)
|
|||
return dumps_perf(perf_sendmmsg, obj);
|
||||
}
|
||||
|
||||
void SrsStatistic::perf_on_rtc_bytes(int nn_bytes, int nn_rtp_bytes, int nn_padding)
|
||||
{
|
||||
// a: AVFrame bytes.
|
||||
// b: RTC bytes.
|
||||
// c: RTC paddings.
|
||||
perf_bytes->a += nn_bytes;
|
||||
perf_bytes->b += nn_rtp_bytes;
|
||||
perf_bytes->c += nn_padding;
|
||||
|
||||
perf_bytes->nn += nn_rtp_bytes;
|
||||
}
|
||||
|
||||
srs_error_t SrsStatistic::dumps_perf_bytes(SrsJsonObject* obj)
|
||||
{
|
||||
obj->set("avframe_bytes", SrsJsonAny::integer(perf_bytes->a));
|
||||
obj->set("rtc_bytes", SrsJsonAny::integer(perf_bytes->b));
|
||||
obj->set("rtc_padding", SrsJsonAny::integer(perf_bytes->c));
|
||||
|
||||
obj->set("nn", SrsJsonAny::integer(perf_bytes->nn));
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
void SrsStatistic::perf_on_dropped(int nn_msgs, int nn_rtc, int nn_dropped)
|
||||
{
|
||||
// a: System AVFrames.
|
||||
// b: RTC frames.
|
||||
// c: Dropped frames.
|
||||
perf_dropped->a += nn_msgs;
|
||||
perf_dropped->b += nn_rtc;
|
||||
perf_dropped->c += nn_dropped;
|
||||
|
||||
perf_dropped->nn += nn_dropped;
|
||||
}
|
||||
|
||||
srs_error_t SrsStatistic::dumps_perf_dropped(SrsJsonObject* obj)
|
||||
{
|
||||
obj->set("avframes", SrsJsonAny::integer(perf_dropped->a));
|
||||
obj->set("rtc_frames", SrsJsonAny::integer(perf_dropped->b));
|
||||
obj->set("rtc_dropeed", SrsJsonAny::integer(perf_dropped->c));
|
||||
|
||||
obj->set("nn", SrsJsonAny::integer(perf_dropped->nn));
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
void SrsStatistic::reset_perf()
|
||||
{
|
||||
srs_freep(perf_iovs);
|
||||
srs_freep(perf_msgs);
|
||||
srs_freep(perf_sendmmsg);
|
||||
srs_freep(perf_gso);
|
||||
srs_freep(perf_rtp);
|
||||
srs_freep(perf_rtc);
|
||||
srs_freep(perf_bytes);
|
||||
srs_freep(perf_dropped);
|
||||
|
||||
perf_iovs = new SrsStatisticCategory();
|
||||
perf_msgs = new SrsStatisticCategory();
|
||||
perf_sendmmsg = new SrsStatisticCategory();
|
||||
perf_gso = new SrsStatisticCategory();
|
||||
perf_rtp = new SrsStatisticCategory();
|
||||
perf_rtc = new SrsStatisticCategory();
|
||||
perf_bytes = new SrsStatisticCategory();
|
||||
perf_dropped = new SrsStatisticCategory();
|
||||
}
|
||||
|
||||
void SrsStatistic::perf_on_packets(SrsStatisticCategory* p, int nb_msgs)
|
||||
{
|
||||
// The range for stat:
|
||||
|
|
|
@ -174,6 +174,8 @@ private:
|
|||
SrsStatisticCategory* perf_gso;
|
||||
SrsStatisticCategory* perf_rtp;
|
||||
SrsStatisticCategory* perf_rtc;
|
||||
SrsStatisticCategory* perf_bytes;
|
||||
SrsStatisticCategory* perf_dropped;
|
||||
private:
|
||||
SrsStatistic();
|
||||
virtual ~SrsStatistic();
|
||||
|
@ -245,13 +247,11 @@ public:
|
|||
// Stat for packets merged written, nb_packets is the number of RTP packets.
|
||||
// For example, a RTC/opus packet maybe package to three RTP packets.
|
||||
virtual void perf_on_rtp_packets(int nb_packets);
|
||||
// Dumps the perf statistic data for RTP packets, for performance analysis.
|
||||
virtual srs_error_t dumps_perf_rtp_packets(SrsJsonObject* obj);
|
||||
public:
|
||||
// Stat for packets UDP GSO, nb_packets is the merged RTP packets.
|
||||
// For example, three RTP/audio packets maybe GSO to one msghdr.
|
||||
virtual void perf_on_gso_packets(int nb_packets);
|
||||
// Dumps the perf statistic data for UDP GSO, for performance analysis.
|
||||
virtual srs_error_t dumps_perf_gso(SrsJsonObject* obj);
|
||||
public:
|
||||
// Stat for TCP writev, nb_iovs is the total number of iovec.
|
||||
|
@ -259,9 +259,19 @@ public:
|
|||
virtual srs_error_t dumps_perf_writev_iovs(SrsJsonObject* obj);
|
||||
public:
|
||||
// Stat for packets UDP sendmmsg, nb_packets is the vlen for sendmmsg.
|
||||
virtual void perf_sendmmsg_on_packets(int nb_packets);
|
||||
// Dumps the perf statistic data for UDP sendmmsg, for performance analysis.
|
||||
virtual void perf_on_sendmmsg_packets(int nb_packets);
|
||||
virtual srs_error_t dumps_perf_sendmmsg(SrsJsonObject* obj);
|
||||
public:
|
||||
// Stat for bytes, nn_bytes is the size of bytes, nb_padding is padding bytes.
|
||||
virtual void perf_on_rtc_bytes(int nn_bytes, int nn_rtp_bytes, int nn_padding);
|
||||
virtual srs_error_t dumps_perf_bytes(SrsJsonObject* obj);
|
||||
public:
|
||||
// Stat for rtc messages, nn_rtc is rtc messages, nn_dropped is dropped messages.
|
||||
virtual void perf_on_dropped(int nn_msgs, int nn_rtc, int nn_dropped);
|
||||
virtual srs_error_t dumps_perf_dropped(SrsJsonObject* obj);
|
||||
public:
|
||||
// Reset all perf stat data.
|
||||
virtual void reset_perf();
|
||||
private:
|
||||
virtual void perf_on_packets(SrsStatisticCategory* p, int nb_msgs);
|
||||
virtual srs_error_t dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj);
|
||||
|
|
|
@ -129,10 +129,10 @@
|
|||
#ifdef SRS_PERF_QUEUE_COND_WAIT
|
||||
// For RTMP, use larger wait queue.
|
||||
#define SRS_PERF_MW_MIN_MSGS 8
|
||||
#define SRS_PERF_MW_MIN_MSGS_REALTIME 0
|
||||
// For RTC, use smaller wait queue.
|
||||
#define SRS_PERF_MW_MIN_MSGS_FOR_RTC 2
|
||||
#define SRS_PERF_MW_MIN_MSGS_FOR_RTC_REALTIME 0
|
||||
#define SRS_PERF_MW_MIN_MSGS_FOR_RTC 1
|
||||
// For Real-Time, never wait messages.
|
||||
#define SRS_PERF_MW_MIN_MSGS_REALTIME 0
|
||||
#endif
|
||||
/**
|
||||
* the default value of vhost for
|
||||
|
@ -192,5 +192,27 @@
|
|||
#define SRS_PERF_GLIBC_MEMORY_CHECK
|
||||
#undef SRS_PERF_GLIBC_MEMORY_CHECK
|
||||
|
||||
// For RTC, how many iovs we alloc for each mmsghdr for GSO.
|
||||
// Assume that there are 3300 clients, say, 10000 msgs in queue to send, the memory is:
|
||||
// 2 # We have two queue, cache and hotspot.
|
||||
// * 4 # We have reuseport, each have msg cache queue.
|
||||
// * (64 + 16*SRS_PERF_RTC_GSO_MAX + SRS_PERF_RTC_GSO_IOVS * 1500) # Each message size.
|
||||
// * 10000 # Total messages.
|
||||
// = 197MB # For SRS_PERF_RTC_GSO_IOVS = 1
|
||||
// = 311MB # For SRS_PERF_RTC_GSO_IOVS = 2
|
||||
// = 540MB # For SRS_PERF_RTC_GSO_IOVS = 4
|
||||
// = 998MB # For SRS_PERF_RTC_GSO_IOVS = 8
|
||||
#if defined(__linux__)
|
||||
#define SRS_PERF_RTC_GSO_IOVS 4
|
||||
#else
|
||||
#define SRS_PERF_RTC_GSO_IOVS 1
|
||||
#endif
|
||||
|
||||
// For RTC, the max iovs in msghdr, the max packets sent in a msghdr.
|
||||
#define SRS_PERF_RTC_GSO_MAX 64
|
||||
|
||||
// For RTC, the max count of RTP packets we process in one loop.
|
||||
#define SRS_PERF_RTC_RTP_PACKETS 1024
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -67,11 +67,6 @@ SrsBuffer::~SrsBuffer()
|
|||
{
|
||||
}
|
||||
|
||||
char* SrsBuffer::data()
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int SrsBuffer::size()
|
||||
{
|
||||
return nb_bytes;
|
||||
|
|
|
@ -113,7 +113,8 @@ public:
|
|||
* get data of stream, set by initialize.
|
||||
* current bytes = data() + pos()
|
||||
*/
|
||||
virtual char* data();
|
||||
inline char* data() { return bytes; }
|
||||
inline char* head() { return p; }
|
||||
/**
|
||||
* the total stream size, set by initialize.
|
||||
* left bytes = size() - pos().
|
||||
|
|
|
@ -422,7 +422,7 @@ public:
|
|||
};
|
||||
|
||||
// Error helpers, should use these functions to new or wrap an error.
|
||||
#define srs_success SrsCplxError::success()
|
||||
#define srs_success 0 // SrsCplxError::success()
|
||||
#define srs_error_new(ret, fmt, ...) SrsCplxError::create(__FUNCTION__, __FILE__, __LINE__, ret, fmt, ##__VA_ARGS__)
|
||||
#define srs_error_wrap(err, fmt, ...) SrsCplxError::wrap(__FUNCTION__, __FILE__, __LINE__, err, fmt, ##__VA_ARGS__)
|
||||
#define srs_error_copy(err) SrsCplxError::copy(err)
|
||||
|
|
|
@ -218,6 +218,7 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()
|
|||
|
||||
extra_payloads = NULL;
|
||||
nn_extra_payloads = 0;
|
||||
nn_max_extra_payloads = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -227,9 +228,10 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
|
|||
srs_memory_unwatch(payload);
|
||||
#endif
|
||||
srs_freepa(payload);
|
||||
srs_freepa(samples);
|
||||
|
||||
#ifdef SRS_AUTO_RTC
|
||||
srs_freepa(samples);
|
||||
|
||||
for (int i = 0; i < nn_extra_payloads; i++) {
|
||||
SrsSample* p = extra_payloads + i;
|
||||
srs_freep(p->bytes);
|
||||
|
|
|
@ -310,10 +310,14 @@ private:
|
|||
int nn_samples;
|
||||
// For RTC video, whether NALUs has IDR.
|
||||
bool has_idr;
|
||||
public:
|
||||
// For RTC audio, we may need to transcode AAC to opus,
|
||||
// so there must be an extra payloads, which is transformed from payload.
|
||||
SrsSample* extra_payloads;
|
||||
int nn_extra_payloads;
|
||||
// The max size payload in extras.
|
||||
// @remark For GSO to fast guess the best padding.
|
||||
int nn_max_extra_payloads;
|
||||
#endif
|
||||
public:
|
||||
SrsSharedPtrPayload();
|
||||
|
@ -363,6 +367,9 @@ public:
|
|||
void set_extra_payloads(SrsSample* payloads, int nn_payloads);
|
||||
int nn_extra_payloads() { return ptr->nn_extra_payloads; }
|
||||
SrsSample* extra_payloads() { return ptr->extra_payloads; }
|
||||
// The max extra payload size.
|
||||
void set_max_extra_payload(int v) { ptr->nn_max_extra_payloads = v; }
|
||||
int nn_max_extra_payloads() { return ptr->nn_max_extra_payloads; }
|
||||
// Whether samples has idr.
|
||||
bool has_idr() { return ptr->has_idr; }
|
||||
void set_has_idr(bool v) { ptr->has_idr = v; }
|
||||
|
|
|
@ -55,27 +55,15 @@ SrsRtpHeader::SrsRtpHeader()
|
|||
extension_length = 0;
|
||||
}
|
||||
|
||||
SrsRtpHeader::SrsRtpHeader(const SrsRtpHeader& rhs)
|
||||
void SrsRtpHeader::reset()
|
||||
{
|
||||
operator=(rhs);
|
||||
}
|
||||
|
||||
SrsRtpHeader& SrsRtpHeader::operator=(const SrsRtpHeader& rhs)
|
||||
{
|
||||
padding = rhs.padding;
|
||||
extension = rhs.extension;
|
||||
cc = rhs.cc;
|
||||
marker = rhs.marker;
|
||||
payload_type = rhs.payload_type;
|
||||
sequence = rhs.sequence;
|
||||
timestamp = rhs.timestamp;
|
||||
ssrc = rhs.ssrc;
|
||||
for (size_t i = 0; i < cc; ++i) {
|
||||
csrc[i] = rhs.csrc[i];
|
||||
}
|
||||
extension_length = rhs.extension_length;
|
||||
|
||||
return *this;
|
||||
// We only reset the optional fields, the required field such as ssrc
|
||||
// will always be set by user.
|
||||
padding = false;
|
||||
extension = false;
|
||||
cc = 0;
|
||||
marker = false;
|
||||
extension_length = 0;
|
||||
}
|
||||
|
||||
SrsRtpHeader::~SrsRtpHeader()
|
||||
|
@ -95,32 +83,63 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream)
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// Encode the RTP fix header, 12bytes.
|
||||
// @see https://tools.ietf.org/html/rfc1889#section-5.1
|
||||
char* op = stream->head();
|
||||
char* p = op;
|
||||
|
||||
// The version, padding, extension and cc, total 1 byte.
|
||||
uint8_t v = 0x80 | cc;
|
||||
if (padding) {
|
||||
v |= 0x40;
|
||||
v |= 0x20;
|
||||
}
|
||||
if (extension) {
|
||||
v |= 0x10;
|
||||
}
|
||||
stream->write_1bytes(v);
|
||||
*p++ = v;
|
||||
|
||||
// The marker and payload type, total 1 byte.
|
||||
v = payload_type;
|
||||
if (marker) {
|
||||
v |= kRtpMarker;
|
||||
}
|
||||
stream->write_1bytes(v);
|
||||
*p++ = v;
|
||||
|
||||
stream->write_2bytes(sequence);
|
||||
stream->write_4bytes(timestamp);
|
||||
stream->write_4bytes(ssrc);
|
||||
// The sequence number, 2 bytes.
|
||||
char* pp = (char*)&sequence;
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
|
||||
// The timestamp, 4 bytes.
|
||||
pp = (char*)×tamp;
|
||||
*p++ = pp[3];
|
||||
*p++ = pp[2];
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
|
||||
// The SSRC, 4 bytes.
|
||||
pp = (char*)&ssrc;
|
||||
*p++ = pp[3];
|
||||
*p++ = pp[2];
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
|
||||
// The CSRC list: 0 to 15 items, each is 4 bytes.
|
||||
for (size_t i = 0; i < cc; ++i) {
|
||||
stream->write_4bytes(csrc[i]);
|
||||
pp = (char*)&csrc[i];
|
||||
*p++ = pp[3];
|
||||
*p++ = pp[2];
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
}
|
||||
|
||||
// TODO: Write exteinsion field.
|
||||
if (extension) {
|
||||
}
|
||||
|
||||
// Consume the data.
|
||||
stream->skip(p - op);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -129,51 +148,77 @@ size_t SrsRtpHeader::header_size()
|
|||
return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0);
|
||||
}
|
||||
|
||||
void SrsRtpHeader::set_marker(bool marker)
|
||||
{
|
||||
this->marker = marker;
|
||||
}
|
||||
|
||||
void SrsRtpHeader::set_payload_type(uint8_t payload_type)
|
||||
{
|
||||
this->payload_type = payload_type;
|
||||
}
|
||||
|
||||
void SrsRtpHeader::set_sequence(uint16_t sequence)
|
||||
{
|
||||
this->sequence = sequence;
|
||||
}
|
||||
|
||||
void SrsRtpHeader::set_timestamp(int64_t timestamp)
|
||||
{
|
||||
this->timestamp = timestamp;
|
||||
}
|
||||
|
||||
void SrsRtpHeader::set_ssrc(uint32_t ssrc)
|
||||
{
|
||||
this->ssrc = ssrc;
|
||||
}
|
||||
|
||||
SrsRtpPacket2::SrsRtpPacket2()
|
||||
{
|
||||
payload = NULL;
|
||||
padding = 0;
|
||||
|
||||
cache_raw = new SrsRtpRawPayload();
|
||||
cache_fua = new SrsRtpFUAPayload2();
|
||||
cache_payload = 0;
|
||||
}
|
||||
|
||||
SrsRtpPacket2::~SrsRtpPacket2()
|
||||
{
|
||||
// We may use the cache as payload.
|
||||
if (payload == cache_raw || payload == cache_fua) {
|
||||
payload = NULL;
|
||||
}
|
||||
|
||||
srs_freep(payload);
|
||||
srs_freep(cache_raw);
|
||||
srs_freep(cache_fua);
|
||||
}
|
||||
|
||||
void SrsRtpPacket2::set_padding(int size)
|
||||
{
|
||||
rtp_header.set_padding(size > 0);
|
||||
if (cache_payload) {
|
||||
cache_payload += size - padding;
|
||||
}
|
||||
padding = size;
|
||||
}
|
||||
|
||||
void SrsRtpPacket2::add_padding(int size)
|
||||
{
|
||||
rtp_header.set_padding(padding + size > 0);
|
||||
if (cache_payload) {
|
||||
cache_payload += size;
|
||||
}
|
||||
padding += size;
|
||||
}
|
||||
|
||||
void SrsRtpPacket2::reset()
|
||||
{
|
||||
rtp_header.reset();
|
||||
padding = 0;
|
||||
cache_payload = 0;
|
||||
|
||||
// We may use the cache as payload.
|
||||
if (payload == cache_raw || payload == cache_fua) {
|
||||
payload = NULL;
|
||||
}
|
||||
srs_freep(payload);
|
||||
}
|
||||
|
||||
SrsRtpRawPayload* SrsRtpPacket2::reuse_raw()
|
||||
{
|
||||
payload = cache_raw;
|
||||
return cache_raw;
|
||||
}
|
||||
|
||||
SrsRtpFUAPayload2* SrsRtpPacket2::reuse_fua()
|
||||
{
|
||||
payload = cache_fua;
|
||||
return cache_fua;
|
||||
}
|
||||
|
||||
int SrsRtpPacket2::nb_bytes()
|
||||
{
|
||||
return rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding;
|
||||
if (!cache_payload) {
|
||||
cache_payload = rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding;
|
||||
}
|
||||
return cache_payload;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf)
|
||||
|
@ -188,11 +233,11 @@ srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf)
|
|||
return srs_error_wrap(err, "encode payload");
|
||||
}
|
||||
|
||||
if (padding) {
|
||||
if (padding > 0) {
|
||||
if (!buf->require(padding)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", padding);
|
||||
}
|
||||
memset(buf->data(), padding, padding);
|
||||
memset(buf->data() + buf->pos(), padding, padding);
|
||||
buf->skip(padding);
|
||||
}
|
||||
|
||||
|
@ -237,12 +282,13 @@ SrsRtpRawNALUs::SrsRtpRawNALUs()
|
|||
|
||||
SrsRtpRawNALUs::~SrsRtpRawNALUs()
|
||||
{
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
srs_freep(p);
|
||||
if (true) {
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
srs_freep(p);
|
||||
}
|
||||
}
|
||||
nalus.clear();
|
||||
}
|
||||
|
||||
void SrsRtpRawNALUs::push_back(SrsSample* sample)
|
||||
|
@ -270,19 +316,19 @@ uint8_t SrsRtpRawNALUs::skip_first_byte()
|
|||
return uint8_t(nalus[0]->bytes[0]);
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpRawNALUs::read_samples(vector<SrsSample*>& samples, int size)
|
||||
srs_error_t SrsRtpRawNALUs::read_samples(vector<SrsSample*>& samples, int packet_size)
|
||||
{
|
||||
if (cursor + size < 0 || cursor + size > nn_bytes) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "cursor=%d, max=%d, size=%d", cursor, nn_bytes, size);
|
||||
if (cursor + packet_size < 0 || cursor + packet_size > nn_bytes) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "cursor=%d, max=%d, size=%d", cursor, nn_bytes, packet_size);
|
||||
}
|
||||
|
||||
int pos = cursor;
|
||||
cursor += size;
|
||||
int left = size;
|
||||
cursor += packet_size;
|
||||
int left = packet_size;
|
||||
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end() && left > 0; ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; left > 0 && i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
|
||||
// Ignore previous consumed samples.
|
||||
if (pos && pos - p->size >= 0) {
|
||||
|
@ -295,9 +341,10 @@ srs_error_t SrsRtpRawNALUs::read_samples(vector<SrsSample*>& samples, int size)
|
|||
srs_assert(nn > 0);
|
||||
|
||||
SrsSample* sample = new SrsSample();
|
||||
samples.push_back(sample);
|
||||
|
||||
sample->bytes = p->bytes + pos;
|
||||
sample->size = nn;
|
||||
samples.push_back(sample);
|
||||
|
||||
left -= nn;
|
||||
pos = 0;
|
||||
|
@ -310,9 +357,9 @@ int SrsRtpRawNALUs::nb_bytes()
|
|||
{
|
||||
int size = 0;
|
||||
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
size += p->size;
|
||||
}
|
||||
|
||||
|
@ -321,9 +368,9 @@ int SrsRtpRawNALUs::nb_bytes()
|
|||
|
||||
srs_error_t SrsRtpRawNALUs::encode(SrsBuffer* buf)
|
||||
{
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
|
||||
if (!buf->require(p->size)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size);
|
||||
|
@ -342,21 +389,20 @@ SrsRtpSTAPPayload::SrsRtpSTAPPayload()
|
|||
|
||||
SrsRtpSTAPPayload::~SrsRtpSTAPPayload()
|
||||
{
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
srs_freep(p);
|
||||
}
|
||||
nalus.clear();
|
||||
}
|
||||
|
||||
int SrsRtpSTAPPayload::nb_bytes()
|
||||
{
|
||||
int size = 1;
|
||||
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
size += 2 + p->size;
|
||||
}
|
||||
|
||||
|
@ -376,9 +422,10 @@ srs_error_t SrsRtpSTAPPayload::encode(SrsBuffer* buf)
|
|||
buf->write_1bytes(v);
|
||||
|
||||
// NALUs.
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
|
||||
if (!buf->require(2 + p->size)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2 + p->size);
|
||||
}
|
||||
|
@ -398,21 +445,20 @@ SrsRtpFUAPayload::SrsRtpFUAPayload()
|
|||
|
||||
SrsRtpFUAPayload::~SrsRtpFUAPayload()
|
||||
{
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
srs_freep(p);
|
||||
}
|
||||
nalus.clear();
|
||||
}
|
||||
|
||||
int SrsRtpFUAPayload::nb_bytes()
|
||||
{
|
||||
int size = 2;
|
||||
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
size += p->size;
|
||||
}
|
||||
|
||||
|
@ -441,9 +487,10 @@ srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf)
|
|||
buf->write_1bytes(fu_header);
|
||||
|
||||
// FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8
|
||||
vector<SrsSample*>::iterator it;
|
||||
for (it = nalus.begin(); it != nalus.end(); ++it) {
|
||||
SrsSample* p = *it;
|
||||
int nn_nalus = (int)nalus.size();
|
||||
for (int i = 0; i < nn_nalus; i++) {
|
||||
SrsSample* p = nalus[i];
|
||||
|
||||
if (!buf->require(p->size)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", p->size);
|
||||
}
|
||||
|
@ -454,6 +501,57 @@ srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf)
|
|||
return srs_success;
|
||||
}
|
||||
|
||||
SrsRtpFUAPayload2::SrsRtpFUAPayload2()
|
||||
{
|
||||
start = end = false;
|
||||
nri = nalu_type = (SrsAvcNaluType)0;
|
||||
|
||||
payload = NULL;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
SrsRtpFUAPayload2::~SrsRtpFUAPayload2()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsRtpFUAPayload2::nb_bytes()
|
||||
{
|
||||
return 2 + size;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpFUAPayload2::encode(SrsBuffer* buf)
|
||||
{
|
||||
if (!buf->require(2 + size)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
|
||||
}
|
||||
|
||||
// Fast encoding.
|
||||
char* p = buf->head();
|
||||
|
||||
// FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8
|
||||
uint8_t fu_indicate = kFuA;
|
||||
fu_indicate |= (nri & (~kNalTypeMask));
|
||||
*p++ = fu_indicate;
|
||||
|
||||
// FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8
|
||||
uint8_t fu_header = nalu_type;
|
||||
if (start) {
|
||||
fu_header |= kStart;
|
||||
}
|
||||
if (end) {
|
||||
fu_header |= kEnd;
|
||||
}
|
||||
*p++ = fu_header;
|
||||
|
||||
// FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8
|
||||
memcpy(p, payload, size);
|
||||
|
||||
// Consume bytes.
|
||||
buf->skip(2 + size);
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
SrsRtpSharedPacket::SrsRtpSharedPacketPayload::SrsRtpSharedPacketPayload()
|
||||
{
|
||||
payload = NULL;
|
||||
|
|
|
@ -38,6 +38,8 @@ const uint8_t kRtpMarker = 0x80;
|
|||
const uint8_t kNalTypeMask = 0x1F;
|
||||
|
||||
class SrsBuffer;
|
||||
class SrsRtpRawPayload;
|
||||
class SrsRtpFUAPayload2;
|
||||
|
||||
class SrsRtpHeader
|
||||
{
|
||||
|
@ -48,7 +50,7 @@ private:
|
|||
bool marker;
|
||||
uint8_t payload_type;
|
||||
uint16_t sequence;
|
||||
int64_t timestamp;
|
||||
int32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t csrc[15];
|
||||
uint16_t extension_length;
|
||||
|
@ -56,25 +58,24 @@ private:
|
|||
public:
|
||||
SrsRtpHeader();
|
||||
virtual ~SrsRtpHeader();
|
||||
SrsRtpHeader(const SrsRtpHeader& rhs);
|
||||
SrsRtpHeader& operator=(const SrsRtpHeader& rhs);
|
||||
void reset();
|
||||
public:
|
||||
srs_error_t decode(SrsBuffer* stream);
|
||||
srs_error_t encode(SrsBuffer* stream);
|
||||
public:
|
||||
size_t header_size();
|
||||
public:
|
||||
void set_marker(bool marker);
|
||||
inline void set_marker(bool v) { marker = v; }
|
||||
bool get_marker() const { return marker; }
|
||||
void set_payload_type(uint8_t payload_type);
|
||||
inline void set_payload_type(uint8_t v) { payload_type = v; }
|
||||
uint8_t get_payload_type() const { return payload_type; }
|
||||
void set_sequence(uint16_t sequence);
|
||||
inline void set_sequence(uint16_t v) { sequence = v; }
|
||||
uint16_t get_sequence() const { return sequence; }
|
||||
void set_timestamp(int64_t timestamp);
|
||||
inline void set_timestamp(int64_t v) { timestamp = (uint32_t)v; }
|
||||
int64_t get_timestamp() const { return timestamp; }
|
||||
void set_ssrc(uint32_t ssrc);
|
||||
inline void set_ssrc(uint32_t v) { ssrc = v; }
|
||||
uint32_t get_ssrc() const { return ssrc; }
|
||||
void set_padding(bool v) { padding = v; }
|
||||
inline void set_padding(bool v) { padding = v; }
|
||||
};
|
||||
|
||||
class SrsRtpPacket2
|
||||
|
@ -83,12 +84,24 @@ public:
|
|||
SrsRtpHeader rtp_header;
|
||||
ISrsEncoder* payload;
|
||||
int padding;
|
||||
private:
|
||||
SrsRtpRawPayload* cache_raw;
|
||||
SrsRtpFUAPayload2* cache_fua;
|
||||
int cache_payload;
|
||||
public:
|
||||
SrsRtpPacket2();
|
||||
virtual ~SrsRtpPacket2();
|
||||
public:
|
||||
// Append size of bytes as padding.
|
||||
virtual void set_padding(int size);
|
||||
// Set the padding of RTP packet.
|
||||
void set_padding(int size);
|
||||
// Increase the padding of RTP packet.
|
||||
void add_padding(int size);
|
||||
// Reset RTP packet.
|
||||
void reset();
|
||||
// Reuse the cached raw message as payload.
|
||||
SrsRtpRawPayload* reuse_raw();
|
||||
// Reuse the cached fua message as payload.
|
||||
SrsRtpFUAPayload2* reuse_fua();
|
||||
// interface ISrsEncoder
|
||||
public:
|
||||
virtual int nb_bytes();
|
||||
|
@ -99,7 +112,8 @@ public:
|
|||
class SrsRtpRawPayload : public ISrsEncoder
|
||||
{
|
||||
public:
|
||||
// @remark We only refer to the memory, user must free it.
|
||||
// The RAW payload, directly point to the shared memory.
|
||||
// @remark We only refer to the memory, user must free its bytes.
|
||||
char* payload;
|
||||
int nn_payload;
|
||||
public:
|
||||
|
@ -115,6 +129,7 @@ public:
|
|||
class SrsRtpRawNALUs : public ISrsEncoder
|
||||
{
|
||||
private:
|
||||
// We will manage the samples, but the sample itself point to the shared memory.
|
||||
std::vector<SrsSample*> nalus;
|
||||
int nn_bytes;
|
||||
int cursor;
|
||||
|
@ -125,7 +140,8 @@ public:
|
|||
void push_back(SrsSample* sample);
|
||||
public:
|
||||
uint8_t skip_first_byte();
|
||||
srs_error_t read_samples(std::vector<SrsSample*>& samples, int size);
|
||||
// We will manage the returned samples, if user want to manage it, please copy it.
|
||||
srs_error_t read_samples(std::vector<SrsSample*>& samples, int packet_size);
|
||||
// interface ISrsEncoder
|
||||
public:
|
||||
virtual int nb_bytes();
|
||||
|
@ -138,7 +154,7 @@ class SrsRtpSTAPPayload : public ISrsEncoder
|
|||
public:
|
||||
// The NRI in NALU type.
|
||||
SrsAvcNaluType nri;
|
||||
// The NALU samples.
|
||||
// The NALU samples, we will manage the samples.
|
||||
// @remark We only refer to the memory, user must free its bytes.
|
||||
std::vector<SrsSample*> nalus;
|
||||
public:
|
||||
|
@ -151,6 +167,7 @@ public:
|
|||
};
|
||||
|
||||
// FU-A, for one NALU with multiple fragments.
|
||||
// With more than one payload.
|
||||
class SrsRtpFUAPayload : public ISrsEncoder
|
||||
{
|
||||
public:
|
||||
|
@ -160,7 +177,7 @@ public:
|
|||
bool start;
|
||||
bool end;
|
||||
SrsAvcNaluType nalu_type;
|
||||
// The NALU samples.
|
||||
// The NALU samples, we manage the samples.
|
||||
// @remark We only refer to the memory, user must free its bytes.
|
||||
std::vector<SrsSample*> nalus;
|
||||
public:
|
||||
|
@ -172,6 +189,29 @@ public:
|
|||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
};
|
||||
|
||||
// FU-A, for one NALU with multiple fragments.
|
||||
// With only one payload.
|
||||
class SrsRtpFUAPayload2 : public ISrsEncoder
|
||||
{
|
||||
public:
|
||||
// The NRI in NALU type.
|
||||
SrsAvcNaluType nri;
|
||||
// The FUA header.
|
||||
bool start;
|
||||
bool end;
|
||||
SrsAvcNaluType nalu_type;
|
||||
// The payload and size,
|
||||
char* payload;
|
||||
int size;
|
||||
public:
|
||||
SrsRtpFUAPayload2();
|
||||
virtual ~SrsRtpFUAPayload2();
|
||||
// interface ISrsEncoder
|
||||
public:
|
||||
virtual int nb_bytes();
|
||||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
};
|
||||
|
||||
class SrsRtpSharedPacket
|
||||
{
|
||||
private:
|
||||
|
|
|
@ -436,6 +436,8 @@ int srs_sendmmsg(srs_netfd_t stfd, struct mmsghdr *msgvec, unsigned int vlen, in
|
|||
}
|
||||
msgvec->msg_len = r0;
|
||||
#else
|
||||
msgvec->msg_len = 0;
|
||||
|
||||
int tolen = (int)msgvec->msg_hdr.msg_namelen;
|
||||
const struct sockaddr* to = (const struct sockaddr*)msgvec->msg_hdr.msg_name;
|
||||
for (int i = 0; i < (int)msgvec->msg_hdr.msg_iovlen; i++) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue