1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-13 11:51:57 +00:00

Merge branch 'feature/rtc' into develop

This commit is contained in:
winlin 2020-04-19 13:17:53 +08:00
commit 65b5081c7d
51 changed files with 3396 additions and 1076 deletions

View file

@ -149,7 +149,6 @@ For previous versions, please read:
- [ ] Support publishing stream by WebRTC, [#307][bug #307].
- [ ] Support change user to run SRS, [#1111][bug #1111].
- [ ] Support HLS variant, [#463][bug #463].
- [ ] Support playing stream by WebRTC.
> Remark: About the milestone and product plan, please read ([CN][v1_CN_Product], [EN][v1_EN_Product]) wiki.
@ -158,6 +157,7 @@ For previous versions, please read:
## V4 changes
* v4.0, 2020-04-14, For [#307][bug #307], support sendmmsg, GSO and reuseport. 4.0.23
* v4.0, 2020-04-05, For [#307][bug #307], SRTP ASM only works with openssl-1.0, auto detect it. 4.0.22
* v4.0, 2020-04-04, Merge RTC and GB28181, with bugs fixed. 4.0.21
* v4.0, 2020-04-04, For [#307][bug #307], refine RTC latency from 600ms to 200ms. 4.0.20

View file

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

View file

@ -171,6 +171,12 @@ else
srs_undefine_macro "SRS_AUTO_HAS_SENDMMSG" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_DEBUG = YES ]; then
srs_define_macro "SRS_AUTO_DEBUG" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_DEBUG" $SRS_AUTO_HEADERS_H
fi
# prefix
echo "" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H

View file

@ -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
@ -647,10 +643,11 @@ if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then
--disable-programs --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \
--disable-avdevice --disable-avformat --disable-swscale --disable-postproc --disable-avfilter --disable-network \
--disable-dct --disable-dwt --disable-error-resilience --disable-lsp --disable-lzo --disable-faan --disable-pixelutils \
--disable-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-appkit --disable-coreimage \
--disable-avfoundation --disable-securetransport --disable-iconv --disable-lzma --disable-sdl2 --disable-everything \
--enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm --enable-decoder=libopus --enable-encoder=aac \
--enable-encoder=opus --enable-encoder=libopus --enable-libopus &&
--disable-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-cuda-llvm --disable-cuvid \
--disable-d3d11va --disable-dxva2 --disable-ffnvcodec --disable-nvdec --disable-nvenc --disable-v4l2-m2m --disable-vaapi \
--disable-vdpau --disable-appkit --disable-coreimage --disable-avfoundation --disable-securetransport --disable-iconv \
--disable-lzma --disable-sdl2 --disable-everything --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm \
--enable-decoder=libopus --enable-encoder=aac --enable-encoder=opus --enable-encoder=libopus --enable-libopus &&
make ${SRS_JOBS} && make install &&
cd .. && rm -rf ffmpeg && ln -sf ffmpeg-4.2-fit/${SRS_PLATFORM}/_release ffmpeg
)

View file

@ -122,6 +122,7 @@ SRS_NASM=YES
SRS_SRTP_ASM=YES
SRS_SENDMMSG=YES
SRS_HAS_SENDMMSG=YES
SRS_DEBUG=NO
#####################################################################################
# menu
@ -162,6 +163,7 @@ Features:
--prefix=<path> The absolute installation path for srs. Default: $SRS_PREFIX
--static Whether add '-static' to link options.
--gcov Whether enable the GCOV compiler options.
--debug Whether enable the debug code, may hurt performance.
--jobs[=N] Allow N jobs at once; infinite jobs with no arg.
Used for make in the configure, for example, to make ffmpeg.
--log-verbose Whether enable the log verbose level. default: no.
@ -293,6 +295,7 @@ function parse_user_option() {
--log-info) SRS_LOG_INFO=YES ;;
--log-trace) SRS_LOG_TRACE=YES ;;
--gcov) SRS_GCOV=YES ;;
--debug) SRS_DEBUG=YES ;;
--arm) SRS_CROSS_BUILD=YES ;;
--mips) SRS_CROSS_BUILD=YES ;;
@ -566,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
@ -623,6 +627,7 @@ function regenerate_options() {
if [ $SRS_LOG_INFO = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --log-info"; fi
if [ $SRS_LOG_TRACE = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --log-trace"; fi
if [ $SRS_GCOV = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gcov"; fi
if [ $SRS_DEBUG = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --debug"; fi
if [[ $SRS_EXTRA_FLAGS != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --extra-flags=\\\"$SRS_EXTRA_FLAGS\\\""; fi
if [[ $SRS_BUILD_TAG != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --build-tag=\\\"$SRS_BUILD_TAG\\\""; fi
if [[ $SRS_TOOL_CC != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cc=$SRS_TOOL_CC"; fi

View file

@ -430,6 +430,34 @@ rtc_server {
# @remark Should always turn it on, or Chrome will fail.
# default: on
encrypt on;
# We listen multiple times at the same port, by REUSEPORT, to increase the UDP queue.
# Note that you can set to 1 and increase the system UDP buffer size by net.core.rmem_max
# and net.core.rmem_default or just increase this to get larger UDP recv and send buffer.
# default: 4
reuseport 4;
# Whether merge multiple NALUs into one.
# @see https://github.com/ossrs/srs/issues/307#issuecomment-612806318
# default: on
merge_nalus on;
# Whether enable GSO to send out RTP packets.
# @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 {
@ -456,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;
}
}
@ -688,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
@ -748,6 +788,7 @@ vhost mrw.srs.com {
# @see play.srs.com
play {
mw_latency 350;
mw_msgs 8;
}
# @see publish.srs.com
@ -767,6 +808,7 @@ vhost min.delay.com {
# @see play.srs.com
play {
mw_latency 100;
mw_msgs 4;
gop_cache off;
queue_length 10;
}
@ -795,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;

12
trunk/configure vendored
View file

@ -444,7 +444,7 @@ mv ${SRS_WORKDIR}/${SRS_MAKEFILE} ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk
# generate phony header
cat << END > ${SRS_WORKDIR}/${SRS_MAKEFILE}
.PHONY: default _default install install-api help clean destroy server srs_ingest_hls librtmp utest _prepare_dir $__mphonys
.PHONY: clean_srs clean_modules clean_openssl clean_nginx clean_cherrypy clean_srtp2 clean_opus
.PHONY: clean_srs clean_modules clean_openssl clean_nginx clean_cherrypy clean_srtp2 clean_opus clean_ffmpeg clean_st
.PHONY: st ffmpeg
# install prefix.
@ -481,6 +481,8 @@ help:
@echo " clean_openssl Remove the openssl cache."
@echo " clean_srtp2 Remove the libsrtp2 cache."
@echo " clean_opus Remove the opus cache."
@echo " clean_ffmpeg Remove the FFmpeg cache."
@echo " clean_st Remove the ST cache."
@echo "For example:"
@echo " make"
@echo " make help"
@ -519,6 +521,14 @@ clean_opus:
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf opus-1.3.1)
@echo "Please rebuild opus by: ./configure"
clean_ffmpeg:
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf ffmpeg-4.2-fit)
@echo "Please rebuild FFmpeg by: ./configure"
clean_st:
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf st-srs)
@echo "Please rebuild ST by: ./configure"
clean_nginx:
(cd ${SRS_OBJS_DIR} && rm -rf nginx)

View file

@ -207,6 +207,14 @@ function build_default_hls_url() {
}
function build_default_rtc_url(query) {
// Use target to overwrite server, vhost and eip.
console.log('?target=x.x.x.x to overwrite server, vhost and eip.');
if (query.target) {
query.server = query.vhost = query.eip = query.target;
query.user_query.eip = query.target;
delete query.target;
}
var server = (!query.server)? window.location.hostname:query.server;
var vhost = (!query.vhost)? window.location.hostname:query.vhost;
var app = (!query.app)? "live":query.app;

97
trunk/scripts/perf_gso.py Executable file
View file

@ -0,0 +1,97 @@
#!/usr/bin/python
'''
The MIT License (MIT)
Copyright (c) 2013-2016 SRS(ossrs)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''
import urllib, sys, json
url = "http://localhost:1985/api/v1/perf"
if len(sys.argv) < 2:
print "Usage: %s <url>"%(sys.argv[0])
print "For example:"
print " %s http://localhost:1985/api/v1/perf"%(sys.argv[0])
sys.exit(-1)
url = sys.argv[1]
print "Open %s"%(url)
f = urllib.urlopen(url)
s = f.read()
f.close()
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"),
p = obj['data']['avframes']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),
print ""
print("RTC--Frames"),
p = obj['data']['rtc']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),
print ""
print("RTP-Packets"),
p = obj['data']['rtp']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),
print ""
print("GSO-Packets"),
p = obj['data']['gso']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),

View file

@ -388,16 +388,13 @@ srs_error_t SrsAudioRecode::initialize()
srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int &n)
{
srs_error_t err = srs_success;
static char decode_buffer[kPacketBufMax];
static char resample_buffer[kFrameBufMax];
static char encode_buffer[kPacketBufMax];
if (!dec_) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "dec_ nullptr");
}
int decode_len = kPacketBufMax;
static char decode_buffer[kPacketBufMax];
if ((err = dec_->decode(pkt, decode_buffer, decode_len)) != srs_success) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error");
}
@ -412,15 +409,18 @@ srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int
if (!resample_) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "SrsAudioResample failed");
}
resample_->initialize();
if ((err = resample_->initialize()) != srs_success) {
return srs_error_wrap(err, "init resample");
}
}
SrsSample pcm;
pcm.bytes = decode_buffer;
pcm.size = decode_len;
int resample_len = kFrameBufMax;
static char resample_buffer[kFrameBufMax];
if ((err = resample_->resample(&pcm, resample_buffer, resample_len)) != srs_success) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error");
return srs_error_new(ERROR_RTC_RTP_MUXER, "resample error");
}
n = 0;
@ -445,8 +445,9 @@ srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int
int encode_len;
pcm.bytes = (char *)data_;
pcm.size = size_;
static char encode_buffer[kPacketBufMax];
if ((err = enc_->encode(&pcm, encode_buffer, encode_len)) != srs_success) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error");
return srs_error_new(ERROR_RTC_RTP_MUXER, "encode error");
}
memcpy(buf[n], encode_buffer, encode_len);

View file

@ -33,6 +33,10 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef __linux__
#include <linux/version.h>
#include <sys/utsname.h>
#endif
#include <vector>
#include <algorithm>
@ -1540,6 +1544,11 @@ srs_error_t SrsConfig::reload_conf(SrsConfig* conf)
if ((err = reload_http_stream(old_root)) != srs_success) {
return srs_error_wrap(err, "http steram");;
}
// Merge config: rtc_server
if ((err = reload_rtc_server(old_root)) != srs_success) {
return srs_error_wrap(err, "http steram");;
}
// TODO: FIXME: support reload stream_caster.
@ -1697,6 +1706,40 @@ srs_error_t SrsConfig::reload_http_stream(SrsConfDirective* old_root)
return err;
}
srs_error_t SrsConfig::reload_rtc_server(SrsConfDirective* old_root)
{
srs_error_t err = srs_success;
// merge config.
std::vector<ISrsReloadHandler*>::iterator it;
// state graph
// old_rtc_server new_rtc_server
// ENABLED => ENABLED (modified)
SrsConfDirective* new_rtc_server = root->get("rtc_server");
SrsConfDirective* old_rtc_server = old_root->get("rtc_server");
// TODO: FIXME: Support disable or enable reloading.
// ENABLED => ENABLED (modified)
if (get_rtc_server_enabled(old_rtc_server) && get_rtc_server_enabled(new_rtc_server)
&& !srs_directive_equals(old_rtc_server, new_rtc_server)
) {
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
ISrsReloadHandler* subscribe = *it;
if ((err = subscribe->on_reload_rtc_server()) != srs_success) {
return srs_error_wrap(err, "rtc server enabled");
}
}
srs_trace("reload rtc server success.");
return err;
}
srs_trace("reload rtc server success, nothing changed.");
return err;
}
srs_error_t SrsConfig::reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost)
{
srs_error_t err = srs_success;
@ -3575,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 != "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());
}
}
@ -3741,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());
}
}
@ -4706,6 +4751,148 @@ int SrsConfig::get_rtc_server_sendmmsg()
#endif
}
int SrsConfig::get_rtc_server_reuseport()
{
int v = get_rtc_server_reuseport2();
#if !defined(SO_REUSEPORT)
srs_warn("REUSEPORT not supported, reset %d to %d", reuseport, DEFAULT);
v = 1
#endif
return v;
}
int SrsConfig::get_rtc_server_reuseport2()
{
static int DEFAULT = 4;
SrsConfDirective* conf = root->get("rtc_server");
if (!conf) {
return DEFAULT;
}
conf = conf->get("reuseport");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return ::atoi(conf->arg0().c_str());
}
bool SrsConfig::get_rtc_server_merge_nalus()
{
static int DEFAULT = true;
SrsConfDirective* conf = root->get("rtc_server");
if (!conf) {
return DEFAULT;
}
conf = conf->get("merge_nalus");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
bool SrsConfig::get_rtc_server_gso()
{
bool v = get_rtc_server_gso2();
bool gso_disabled = false;
#if !defined(__linux__)
gso_disabled = true;
if (v) {
srs_warn("GSO is disabled, for Linux 4.18+ only");
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0)
if (v) {
utsname un = {0};
int r0 = uname(&un);
if (r0 || strcmp(un.release, "4.18.0") < 0) {
gso_disabled = true;
srs_warn("GSO is disabled, for Linux 4.18+ only, r0=%d, kernel=%s", r0, un.release);
}
}
#endif
if (v && gso_disabled) {
v = false;
}
return v;
}
bool SrsConfig::get_rtc_server_gso2()
{
static int DEFAULT = true;
SrsConfDirective* conf = root->get("rtc_server");
if (!conf) {
return DEFAULT;
}
conf = conf->get("gso");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
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);
@ -5233,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)

View file

@ -333,6 +333,8 @@ private:
// Reload the http_stream section of config.
// TODO: FIXME: rename to http_server.
virtual srs_error_t reload_http_stream(SrsConfDirective* old_root);
// Reload the rtc_server section of config.
virtual srs_error_t reload_rtc_server(SrsConfDirective* old_root);
// Reload the transcode section of vhost of config.
virtual srs_error_t reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost);
// Reload the ingest section of vhost of config.
@ -525,7 +527,20 @@ public:
virtual bool get_rtc_server_ecdsa();
virtual int get_rtc_server_sendmmsg();
virtual bool get_rtc_server_encrypt();
virtual int get_rtc_server_reuseport();
private:
virtual int get_rtc_server_reuseport2();
public:
virtual bool get_rtc_server_merge_nalus();
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);
bool get_rtc_bframe_discard(std::string vhost);
@ -615,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.

View file

@ -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,20 +1623,56 @@ 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=writev|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 (target.empty() || target == "writev") {
if (!reset.empty()) {
stat->reset_perf();
return srs_api_response(w, r, obj->dumps());
}
if (target.empty() || target == "avframes") {
SrsJsonObject* p = SrsJsonAny::object();
data->set("writev", p);
if ((err = stat->dumps_perf_writev(p)) != srs_success) {
data->set("avframes", p);
if ((err = stat->dumps_perf_msgs(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 == "rtc") {
SrsJsonObject* p = SrsJsonAny::object();
data->set("rtc", p);
if ((err = stat->dumps_perf_rtc_packets(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 == "rtp") {
SrsJsonObject* p = SrsJsonAny::object();
data->set("rtp", p);
if ((err = stat->dumps_perf_rtp_packets(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 == "gso") {
SrsJsonObject* p = SrsJsonAny::object();
data->set("gso", p);
if ((err = stat->dumps_perf_gso(p)) != srs_success) {
int code = srs_error_code(err); srs_error_reset(err);
return srs_api_response_code(w, r, code);
}
@ -1643,6 +1687,33 @@ srs_error_t SrsGoApiPerf::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
}
}
if (target.empty() || target == "writev_iovs") {
SrsJsonObject* p = SrsJsonAny::object();
data->set("writev_iovs", p);
if ((err = stat->dumps_perf_writev_iovs(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 == "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());
}

View file

@ -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);
@ -680,6 +681,8 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
err = streaming_send_messages(enc, msgs.msgs, count);
}
// TODO: FIXME: Update the stat.
// free the messages.
for (int i = 0; i < count; i++) {
SrsSharedPtrMessage* msg = msgs.msgs[i];

View file

@ -40,6 +40,7 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_app_server.hpp>
#include <srs_app_utility.hpp>
#include <srs_kernel_utility.hpp>
// set the max packet size.
#define SRS_UDP_MAX_PACKET_SIZE 65535
@ -235,12 +236,21 @@ srs_error_t SrsTcpListener::cycle()
return err;
}
SrsUdpMuxSocket::SrsUdpMuxSocket(srs_netfd_t fd)
ISrsUdpSender::ISrsUdpSender()
{
}
ISrsUdpSender::~ISrsUdpSender()
{
}
SrsUdpMuxSocket::SrsUdpMuxSocket(ISrsUdpSender* h, srs_netfd_t fd)
{
nb_buf = SRS_UDP_MAX_PACKET_SIZE;
buf = new char[nb_buf];
nread = 0;
handler = h;
lfd = fd;
fromlen = 0;
@ -253,7 +263,7 @@ SrsUdpMuxSocket::~SrsUdpMuxSocket()
SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly()
{
SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(lfd);
SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(handler, lfd);
// Don't copy buffer
srs_freepa(sendonly->buf);
@ -339,16 +349,18 @@ std::string SrsUdpMuxSocket::get_peer_id()
return string(id_buf, len);
}
SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p)
SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, ISrsUdpSender* s, std::string i, int p)
{
handler = h;
sender = s;
ip = i;
port = p;
lfd = NULL;
nb_buf = SRS_UDP_MAX_PACKET_SIZE;
buf = new char[nb_buf];
trd = new SrsDummyCoroutine();
}
@ -390,60 +402,108 @@ srs_error_t SrsUdpMuxListener::listen()
void SrsUdpMuxListener::set_socket_buffer()
{
int sndbuf_size = 0;
socklen_t opt_len = sizeof(sndbuf_size);
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len);
srs_trace("default udp remux socket sndbuf=%d", sndbuf_size);
int default_sndbuf = 0;
// TODO: FIXME: Config it.
int expect_sndbuf = 1024*1024*10; // 10M
int actual_sndbuf = expect_sndbuf;
int r0_sndbuf = 0;
if (true) {
socklen_t opt_len = sizeof(default_sndbuf);
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&default_sndbuf, &opt_len);
sndbuf_size = 1024*1024*10; // 10M
if (setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, sizeof(sndbuf_size)) < 0) {
srs_warn("set sock opt SO_SNDBUFFORCE failed");
if ((r0_sndbuf = setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, sizeof(actual_sndbuf))) < 0) {
srs_warn("set SO_SNDBUF failed, expect=%d, r0=%d", expect_sndbuf, r0_sndbuf);
}
opt_len = sizeof(actual_sndbuf);
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, &opt_len);
}
opt_len = sizeof(sndbuf_size);
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len);
srs_trace("udp remux socket sndbuf=%d", sndbuf_size);
int default_rcvbuf = 0;
// TODO: FIXME: Config it.
int expect_rcvbuf = 1024*1024*10; // 10M
int actual_rcvbuf = expect_rcvbuf;
int r0_rcvbuf = 0;
if (true) {
socklen_t opt_len = sizeof(default_rcvbuf);
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&default_rcvbuf, &opt_len);
int rcvbuf_size = 0;
opt_len = sizeof(rcvbuf_size);
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len);
srs_trace("default udp remux socket rcvbuf=%d", rcvbuf_size);
if ((r0_rcvbuf = setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, sizeof(actual_rcvbuf))) < 0) {
srs_warn("set SO_RCVBUF failed, expect=%d, r0=%d", expect_rcvbuf, r0_rcvbuf);
}
rcvbuf_size = 1024*1024*10; // 10M
if (setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
srs_warn("set sock opt SO_RCVBUFFORCE failed");
opt_len = sizeof(actual_rcvbuf);
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, &opt_len);
}
opt_len = sizeof(rcvbuf_size);
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len);
srs_trace("udp remux socket rcvbuf=%d", rcvbuf_size);
srs_trace("UDP #%d LISTEN at %s:%d, SO_SNDBUF(default=%d, expect=%d, actual=%d, r0=%d), SO_RCVBUF(default=%d, expect=%d, actual=%d, r0=%d)",
srs_netfd_fileno(lfd), ip.c_str(), port, default_sndbuf, expect_sndbuf, actual_sndbuf, r0_sndbuf, default_rcvbuf, expect_rcvbuf, actual_rcvbuf, r0_rcvbuf);
}
srs_error_t SrsUdpMuxListener::cycle()
{
srs_error_t err = srs_success;
SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_recv(srs_netfd_fileno(lfd));
SrsAutoFree(SrsPithyPrint, pprint);
uint64_t nn_msgs = 0;
uint64_t nn_msgs_stage = 0;
uint64_t nn_msgs_last = 0;
uint64_t nn_loop = 0;
srs_utime_t time_last = srs_get_system_time();
while (true) {
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "udp listener");
}
}
SrsUdpMuxSocket udp_mux_skt(lfd);
nn_loop++;
int nread = udp_mux_skt.recvfrom(SRS_UTIME_NO_TIMEOUT);
SrsUdpMuxSocket skt(sender, lfd);
int nread = skt.recvfrom(SRS_UTIME_NO_TIMEOUT);
if (nread <= 0) {
if (nread < 0) {
srs_warn("udp recv error");
}
// remux udp never return
continue;
}
}
nn_msgs++;
nn_msgs_stage++;
if ((err = handler->on_udp_packet(&udp_mux_skt)) != srs_success) {
if ((err = handler->on_udp_packet(&skt)) != srs_success) {
// remux udp never return
srs_warn("udp packet handler error:%s", srs_error_desc(err).c_str());
continue;
}
srs_error_reset(err);
}
pprint->elapse();
if (pprint->can_print()) {
int pps_average = 0; int pps_last = 0;
if (true) {
if (srs_get_system_time() > srs_get_system_startup_time()) {
pps_average = (int)(nn_msgs * SRS_UTIME_SECONDS / (srs_get_system_time() - srs_get_system_startup_time()));
}
if (srs_get_system_time() > time_last) {
pps_last = (int)((nn_msgs - nn_msgs_last) * SRS_UTIME_SECONDS / (srs_get_system_time() - time_last));
}
}
string pps_unit = "";
if (pps_last > 10000 || pps_average > 10000) {
pps_unit = "(w)"; pps_last /= 10000; pps_average /= 10000;
} else if (pps_last > 1000 || pps_average > 1000) {
pps_unit = "(k)"; pps_last /= 10000; pps_average /= 10000;
}
srs_trace("<- RTC RECV #%d, udp %" PRId64 ", pps %d/%d%s, schedule %" PRId64,
srs_netfd_fileno(lfd), nn_msgs_stage, pps_average, pps_last, pps_unit.c_str(), nn_loop);
nn_msgs_last = nn_msgs; time_last = srs_get_system_time();
nn_loop = 0; nn_msgs_stage = 0;
}
if (SrsUdpPacketRecvCycleInterval > 0) {
srs_usleep(SrsUdpPacketRecvCycleInterval);

View file

@ -69,7 +69,7 @@ public:
virtual ~ISrsUdpMuxHandler();
public:
virtual srs_error_t on_stfd_change(srs_netfd_t fd);
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) = 0;
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt) = 0;
};
// The tcp connection handler.
@ -131,9 +131,27 @@ public:
virtual srs_error_t cycle();
};
class ISrsUdpSender
{
public:
ISrsUdpSender();
virtual ~ISrsUdpSender();
public:
// Fetch a mmsghdr from sender's cache.
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
{
private:
ISrsUdpSender* handler;
char* buf;
int nb_buf;
int nread;
@ -143,7 +161,7 @@ private:
std::string peer_ip;
int peer_port;
public:
SrsUdpMuxSocket(srs_netfd_t fd);
SrsUdpMuxSocket(ISrsUdpSender* h, srs_netfd_t fd);
virtual ~SrsUdpMuxSocket();
int recvfrom(srs_utime_t timeout);
@ -160,6 +178,7 @@ public:
std::string get_peer_id();
public:
SrsUdpMuxSocket* copy_sendonly();
ISrsUdpSender* sender() { return handler; };
private:
// Don't allow copy, user copy_sendonly instead
SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs);
@ -170,6 +189,7 @@ class SrsUdpMuxListener : public ISrsCoroutineHandler
{
protected:
srs_netfd_t lfd;
ISrsUdpSender* sender;
SrsCoroutine* trd;
protected:
char* buf;
@ -179,7 +199,7 @@ protected:
std::string ip;
int port;
public:
SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p);
SrsUdpMuxListener(ISrsUdpMuxHandler* h, ISrsUdpSender* s, std::string i, int p);
virtual ~SrsUdpMuxListener();
public:
virtual int fd();

View file

@ -112,6 +112,10 @@ SrsPithyPrint::SrsPithyPrint(int _stage_id)
#define SRS_CONSTS_STAGE_EXEC 11
// for the rtc play
#define SRS_CONSTS_STAGE_RTC_PLAY 12
// for the rtc send
#define SRS_CONSTS_STAGE_RTC_SEND 13
// for the rtc recv
#define SRS_CONSTS_STAGE_RTC_RECV 14
SrsPithyPrint* SrsPithyPrint::create_rtmp_play()
{
@ -173,6 +177,16 @@ SrsPithyPrint* SrsPithyPrint::create_rtc_play()
return new SrsPithyPrint(SRS_CONSTS_STAGE_RTC_PLAY);
}
SrsPithyPrint* SrsPithyPrint::create_rtc_send(int fd)
{
return new SrsPithyPrint(fd<<16 | SRS_CONSTS_STAGE_RTC_SEND);
}
SrsPithyPrint* SrsPithyPrint::create_rtc_recv(int fd)
{
return new SrsPithyPrint(fd<<16 | SRS_CONSTS_STAGE_RTC_RECV);
}
SrsPithyPrint::~SrsPithyPrint()
{
leave_stage();

View file

@ -88,6 +88,9 @@ public:
static SrsPithyPrint* create_http_stream();
static SrsPithyPrint* create_http_stream_cache();
static SrsPithyPrint* create_rtc_play();
// For RTC sender and receiver, we create printer for each fd.
static SrsPithyPrint* create_rtc_send(int fd);
static SrsPithyPrint* create_rtc_recv(int fd);
virtual ~SrsPithyPrint();
private:
// Enter the specified stage, return the client id.

View file

@ -115,6 +115,11 @@ srs_error_t ISrsReloadHandler::on_reload_http_stream_crossdomain()
return srs_success;
}
srs_error_t ISrsReloadHandler::on_reload_rtc_server()
{
return srs_success;
}
srs_error_t ISrsReloadHandler::on_reload_vhost_http_updated()
{
return srs_success;

View file

@ -55,6 +55,7 @@ public:
virtual srs_error_t on_reload_http_stream_disabled();
virtual srs_error_t on_reload_http_stream_updated();
virtual srs_error_t on_reload_http_stream_crossdomain();
virtual srs_error_t on_reload_rtc_server();
public:
// TODO: FIXME: should rename to http_static
virtual srs_error_t on_reload_vhost_http_updated();

View file

@ -54,7 +54,7 @@ using namespace std;
#include <srs_app_audio_recode.hpp>
// TODO: Add this function into SrsRtpMux class.
srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer** stream_ptr)
srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFormat* format, char** pbuf, int* pnn_buf)
{
srs_error_t err = srs_success;
@ -62,37 +62,33 @@ srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFor
return err;
}
if (stream_ptr == NULL) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "adts");
}
if (format->audio->nb_samples != 1) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "adts");
}
int nb_buf = format->audio->samples[0].size + 7;
char* buf = new char[nb_buf];
SrsBuffer* stream = new SrsBuffer(buf, nb_buf);
SrsBuffer stream(buf, nb_buf);
// TODO: Add comment.
stream->write_1bytes(0xFF);
stream->write_1bytes(0xF9);
stream->write_1bytes(((format->acodec->aac_object - 1) << 6) | ((format->acodec->aac_sample_rate & 0x0F) << 2) | ((format->acodec->aac_channels & 0x04) >> 2));
stream->write_1bytes(((format->acodec->aac_channels & 0x03) << 6) | ((nb_buf >> 11) & 0x03));
stream->write_1bytes((nb_buf >> 3) & 0xFF);
stream->write_1bytes(((nb_buf & 0x07) << 5) | 0x1F);
stream->write_1bytes(0xFC);
stream.write_1bytes(0xFF);
stream.write_1bytes(0xF9);
stream.write_1bytes(((format->acodec->aac_object - 1) << 6) | ((format->acodec->aac_sample_rate & 0x0F) << 2) | ((format->acodec->aac_channels & 0x04) >> 2));
stream.write_1bytes(((format->acodec->aac_channels & 0x03) << 6) | ((nb_buf >> 11) & 0x03));
stream.write_1bytes((nb_buf >> 3) & 0xFF);
stream.write_1bytes(((nb_buf & 0x07) << 5) | 0x1F);
stream.write_1bytes(0xFC);
stream->write_bytes(format->audio->samples[0].bytes, format->audio->samples[0].size);
stream.write_bytes(format->audio->samples[0].bytes, format->audio->samples[0].size);
*stream_ptr = stream;
*pbuf = buf;
*pnn_buf = nb_buf;
return err;
}
SrsRtpH264Muxer::SrsRtpH264Muxer()
{
sequence = 0;
discard_bframe = false;
}
@ -100,269 +96,118 @@ SrsRtpH264Muxer::~SrsRtpH264Muxer()
{
}
srs_error_t SrsRtpH264Muxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format)
srs_error_t SrsRtpH264Muxer::filter(SrsSharedPtrMessage* shared_frame, SrsFormat* format)
{
srs_error_t err = srs_success;
if (format->is_avc_sequence_header()) {
sps.assign(format->vcodec->sequenceParameterSetNALUnit.data(), format->vcodec->sequenceParameterSetNALUnit.size());
pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size());
// only collect SPS/PPS.
// If IDR, we will insert SPS/PPS before IDR frame.
if (format->video && format->video->has_idr) {
shared_frame->set_has_idr(true);
}
// Update samples to shared frame.
for (int i = 0; i < format->video->nb_samples; ++i) {
SrsSample* sample = &format->video->samples[i];
// Because RTC does not support B-frame, so we will drop them.
// TODO: Drop B-frame in better way, which not cause picture corruption.
if (discard_bframe) {
if ((err = sample->parse_bframe()) != srs_success) {
return srs_error_wrap(err, "parse bframe");
}
if (sample->bframe) {
continue;
}
}
}
if (format->video->nb_samples <= 0) {
return err;
}
vector<SrsRtpSharedPacket*> rtp_packet_vec;
for (int i = 0; i < format->video->nb_samples; ++i) {
SrsSample sample = format->video->samples[i];
uint8_t header = sample.bytes[0];
uint8_t nal_type = header & kNalTypeMask;
// TODO: Use config to determine should check avc stream.
if (nal_type == SrsAvcNaluTypeNonIDR || nal_type == SrsAvcNaluTypeDataPartitionA || nal_type == SrsAvcNaluTypeIDR) {
SrsBuffer* stream = new SrsBuffer(sample.bytes, sample.size);
SrsAutoFree(SrsBuffer, stream);
// Skip nalu header.
stream->skip(1);
SrsBitBuffer bitstream(stream);
int32_t first_mb_in_slice = 0;
if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) {
return srs_error_wrap(err, "nalu read uev");
}
int32_t slice_type = 0;
if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type)) != srs_success) {
return srs_error_wrap(err, "nalu read uev");
}
srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type);
if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) {
if (discard_bframe) {
continue;
}
}
}
if (sample.size <= kRtpMaxPayloadSize) {
if ((err = packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) {
return srs_error_wrap(err, "packet single nalu");
}
} else {
if ((err = packet_fu_a(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) {
return srs_error_wrap(err, "packet fu-a");
}
}
}
if (! rtp_packet_vec.empty()) {
// At the end of the frame, set marker bit.
// One frame may have multi nals. Set the marker bit in the last nal end, no the end of the nal.
if ((err = rtp_packet_vec.back()->modify_rtp_header_marker(true)) != srs_success) {
return srs_error_wrap(err, "set marker");
}
}
shared_frame->set_rtp_packets(rtp_packet_vec);
return err;
}
srs_error_t SrsRtpH264Muxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector<SrsRtpSharedPacket*>& rtp_packet_vec)
{
srs_error_t err = srs_success;
char* p = sample->bytes + 1;
int nb_left = sample->size - 1;
uint8_t header = sample->bytes[0];
uint8_t nal_type = header & kNalTypeMask;
if (nal_type == SrsAvcNaluTypeIDR) {
if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) {
return srs_error_wrap(err, "packet stap-a");
}
}
int num_of_packet = (sample->size - 1 + kRtpMaxPayloadSize) / kRtpMaxPayloadSize;
for (int i = 0; i < num_of_packet; ++i) {
char buf[kRtpPacketSize];
SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize);
SrsAutoFree(SrsBuffer, stream);
int packet_size = min(nb_left, kRtpMaxPayloadSize);
// fu-indicate
uint8_t fu_indicate = kFuA;
fu_indicate |= (header & (~kNalTypeMask));
stream->write_1bytes(fu_indicate);
uint8_t fu_header = nal_type;
if (i == 0)
fu_header |= kStart;
if (i == num_of_packet - 1)
fu_header |= kEnd;
stream->write_1bytes(fu_header);
stream->write_bytes(p, packet_size);
p += packet_size;
nb_left -= packet_size;
srs_verbose("rtp fu-a nalu, size=%u, seq=%u, timestamp=%lu", sample->size, sequence, (shared_frame->timestamp * 90));
SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket();
if ((err = rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos())) != srs_success) {
return srs_error_wrap(err, "rtp packet encode");
}
rtp_packet_vec.push_back(rtp_shared_pkt);
}
return err;
}
srs_error_t SrsRtpH264Muxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector<SrsRtpSharedPacket*>& rtp_packet_vec)
{
srs_error_t err = srs_success;
uint8_t header = sample->bytes[0];
uint8_t nal_type = header & kNalTypeMask;
if (nal_type == SrsAvcNaluTypeIDR) {
if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) {
return srs_error_wrap(err, "packet stap-a");
}
}
srs_verbose("rtp single nalu, size=%u, seq=%u, timestamp=%lu", sample->size, sequence, (shared_frame->timestamp * 90));
SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket();
if ((err = rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, sample->bytes, sample->size)) != srs_success) {
return srs_error_wrap(err, "rtp packet encode");
}
rtp_packet_vec.push_back(rtp_shared_pkt);
return err;
}
srs_error_t SrsRtpH264Muxer::packet_stap_a(const string &sps, const string& pps, SrsSharedPtrMessage* shared_frame, vector<SrsRtpSharedPacket*>& rtp_packet_vec)
{
srs_error_t err = srs_success;
if (sps.empty() || pps.empty()) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "sps/pps empty");
}
uint8_t header = sps[0];
uint8_t nal_type = header & kNalTypeMask;
char buf[kRtpPacketSize];
SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize);
SrsAutoFree(SrsBuffer, stream);
// stap-a header
uint8_t stap_a_header = kStapA;
stap_a_header |= (nal_type & (~kNalTypeMask));
stream->write_1bytes(stap_a_header);
stream->write_2bytes(sps.size());
stream->write_bytes((char*)sps.data(), sps.size());
stream->write_2bytes(pps.size());
stream->write_bytes((char*)pps.data(), pps.size());
srs_verbose("rtp stap-a nalu, size=%u, seq=%u, timestamp=%lu", (sps.size() + pps.size()), sequence, (shared_frame->timestamp * 90));
SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket();
if ((err = rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos())) != srs_success) {
return srs_error_wrap(err, "rtp packet encode");
}
rtp_packet_vec.push_back(rtp_shared_pkt);
shared_frame->set_samples(format->video->samples, format->video->nb_samples);
return err;
}
SrsRtpOpusMuxer::SrsRtpOpusMuxer()
{
sequence = 0;
timestamp = 0;
transcode = NULL;
codec = NULL;
}
SrsRtpOpusMuxer::~SrsRtpOpusMuxer()
{
if (transcode) {
delete transcode;
transcode = NULL;
}
srs_freep(codec);
}
srs_error_t SrsRtpOpusMuxer::initialize()
{
srs_error_t err = srs_success;
transcode = new SrsAudioRecode(kChannel, kSamplerate);
if (!transcode) {
codec = new SrsAudioRecode(kChannel, kSamplerate);
if (!codec) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "SrsAacOpus init failed");
}
transcode->initialize();
if ((err = codec->initialize()) != srs_success) {
return srs_error_wrap(err, "init codec");
}
return err;
}
srs_error_t SrsRtpOpusMuxer::frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream)
// An AAC packet may be transcoded to many OPUS packets.
const int kMaxOpusPackets = 8;
// The max size for each OPUS packet.
const int kMaxOpusPacketSize = 4096;
srs_error_t SrsRtpOpusMuxer::transcode(SrsSharedPtrMessage* shared_audio, char* adts_audio, int nn_adts_audio)
{
srs_error_t err = srs_success;
vector<SrsRtpSharedPacket*> rtp_packet_vec;
// Opus packet cache.
static char* opus_payloads[kMaxOpusPackets];
char* data_ptr[kArrayLength];
static char data_array[kArrayLength][kArrayBuffer];
int elen[kArrayLength], number = 0;
static bool initialized = false;
if (!initialized) {
initialized = true;
data_ptr[0] = &data_array[0][0];
for (int i = 1; i < kArrayLength; i++) {
data_ptr[i] = data_array[i];
static char opus_packets_cache[kMaxOpusPackets][kMaxOpusPacketSize];
opus_payloads[0] = &opus_packets_cache[0][0];
for (int i = 1; i < kMaxOpusPackets; i++) {
opus_payloads[i] = opus_packets_cache[i];
}
}
SrsSample pkt;
pkt.bytes = stream->data();
pkt.size = stream->pos();
// Transcode an aac packet to many opus packets.
SrsSample aac;
aac.bytes = adts_audio;
aac.size = nn_adts_audio;
if ((err = transcode->recode(&pkt, data_ptr, elen, number)) != srs_success) {
int nn_opus_packets = 0;
int opus_sizes[kMaxOpusPackets];
if ((err = codec->recode(&aac, opus_payloads, opus_sizes, nn_opus_packets)) != srs_success) {
return srs_error_wrap(err, "recode error");
}
for (int i = 0; i < number; i++) {
SrsSample sample;
sample.size = elen[i];
sample.bytes = data_ptr[i];
packet_opus(shared_audio, &sample, rtp_packet_vec);
// Save OPUS packets in shared message.
if (nn_opus_packets <= 0) {
return err;
}
shared_audio->set_rtp_packets(rtp_packet_vec);
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);
return err;
}
srs_error_t SrsRtpOpusMuxer::packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector<SrsRtpSharedPacket*>& rtp_packet_vec)
{
srs_error_t err = srs_success;
SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket();
rtp_shared_pkt->rtp_header.set_marker(true);
if ((err = rtp_shared_pkt->create(timestamp, sequence++, kAudioSSRC, kOpusPayloadType, sample->bytes, sample->size)) != srs_success) {
return srs_error_wrap(err, "rtp packet encode");
nn_max_extra_payload = srs_max(nn_max_extra_payload, p->size);
}
// TODO: FIXME: Why 960? Need Refactoring?
timestamp += 960;
rtp_packet_vec.push_back(rtp_shared_pkt);
shared_audio->set_extra_payloads(samples, nn_opus_packets);
shared_audio->set_max_extra_payload(nn_max_extra_payload);
return err;
}
@ -485,17 +330,16 @@ srs_error_t SrsRtc::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
// ignore sequence header
srs_assert(format->audio);
SrsBuffer* stream = NULL;
SrsAutoFree(SrsBuffer, stream);
if ((err = aac_raw_append_adts_header(shared_audio, format, &stream)) != srs_success) {
char* adts_audio = NULL;
int nn_adts_audio = 0;
// TODO: FIXME: Reserve 7 bytes header when create shared message.
if ((err = aac_raw_append_adts_header(shared_audio, format, &adts_audio, &nn_adts_audio)) != srs_success) {
return srs_error_wrap(err, "aac append header");
}
if (stream) {
char* stream_data = stream->data();
SrsAutoFreeA(char, stream_data);
return rtp_opus_muxer->frame_to_packet(shared_audio, format, stream);
if (adts_audio) {
err = rtp_opus_muxer->transcode(shared_audio, adts_audio, nn_adts_audio);
srs_freep(adts_audio);
}
return err;
@ -522,5 +366,5 @@ srs_error_t SrsRtc::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma
// ignore info frame,
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
srs_assert(format->video);
return rtp_h264_muxer->frame_to_packet(shared_video, format);
return rtp_h264_muxer->filter(shared_video, format);
}

View file

@ -39,30 +39,15 @@ class SrsOriginHub;
class SrsAudioRecode;
class SrsBuffer;
// Rtp packet max payload size, not include rtp header.
// Must left some bytes to payload header, rtp header, udp header, ip header.
const int kRtpMaxPayloadSize = 1200;
// The RTP packet max size, should never exceed this size.
const int kRtpPacketSize = 1500;
// Payload type will rewrite in srs_app_rtc_conn.cpp when send to client.
const uint8_t kOpusPayloadType = 111;
const uint8_t kH264PayloadType = 102;
// H.264 nalu header type mask.
const uint8_t kNalTypeMask = 0x1F;
// @see: https://tools.ietf.org/html/rfc6184#section-5.2
const uint8_t kStapA = 24;
const uint8_t kFuA = 28;
// @see: https://tools.ietf.org/html/rfc6184#section-5.8
const uint8_t kStart = 0x80; // Fu-header start bit
const uint8_t kEnd = 0x40; // Fu-header end bit
const int kChannel = 2;
const int kSamplerate = 48000;
const int kArrayLength = 8;
const int kArrayBuffer = 4096;
// SSRC will rewrite in srs_app_rtc_conn.cpp when send to client.
const uint32_t kAudioSSRC = 1;
@ -71,39 +56,26 @@ const uint32_t kVideoSSRC = 2;
// TODO: Define interface class like ISrsRtpMuxer
class SrsRtpH264Muxer
{
private:
uint16_t sequence;
std::string sps;
std::string pps;
public:
bool discard_bframe;
public:
SrsRtpH264Muxer();
virtual ~SrsRtpH264Muxer();
public:
srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format);
private:
srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector<SrsRtpSharedPacket*>& rtp_packet_vec);
srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector<SrsRtpSharedPacket*>& rtp_packet_vec);
srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector<SrsRtpSharedPacket*>& rtp_packet_vec);
srs_error_t filter(SrsSharedPtrMessage* shared_video, SrsFormat* format);
};
// TODO: FIXME: It's not a muxer, but a transcoder.
class SrsRtpOpusMuxer
{
private:
// TODO: FIXME: How to handle timestamp overflow?
uint32_t timestamp;
uint16_t sequence;
SrsAudioRecode* transcode;
SrsAudioRecode* codec;
public:
SrsRtpOpusMuxer();
virtual ~SrsRtpOpusMuxer();
virtual srs_error_t initialize();
public:
srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream);
private:
srs_error_t packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector<SrsRtpSharedPacket*>& rtp_packet_vec);
srs_error_t transcode(SrsSharedPtrMessage* shared_audio, char* adts_audio, int nn_adts_audio);
};
class SrsRtc

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,7 @@
#include <srs_app_hybrid.hpp>
#include <srs_app_hourglass.hpp>
#include <srs_app_sdp.hpp>
#include <srs_app_reload.hpp>
#include <string>
#include <map>
@ -48,6 +49,8 @@ class SrsRtcServer;
class SrsRtcSession;
class SrsSharedPtrMessage;
class SrsSource;
class SrsRtpPacket2;
class ISrsUdpSender;
const uint8_t kSR = 200;
const uint8_t kRR = 201;
@ -98,23 +101,75 @@ public:
srs_error_t initialize(const SrsRequest& req);
srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* skt);
srs_error_t on_dtls_application_data(const char* data, const int len);
public:
srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf);
srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr);
srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf);
srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf);
srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf);
private:
srs_error_t handshake(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t handshake(SrsUdpMuxSocket* skt);
private:
srs_error_t srtp_initialize();
srs_error_t srtp_send_init();
srs_error_t srtp_recv_init();
};
class SrsRtcSenderThread : public ISrsCoroutineHandler
// A group of RTP packets.
class SrsRtcPackets
{
public:
bool use_gso;
bool should_merge_nalus;
public:
#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;
// For video, the samples or NALUs.
int nn_samples;
// For audio, the generated extra audio packets.
// For example, when transcoding AAC to opus, may many extra payloads for a audio.
int nn_extras;
// The original audio messages.
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:
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
{
protected:
SrsCoroutine* trd;
@ -125,13 +180,34 @@ private:
uint32_t audio_ssrc;
uint16_t video_payload_type;
uint16_t audio_payload_type;
private:
// TODO: FIXME: How to handle timestamp overflow?
uint32_t audio_timestamp;
uint16_t audio_sequence;
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();
public:
srs_error_t initialize(const uint32_t& vssrc, const uint32_t& assrc, const uint16_t& v_pt, const uint16_t& a_pt);
// 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:
@ -139,11 +215,21 @@ public:
virtual void stop();
virtual void stop_loop();
public:
virtual srs_error_t cycle();
void update_sendonly_socket(SrsUdpMuxSocket* skt);
public:
void update_sendonly_socket(SrsUdpMuxSocket* ukt);
virtual srs_error_t cycle();
private:
void send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt);
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(SrsRtcPackets& packets);
srs_error_t send_packets_gso(SrsRtcPackets& packets);
private:
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, SrsRtcPackets& packets);
srs_error_t packet_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtcPackets& packets);
};
class SrsRtcSession
@ -194,37 +280,75 @@ public:
void switch_to_context();
public:
srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req);
srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_rtcp(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req);
srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_rtcp(SrsUdpMuxSocket* skt);
public:
srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_connection_established(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t start_play(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t send_client_hello(SrsUdpMuxSocket* skt);
srs_error_t on_connection_established(SrsUdpMuxSocket* skt);
srs_error_t start_play(SrsUdpMuxSocket* skt);
public:
bool is_stun_timeout();
private:
srs_error_t check_source();
private:
srs_error_t on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req);
srs_error_t on_binding_request(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req);
private:
srs_error_t on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt);
srs_error_t on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt);
srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* skt);
};
class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass, virtual public ISrsCoroutineHandler
class SrsUdpMuxSender : virtual public ISrsUdpSender, virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
{
private:
SrsUdpMuxListener* listener;
SrsHourGlass* timer;
private:
srs_netfd_t lfd;
SrsRtcServer* server;
SrsCoroutine* trd;
private:
srs_cond_t cond;
bool waiting_msgs;
// TODO: FIXME: Support multiple stfd.
srs_netfd_t mmstfd;
std::vector<mmsghdr> mmhdrs;
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;
// Cache msgs, for other coroutines to fill it.
std::vector<mmsghdr> cache;
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, 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:
virtual srs_error_t on_reload_rtc_server();
};
class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass
{
private:
SrsHourGlass* timer;
std::vector<SrsUdpMuxListener*> listeners;
std::vector<SrsUdpMuxSender*> senders;
private:
std::map<std::string, SrsRtcSession*> map_username_session; // key: username(local_ufrag + ":" + remote_ufrag)
std::map<std::string, SrsRtcSession*> map_id_session; // key: peerip(ip + ":" + port)
@ -237,27 +361,23 @@ public:
// TODO: FIXME: Support gracefully quit.
// TODO: FIXME: Support reload.
virtual srs_error_t listen_udp();
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt);
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt);
public:
virtual srs_error_t listen_api();
SrsRtcSession* create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp, const std::string& mock_eip);
bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session);
void check_and_clean_timeout_session();
int nn_sessions() { return (int)map_username_session.size(); }
private:
srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt);
srs_error_t on_stun(SrsUdpMuxSocket* skt);
srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* skt);
private:
SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag);
SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id);
// interface ISrsHourGlass
public:
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick);
// Internal only.
public:
srs_error_t send_and_free_messages(srs_netfd_t stfd, const std::vector<mmsghdr>& msgs);
void free_messages(std::vector<mmsghdr>& hdrs);
virtual srs_error_t cycle();
};
// The RTC server adapter.

View file

@ -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(0, 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;

View file

@ -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();

View file

@ -78,6 +78,14 @@ srs_error_t parse_h264_fmtp(const std::string& fmtp, H264SpecificParam& h264_par
if (kv[0] == "profile-level-id") {
h264_param.profile_level_id = kv[1];
} else if (kv[0] == "packetization-mode") {
// 6.3. Non-Interleaved Mode
// This mode is in use when the value of the OPTIONAL packetization-mode
// media type parameter is equal to 1. This mode SHOULD be supported.
// It is primarily intended for low-delay applications. Only single NAL
// unit packets, STAP-As, and FU-As MAY be used in this mode. STAP-Bs,
// MTAPs, and FU-Bs MUST NOT be used. The transmission order of NAL
// units MUST comply with the NAL unit decoding order.
// @see https://tools.ietf.org/html/rfc6184#section-6.3
h264_param.packetization_mode = kv[1];
} else if (kv[0] == "level-asymmetry-allowed") {
h264_param.level_asymmerty_allow = kv[1];

View file

@ -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");
}
@ -1143,7 +1168,8 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se
// TODO: FIXME: Refactor to move to rtp?
// Save the RTP packets for find_rtp_packet() to rtx or restore it.
source->rtp_queue->push(msg->rtp_packets);
// TODO: FIXME: Remove dead code.
//source->rtp_queue->push(msg->rtp_packets);
#endif
if ((err = hls->on_video(msg, format)) != srs_success) {
@ -2718,4 +2744,9 @@ SrsRtpSharedPacket* SrsSource::find_rtp_packet(const uint16_t& seq)
{
return rtp_queue->find(seq);
}
SrsMetaCache* SrsSource::cached_meta()
{
return meta;
}
#endif

View file

@ -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.
@ -327,6 +335,7 @@ public:
#ifdef SRS_AUTO_RTC
// To find the RTP packet for RTX or restore.
// TODO: FIXME: Should queue RTP packets in connection level.
class SrsRtpPacketQueue
{
private:
@ -634,6 +643,8 @@ public:
#ifdef SRS_AUTO_RTC
// Find rtp packet by sequence
SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq);
// Get the cached meta, as such the sps/pps.
SrsMetaCache* cached_meta();
#endif
};

View file

@ -236,6 +236,8 @@ srs_error_t SrsStatisticClient::dumps(SrsJsonObject* obj)
SrsStatisticCategory::SrsStatisticCategory()
{
nn = 0;
a = 0;
b = 0;
c = 0;
@ -265,8 +267,12 @@ SrsStatistic::SrsStatistic()
perf_iovs = new SrsStatisticCategory();
perf_msgs = new SrsStatisticCategory();
perf_sys = 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();
}
SrsStatistic::~SrsStatistic()
@ -303,8 +309,12 @@ SrsStatistic::~SrsStatistic()
srs_freep(perf_iovs);
srs_freep(perf_msgs);
srs_freep(perf_sys);
srs_freep(perf_sendmmsg);
srs_freep(perf_gso);
srs_freep(perf_rtp);
srs_freep(perf_rtc);
srs_freep(perf_bytes);
srs_freep(perf_dropped);
}
SrsStatistic* SrsStatistic::instance()
@ -585,225 +595,202 @@ srs_error_t SrsStatistic::dumps_clients(SrsJsonArray* arr, int start, int count)
return err;
}
void SrsStatistic::perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs)
void SrsStatistic::perf_on_msgs(int nb_msgs)
{
// For perf msgs, the nb_msgs stat.
// a: =1
// b: <10
// c: <100
// d: <200
// e: <300
// f: <400
// g: <500
// h: <600
// i: <1000
// j: >=1000
if (nb_msgs == 1) {
perf_msgs->a++;
} else if (nb_msgs < 10) {
perf_msgs->b++;
} else if (nb_msgs < 100) {
perf_msgs->c++;
} else if (nb_msgs < 200) {
perf_msgs->d++;
} else if (nb_msgs < 300) {
perf_msgs->e++;
} else if (nb_msgs < 400) {
perf_msgs->f++;
} else if (nb_msgs < 500) {
perf_msgs->g++;
} else if (nb_msgs < 600) {
perf_msgs->h++;
} else if (nb_msgs < 1000) {
perf_msgs->i++;
} else {
perf_msgs->j++;
}
// For perf iovs, the nb_iovs stat.
// a: <=2
// b: <10
// c: <20
// d: <200
// e: <300
// f: <500
// g: <700
// h: <900
// i: <1024
// j: >=1024
if (nb_iovs <= 2) {
perf_iovs->a++;
} else if (nb_iovs < 10) {
perf_iovs->b++;
} else if (nb_iovs < 20) {
perf_iovs->c++;
} else if (nb_iovs < 200) {
perf_iovs->d++;
} else if (nb_iovs < 300) {
perf_iovs->e++;
} else if (nb_iovs < 500) {
perf_iovs->f++;
} else if (nb_iovs < 700) {
perf_iovs->g++;
} else if (nb_iovs < 900) {
perf_iovs->h++;
} else if (nb_iovs < 1024) {
perf_iovs->i++;
} else {
perf_iovs->j++;
}
// Stat the syscalls.
// a: number of syscalls of msgs.
perf_sys->a++;
perf_on_packets(perf_msgs, nb_msgs);
}
void SrsStatistic::perf_mw_on_packets(int nb_pkts, int bytes_pkts, int nb_iovs)
srs_error_t SrsStatistic::dumps_perf_msgs(SrsJsonObject* obj)
{
// Stat the syscalls.
// a: number of syscalls of msgs.
// b: number of syscalls of pkts.
perf_sys->b++;
return dumps_perf(perf_msgs, obj);
}
srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj)
void SrsStatistic::perf_on_rtc_packets(int nb_packets)
{
srs_error_t err = srs_success;
if (true) {
SrsJsonObject* p = SrsJsonAny::object();
obj->set("msgs", p);
// For perf msgs, the nb_msgs stat.
// a: =1
// b: <10
// c: <100
// d: <200
// e: <300
// f: <400
// g: <500
// h: <600
// i: <1000
// j: >=1000
p->set("lt_2", SrsJsonAny::integer(perf_msgs->a));
p->set("lt_10", SrsJsonAny::integer(perf_msgs->b));
p->set("lt_100", SrsJsonAny::integer(perf_msgs->c));
p->set("lt_200", SrsJsonAny::integer(perf_msgs->d));
p->set("lt_300", SrsJsonAny::integer(perf_msgs->e));
p->set("lt_400", SrsJsonAny::integer(perf_msgs->f));
p->set("lt_500", SrsJsonAny::integer(perf_msgs->g));
p->set("lt_600", SrsJsonAny::integer(perf_msgs->h));
p->set("lt_1000", SrsJsonAny::integer(perf_msgs->i));
p->set("gt_1000", SrsJsonAny::integer(perf_msgs->j));
}
if (true) {
SrsJsonObject* p = SrsJsonAny::object();
obj->set("iovs", p);
// For perf iovs, the nb_iovs stat.
// a: <=2
// b: <10
// c: <20
// d: <200
// e: <300
// f: <500
// g: <700
// h: <900
// i: <1024
// j: >=1024
p->set("lt_3", SrsJsonAny::integer(perf_iovs->a));
p->set("lt_10", SrsJsonAny::integer(perf_iovs->b));
p->set("lt_20", SrsJsonAny::integer(perf_iovs->c));
p->set("lt_200", SrsJsonAny::integer(perf_iovs->d));
p->set("lt_300", SrsJsonAny::integer(perf_iovs->e));
p->set("lt_500", SrsJsonAny::integer(perf_iovs->f));
p->set("lt_700", SrsJsonAny::integer(perf_iovs->g));
p->set("lt_900", SrsJsonAny::integer(perf_iovs->h));
p->set("lt_1024", SrsJsonAny::integer(perf_iovs->i));
p->set("gt_1024", SrsJsonAny::integer(perf_iovs->j));
}
if (true) {
SrsJsonObject* p = SrsJsonAny::object();
obj->set("sys", p);
// Stat the syscalls.
// a: number of syscalls of msgs.
// b: number of syscalls of pkts.
p->set("msgs", SrsJsonAny::integer(perf_sys->a));
p->set("pkts", SrsJsonAny::integer(perf_sys->b));
}
return err;
perf_on_packets(perf_rtc, nb_packets);
}
void SrsStatistic::perf_mw_on_packets(int nb_msgs)
srs_error_t SrsStatistic::dumps_perf_rtc_packets(SrsJsonObject* obj)
{
// For perf msgs, the nb_msgs stat.
// a: =1
// b: <10
// c: <100
// d: <200
// e: <300
// f: <400
// g: <500
// h: <600
// i: <1000
// j: >=1000
if (nb_msgs == 1) {
perf_sendmmsg->a++;
} else if (nb_msgs < 10) {
perf_sendmmsg->b++;
} else if (nb_msgs < 100) {
perf_sendmmsg->c++;
} else if (nb_msgs < 200) {
perf_sendmmsg->d++;
} else if (nb_msgs < 300) {
perf_sendmmsg->e++;
} else if (nb_msgs < 400) {
perf_sendmmsg->f++;
} else if (nb_msgs < 500) {
perf_sendmmsg->g++;
} else if (nb_msgs < 600) {
perf_sendmmsg->h++;
} else if (nb_msgs < 1000) {
perf_sendmmsg->i++;
} else {
perf_sendmmsg->j++;
}
return dumps_perf(perf_rtc, obj);
}
void SrsStatistic::perf_on_rtp_packets(int nb_packets)
{
perf_on_packets(perf_rtp, nb_packets);
}
srs_error_t SrsStatistic::dumps_perf_rtp_packets(SrsJsonObject* obj)
{
return dumps_perf(perf_rtp, obj);
}
void SrsStatistic::perf_on_gso_packets(int nb_packets)
{
perf_on_packets(perf_gso, nb_packets);
}
srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj)
{
return dumps_perf(perf_gso, obj);
}
void SrsStatistic::perf_on_writev_iovs(int nb_iovs)
{
perf_on_packets(perf_iovs, nb_iovs);
}
srs_error_t SrsStatistic::dumps_perf_writev_iovs(SrsJsonObject* obj)
{
return dumps_perf(perf_iovs, obj);
}
void SrsStatistic::perf_on_sendmmsg_packets(int nb_packets)
{
perf_on_packets(perf_sendmmsg, nb_packets);
}
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:
// 2, 3, 5, 9, 16, 32, 64, 128, 256
// that is:
// a: <2
// b: <3
// c: <5
// d: <9
// e: <16
// f: <32
// g: <64
// h: <128
// i: <256
// j: >=256
if (nb_msgs < 2) {
p->a++;
} else if (nb_msgs < 3) {
p->b++;
} else if (nb_msgs < 5) {
p->c++;
} else if (nb_msgs < 9) {
p->d++;
} else if (nb_msgs < 16) {
p->e++;
} else if (nb_msgs < 32) {
p->f++;
} else if (nb_msgs < 64) {
p->g++;
} else if (nb_msgs < 128) {
p->h++;
} else if (nb_msgs < 256) {
p->i++;
} else {
p->j++;
}
p->nn += nb_msgs;
}
srs_error_t SrsStatistic::dumps_perf(SrsStatisticCategory* p, SrsJsonObject* obj)
{
srs_error_t err = srs_success;
if (true) {
SrsJsonObject* p = SrsJsonAny::object();
obj->set("msgs", p);
// The range for stat:
// 2, 3, 5, 9, 16, 32, 64, 128, 256
// that is:
// a: <2
// b: <3
// c: <5
// d: <9
// e: <16
// f: <32
// g: <64
// h: <128
// i: <256
// j: >=256
if (p->a) obj->set("lt_2", SrsJsonAny::integer(p->a));
if (p->b) obj->set("lt_3", SrsJsonAny::integer(p->b));
if (p->c) obj->set("lt_5", SrsJsonAny::integer(p->c));
if (p->d) obj->set("lt_9", SrsJsonAny::integer(p->d));
if (p->e) obj->set("lt_16", SrsJsonAny::integer(p->e));
if (p->f) obj->set("lt_32", SrsJsonAny::integer(p->f));
if (p->g) obj->set("lt_64", SrsJsonAny::integer(p->g));
if (p->h) obj->set("lt_128", SrsJsonAny::integer(p->h));
if (p->i) obj->set("lt_256", SrsJsonAny::integer(p->i));
if (p->j) obj->set("gt_256", SrsJsonAny::integer(p->j));
// For perf msgs, the nb_msgs stat.
// a: =1
// b: <10
// c: <100
// d: <200
// e: <300
// f: <400
// g: <500
// h: <600
// i: <1000
// j: >=1000
p->set("lt_2", SrsJsonAny::integer(perf_sendmmsg->a));
p->set("lt_10", SrsJsonAny::integer(perf_sendmmsg->b));
p->set("lt_100", SrsJsonAny::integer(perf_sendmmsg->c));
p->set("lt_200", SrsJsonAny::integer(perf_sendmmsg->d));
p->set("lt_300", SrsJsonAny::integer(perf_sendmmsg->e));
p->set("lt_400", SrsJsonAny::integer(perf_sendmmsg->f));
p->set("lt_500", SrsJsonAny::integer(perf_sendmmsg->g));
p->set("lt_600", SrsJsonAny::integer(perf_sendmmsg->h));
p->set("lt_1000", SrsJsonAny::integer(perf_sendmmsg->i));
p->set("gt_1000", SrsJsonAny::integer(perf_sendmmsg->j));
}
obj->set("nn", SrsJsonAny::integer(p->nn));
return err;
}

View file

@ -124,6 +124,8 @@ public:
class SrsStatisticCategory
{
public:
uint64_t nn;
public:
uint64_t a;
uint64_t b;
@ -168,8 +170,12 @@ private:
// The perf stat for mw(merged write).
SrsStatisticCategory* perf_iovs;
SrsStatisticCategory* perf_msgs;
SrsStatisticCategory* perf_sys;
SrsStatisticCategory* perf_sendmmsg;
SrsStatisticCategory* perf_gso;
SrsStatisticCategory* perf_rtp;
SrsStatisticCategory* perf_rtc;
SrsStatisticCategory* perf_bytes;
SrsStatisticCategory* perf_dropped;
private:
SrsStatistic();
virtual ~SrsStatistic();
@ -228,19 +234,47 @@ public:
// @param count the max count of clients to dump.
virtual srs_error_t dumps_clients(SrsJsonArray* arr, int start, int count);
public:
// Stat for packets merged written, nb_msgs is the number of RTMP messages,
// bytes_msgs is the total bytes of RTMP messages, nb_iovs is the total number of iovec.
virtual void perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs);
// Stat for packets merged written, nb_pkts is the number of or chunk packets,
// bytes_pkts is the total bytes of or chunk packets, nb_iovs is the total number of iovec.
virtual void perf_mw_on_packets(int nb_pkts, int bytes_pkts, int nb_iovs);
// Dumps the perf statistic data for TCP writev, for performance analysis.
virtual srs_error_t dumps_perf_writev(SrsJsonObject* obj);
// Stat for packets merged written, nb_msgs is the number of RTMP messages.
// For example, publish by FFMPEG, Audio and Video frames.
virtual void perf_on_msgs(int nb_msgs);
virtual srs_error_t dumps_perf_msgs(SrsJsonObject* obj);
public:
// Stat for packets UDP sendmmsg, nb_msgs is the vlen for sendmmsg.
virtual void perf_mw_on_packets(int nb_msgs);
// Dumps the perf statistic data for UDP sendmmsg, for performance analysis.
// Stat for packets merged written, nb_packets is the number of RTC packets.
// For example, a RTMP/AAC audio packet maybe transcoded to two RTC/opus packets.
virtual void perf_on_rtc_packets(int nb_packets);
virtual srs_error_t dumps_perf_rtc_packets(SrsJsonObject* obj);
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);
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);
virtual srs_error_t dumps_perf_gso(SrsJsonObject* obj);
public:
// Stat for TCP writev, nb_iovs is the total number of iovec.
virtual void perf_on_writev_iovs(int nb_iovs);
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_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);
private:
virtual SrsStatisticVhost* create_vhost(SrsRequest* req);
virtual SrsStatisticStream* create_stream(SrsStatisticVhost* vhost, SrsRequest* req);

View file

@ -33,6 +33,11 @@
// The macros generated by configure script.
#include <srs_auto_headers.hpp>
// Alias for debug.
#ifdef SRS_AUTO_DEBUG
#define SRS_DEBUG
#endif
// To convert macro values to string.
// @see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
#define SRS_INTERNAL_STR(v) #v

View file

@ -127,8 +127,12 @@
*/
#define SRS_PERF_QUEUE_COND_WAIT
#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_FOR_RTC 4
// For RTC, use smaller wait queue.
#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
@ -188,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

View file

@ -24,6 +24,6 @@
#ifndef SRS_CORE_VERSION4_HPP
#define SRS_CORE_VERSION4_HPP
#define SRS_VERSION4_REVISION 22
#define SRS_VERSION4_REVISION 23
#endif

View file

@ -29,6 +29,14 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_kernel_utility.hpp>
ISrsEncoder::ISrsEncoder()
{
}
ISrsEncoder::~ISrsEncoder()
{
}
ISrsCodec::ISrsCodec()
{
}
@ -59,11 +67,6 @@ SrsBuffer::~SrsBuffer()
{
}
char* SrsBuffer::data()
{
return bytes;
}
int SrsBuffer::size()
{
return nb_bytes;

View file

@ -31,6 +31,24 @@
class SrsBuffer;
// Encoder.
class ISrsEncoder
{
public:
ISrsEncoder();
virtual ~ISrsEncoder();
public:
/**
* get the number of bytes to code to.
*/
// TODO: FIXME: change to uint64_t.
virtual int nb_bytes() = 0;
/**
* encode object to bytes in SrsBuffer.
*/
virtual srs_error_t encode(SrsBuffer* buf) = 0;
};
/**
* the srs codec, to code and decode object with bytes:
* code: to encode/serialize object to bytes in buffer,
@ -56,21 +74,11 @@ class SrsBuffer;
* @remark protocol or amf0 or json should implements this interface.
*/
// TODO: FIXME: protocol, amf0, json should implements it.
class ISrsCodec
class ISrsCodec : public ISrsEncoder
{
public:
ISrsCodec();
virtual ~ISrsCodec();
public:
/**
* get the number of bytes to code to.
*/
// TODO: FIXME: change to uint64_t.
virtual int nb_bytes() = 0;
/**
* encode object to bytes in SrsBuffer.
*/
virtual srs_error_t encode(SrsBuffer* buf) = 0;
public:
/**
* decode object from bytes in SrsBuffer.
@ -105,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().

View file

@ -32,6 +32,7 @@ using namespace std;
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_rtp.hpp>
string srs_video_codec_id2str(SrsVideoCodecId codec)
{
@ -364,12 +365,58 @@ SrsSample::SrsSample()
{
size = 0;
bytes = NULL;
bframe = false;
}
SrsSample::~SrsSample()
{
}
srs_error_t SrsSample::parse_bframe()
{
srs_error_t err = srs_success;
uint8_t header = bytes[0];
SrsAvcNaluType nal_type = (SrsAvcNaluType)(header & kNalTypeMask);
if (nal_type != SrsAvcNaluTypeNonIDR && nal_type != SrsAvcNaluTypeDataPartitionA && nal_type != SrsAvcNaluTypeIDR) {
return err;
}
SrsBuffer* stream = new SrsBuffer(bytes, size);
SrsAutoFree(SrsBuffer, stream);
// Skip nalu header.
stream->skip(1);
SrsBitBuffer bitstream(stream);
int32_t first_mb_in_slice = 0;
if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) {
return srs_error_wrap(err, "nalu read uev");
}
int32_t slice_type_v = 0;
if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type_v)) != srs_success) {
return srs_error_wrap(err, "nalu read uev");
}
SrsAvcSliceType slice_type = (SrsAvcSliceType)slice_type_v;
if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) {
bframe = true;
srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type);
}
return err;
}
SrsSample* SrsSample::copy()
{
SrsSample* p = new SrsSample();
p->bytes = bytes;
p->size = size;
return p;
}
SrsCodecConfig::SrsCodecConfig()
{
}
@ -458,6 +505,7 @@ srs_error_t SrsFrame::add_sample(char* bytes, int size)
SrsSample* sample = &samples[nb_samples++];
sample->bytes = bytes;
sample->size = size;
sample->bframe = false;
return err;
}
@ -488,6 +536,13 @@ SrsVideoFrame::~SrsVideoFrame()
{
}
srs_error_t SrsVideoFrame::initialize(SrsCodecConfig* c)
{
first_nalu_type = SrsAvcNaluTypeForbidden;
has_idr = has_sps_pps = has_aud = false;
return SrsFrame::initialize(c);
}
srs_error_t SrsVideoFrame::add_sample(char* bytes, int size)
{
srs_error_t err = srs_success;

View file

@ -532,11 +532,18 @@ class SrsSample
public:
// The size of unit.
int size;
// The ptr of unit, user must manage it.
// The ptr of unit, user must free it.
char* bytes;
// Whether is B frame.
bool bframe;
public:
SrsSample();
virtual ~SrsSample();
~SrsSample();
public:
// If we need to know whether sample is bframe, we have to parse the NALU payload.
srs_error_t parse_bframe();
// Copy sample, share the bytes pointer.
SrsSample* copy();
};
/**
@ -703,6 +710,8 @@ public:
SrsVideoFrame();
virtual ~SrsVideoFrame();
public:
// Initialize the frame, to parse sampels.
virtual srs_error_t initialize(SrsCodecConfig* c);
// Add the sample without ANNEXB or IBMF header, or RAW AAC or MP3 data.
virtual srs_error_t add_sample(char* bytes, int size);
public:

View file

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

View file

@ -194,8 +194,11 @@ srs_error_t SrsCommonMessage::create(SrsMessageHeader* pheader, char* body, int
return srs_success;
}
SrsSharedMessageHeader::SrsSharedMessageHeader() : payload_length(0), message_type(0), perfer_cid(0)
SrsSharedMessageHeader::SrsSharedMessageHeader()
{
payload_length = 0;
message_type = 0;
perfer_cid = 0;
}
SrsSharedMessageHeader::~SrsSharedMessageHeader()
@ -207,6 +210,16 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()
payload = NULL;
size = 0;
shared_count = 0;
#ifdef SRS_AUTO_RTC
samples = NULL;
nn_samples = 0;
has_idr = false;
extra_payloads = NULL;
nn_extra_payloads = 0;
nn_max_extra_payloads = 0;
#endif
}
SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
@ -215,6 +228,17 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
srs_memory_unwatch(payload);
#endif
srs_freepa(payload);
#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);
}
srs_freepa(extra_payloads);
nn_extra_payloads = 0;
#endif
}
SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL)
@ -231,12 +255,6 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage()
ptr->shared_count--;
}
}
#ifdef SRS_AUTO_RTC
for (int i = 0; i < (int)rtp_packets.size(); ++i) {
srs_freep(rtp_packets[i]);
}
#endif
}
srs_error_t SrsSharedPtrMessage::create(SrsCommonMessage* msg)
@ -355,19 +373,30 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy()
copy->payload = ptr->payload;
copy->size = ptr->size;
#ifdef SRS_AUTO_RTC
for (int i = 0; i < (int)rtp_packets.size(); ++i) {
copy->rtp_packets.push_back(rtp_packets[i]->copy());
}
#endif
return copy;
}
#ifdef SRS_AUTO_RTC
void SrsSharedPtrMessage::set_rtp_packets(const std::vector<SrsRtpSharedPacket*>& pkts)
void SrsSharedPtrMessage::set_extra_payloads(SrsSample* payloads, int nn_payloads)
{
rtp_packets = pkts;
srs_assert(nn_payloads);
srs_assert(!ptr->extra_payloads);
ptr->nn_extra_payloads = nn_payloads;
ptr->extra_payloads = new SrsSample[nn_payloads];
memcpy((void*)ptr->extra_payloads, payloads, nn_payloads * sizeof(SrsSample));
}
void SrsSharedPtrMessage::set_samples(SrsSample* samples, int nn_samples)
{
srs_assert(nn_samples);
srs_assert(!ptr->samples);
ptr->nn_samples = nn_samples;
ptr->samples = new SrsSample[nn_samples];
memcpy((void*)ptr->samples, samples, nn_samples * sizeof(SrsSample));
}
#endif

View file

@ -40,6 +40,7 @@ class ISrsReader;
class SrsFileReader;
class SrsPacket;
class SrsRtpSharedPacket;
class SrsSample;
#define SRS_FLV_TAG_HEADER_SIZE 11
#define SRS_FLV_PREVIOUS_TAG_SIZE 4
@ -288,10 +289,6 @@ public:
// video/audio packet use raw bytes, no video/audio packet.
char* payload;
#ifdef SRS_AUTO_RTC
std::vector<SrsRtpSharedPacket*> rtp_packets;
#endif
private:
class SrsSharedPtrPayload
{
@ -305,6 +302,23 @@ private:
int size;
// The reference count
int shared_count;
#ifdef SRS_AUTO_RTC
public:
// For RTC video, we need to know the NALU structures,
// because the RTP STAP-A or FU-A based on NALU.
SrsSample* samples;
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();
virtual ~SrsSharedPtrPayload();
@ -348,7 +362,21 @@ public:
virtual SrsSharedPtrMessage* copy();
public:
#ifdef SRS_AUTO_RTC
virtual void set_rtp_packets(const std::vector<SrsRtpSharedPacket*>& pkts);
// Set extra samples, for example, when we transcode an AAC audio packet to OPUS,
// we may get more than one OPUS packets, we set these OPUS packets in extra payloads.
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; }
// Set samples, each sample points to the address of payload.
void set_samples(SrsSample* samples, int nn_samples);
int nn_samples() { return ptr->nn_samples; }
SrsSample* samples() { return ptr->samples; }
#endif
};

View file

@ -32,6 +32,15 @@ using namespace std;
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp>
// @see: https://tools.ietf.org/html/rfc6184#section-5.2
const uint8_t kStapA = 24;
// @see: https://tools.ietf.org/html/rfc6184#section-5.2
const uint8_t kFuA = 28;
// @see: https://tools.ietf.org/html/rfc6184#section-5.8
const uint8_t kStart = 0x80; // Fu-header start bit
const uint8_t kEnd = 0x40; // Fu-header end bit
SrsRtpHeader::SrsRtpHeader()
{
@ -46,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()
@ -77,7 +74,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* stream)
{
srs_error_t err = srs_success;
// TODO:
// TODO: FIXME: Implements it.
return err;
}
@ -86,30 +83,63 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream)
{
srs_error_t err = srs_success;
uint8_t first = 0x80 | cc;
// 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) {
first |= 0x40;
v |= 0x20;
}
if (extension) {
first |= 0x10;
v |= 0x10;
}
stream->write_1bytes(first);
uint8_t second = payload_type;
*p++ = v;
// The marker and payload type, total 1 byte.
v = payload_type;
if (marker) {
payload_type |= kRtpMarker;
v |= kRtpMarker;
}
stream->write_1bytes(second);
stream->write_2bytes(sequence);
stream->write_4bytes(timestamp);
stream->write_4bytes(ssrc);
*p++ = v;
// The sequence number, 2 bytes.
char* pp = (char*)&sequence;
*p++ = pp[1];
*p++ = pp[0];
// The timestamp, 4 bytes.
pp = (char*)&timestamp;
*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;
}
@ -118,29 +148,408 @@ size_t SrsRtpHeader::header_size()
return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0);
}
void SrsRtpHeader::set_marker(bool marker)
SrsRtpPacket2::SrsRtpPacket2()
{
this->marker = marker;
payload = NULL;
padding = 0;
cache_raw = new SrsRtpRawPayload();
cache_fua = new SrsRtpFUAPayload2();
cache_payload = 0;
}
void SrsRtpHeader::set_payload_type(uint8_t payload_type)
SrsRtpPacket2::~SrsRtpPacket2()
{
this->payload_type = payload_type;
// 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 SrsRtpHeader::set_sequence(uint16_t sequence)
void SrsRtpPacket2::set_padding(int size)
{
this->sequence = sequence;
rtp_header.set_padding(size > 0);
if (cache_payload) {
cache_payload += size - padding;
}
padding = size;
}
void SrsRtpHeader::set_timestamp(int64_t timestamp)
void SrsRtpPacket2::add_padding(int size)
{
this->timestamp = timestamp;
rtp_header.set_padding(padding + size > 0);
if (cache_payload) {
cache_payload += size;
}
padding += size;
}
void SrsRtpHeader::set_ssrc(uint32_t ssrc)
void SrsRtpPacket2::reset()
{
this->ssrc = ssrc;
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()
{
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)
{
srs_error_t err = srs_success;
if ((err = rtp_header.encode(buf)) != srs_success) {
return srs_error_wrap(err, "rtp header");
}
if (payload && (err = payload->encode(buf)) != srs_success) {
return srs_error_wrap(err, "encode payload");
}
if (padding > 0) {
if (!buf->require(padding)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", padding);
}
memset(buf->data() + buf->pos(), padding, padding);
buf->skip(padding);
}
return err;
}
SrsRtpRawPayload::SrsRtpRawPayload()
{
payload = NULL;
nn_payload = 0;
}
SrsRtpRawPayload::~SrsRtpRawPayload()
{
}
int SrsRtpRawPayload::nb_bytes()
{
return nn_payload;
}
srs_error_t SrsRtpRawPayload::encode(SrsBuffer* buf)
{
if (nn_payload <= 0) {
return srs_success;
}
if (!buf->require(nn_payload)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", nn_payload);
}
buf->write_bytes(payload, nn_payload);
return srs_success;
}
SrsRtpRawNALUs::SrsRtpRawNALUs()
{
cursor = 0;
nn_bytes = 0;
}
SrsRtpRawNALUs::~SrsRtpRawNALUs()
{
if (true) {
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
srs_freep(p);
}
}
}
void SrsRtpRawNALUs::push_back(SrsSample* sample)
{
if (sample->size <= 0) {
return;
}
if (!nalus.empty()) {
SrsSample* p = new SrsSample();
p->bytes = (char*)"\0\0\1";
p->size = 3;
nn_bytes += 3;
nalus.push_back(p);
}
nn_bytes += sample->size;
nalus.push_back(sample);
}
uint8_t SrsRtpRawNALUs::skip_first_byte()
{
srs_assert (cursor >= 0 && nn_bytes > 0 && cursor < nn_bytes);
cursor++;
return uint8_t(nalus[0]->bytes[0]);
}
srs_error_t SrsRtpRawNALUs::read_samples(vector<SrsSample*>& samples, int packet_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 += packet_size;
int left = packet_size;
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) {
pos -= p->size;
continue;
}
// Now, we are working at the sample.
int nn = srs_min(left, p->size - pos);
srs_assert(nn > 0);
SrsSample* sample = new SrsSample();
samples.push_back(sample);
sample->bytes = p->bytes + pos;
sample->size = nn;
left -= nn;
pos = 0;
}
return srs_success;
}
int SrsRtpRawNALUs::nb_bytes()
{
int size = 0;
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
size += p->size;
}
return size;
}
srs_error_t SrsRtpRawNALUs::encode(SrsBuffer* buf)
{
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);
}
buf->write_bytes(p->bytes, p->size);
}
return srs_success;
}
SrsRtpSTAPPayload::SrsRtpSTAPPayload()
{
nri = (SrsAvcNaluType)0;
}
SrsRtpSTAPPayload::~SrsRtpSTAPPayload()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
srs_freep(p);
}
}
int SrsRtpSTAPPayload::nb_bytes()
{
int size = 1;
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
size += 2 + p->size;
}
return size;
}
srs_error_t SrsRtpSTAPPayload::encode(SrsBuffer* buf)
{
if (!buf->require(1)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
}
// STAP header, RTP payload format for aggregation packets
// @see https://tools.ietf.org/html/rfc6184#section-5.7
uint8_t v = kStapA;
v |= (nri & (~kNalTypeMask));
buf->write_1bytes(v);
// NALUs.
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);
}
buf->write_2bytes(p->size);
buf->write_bytes(p->bytes, p->size);
}
return srs_success;
}
SrsRtpFUAPayload::SrsRtpFUAPayload()
{
start = end = false;
nri = nalu_type = (SrsAvcNaluType)0;
}
SrsRtpFUAPayload::~SrsRtpFUAPayload()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
srs_freep(p);
}
}
int SrsRtpFUAPayload::nb_bytes()
{
int size = 2;
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
size += p->size;
}
return size;
}
srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf)
{
if (!buf->require(2)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
}
// FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8
uint8_t fu_indicate = kFuA;
fu_indicate |= (nri & (~kNalTypeMask));
buf->write_1bytes(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;
}
buf->write_1bytes(fu_header);
// FU payload, @see https://tools.ietf.org/html/rfc6184#section-5.8
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);
}
buf->write_bytes(p->bytes, p->size);
}
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()

View file

@ -26,12 +26,20 @@
#include <srs_core.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_codec.hpp>
#include <string>
const int kRtpHeaderFixedSize = 12;
const uint8_t kRtpMarker = 0x80;
// H.264 nalu header type mask.
const uint8_t kNalTypeMask = 0x1F;
class SrsBuffer;
class SrsRtpRawPayload;
class SrsRtpFUAPayload2;
class SrsRtpHeader
{
@ -42,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;
@ -50,24 +58,158 @@ 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; }
inline void set_padding(bool v) { padding = v; }
};
class SrsRtpPacket2
{
public:
SrsRtpHeader rtp_header;
ISrsEncoder* payload;
int padding;
private:
SrsRtpRawPayload* cache_raw;
SrsRtpFUAPayload2* cache_fua;
int cache_payload;
public:
SrsRtpPacket2();
virtual ~SrsRtpPacket2();
public:
// 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();
virtual srs_error_t encode(SrsBuffer* buf);
};
// Single payload data.
class SrsRtpRawPayload : public ISrsEncoder
{
public:
// 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:
SrsRtpRawPayload();
virtual ~SrsRtpRawPayload();
// interface ISrsEncoder
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
};
// Multiple NALUs, automatically insert 001 between NALUs.
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;
public:
SrsRtpRawNALUs();
virtual ~SrsRtpRawNALUs();
public:
void push_back(SrsSample* sample);
public:
uint8_t skip_first_byte();
// 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();
virtual srs_error_t encode(SrsBuffer* buf);
};
// STAP-A, for multiple NALUs.
class SrsRtpSTAPPayload : public ISrsEncoder
{
public:
// The NRI in NALU type.
SrsAvcNaluType nri;
// 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:
SrsRtpSTAPPayload();
virtual ~SrsRtpSTAPPayload();
// interface ISrsEncoder
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
};
// FU-A, for one NALU with multiple fragments.
// With more than one payload.
class SrsRtpFUAPayload : public ISrsEncoder
{
public:
// The NRI in NALU type.
SrsAvcNaluType nri;
// The FUA header.
bool start;
bool end;
SrsAvcNaluType nalu_type;
// The NALU samples, we manage the samples.
// @remark We only refer to the memory, user must free its bytes.
std::vector<SrsSample*> nalus;
public:
SrsRtpFUAPayload();
virtual ~SrsRtpFUAPayload();
// interface ISrsEncoder
public:
virtual int nb_bytes();
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

View file

@ -209,7 +209,7 @@ srs_error_t do_main(int argc, char** argv)
int main(int argc, char** argv) {
srs_error_t err = do_main(argc, argv);
if (err != srs_success) {
srs_error("Failed, %s", srs_error_desc(err).c_str());
}

View file

@ -548,7 +548,8 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg
// Notify about perf stat.
if (perf) {
perf->perf_mw_on_msgs(nb_msgs_merged_written, bytes_msgs_merged_written, iov_index);
perf->perf_on_msgs(nb_msgs_merged_written);
perf->perf_on_writev_iovs(iov_index);
nb_msgs_merged_written = 0; bytes_msgs_merged_written = 0;
}
@ -576,7 +577,8 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg
// Notify about perf stat.
if (perf) {
perf->perf_mw_on_msgs(nb_msgs_merged_written, bytes_msgs_merged_written, iov_index);
perf->perf_on_msgs(nb_msgs_merged_written);
perf->perf_on_writev_iovs(iov_index);
nb_msgs_merged_written = 0; bytes_msgs_merged_written = 0;
}
@ -627,11 +629,6 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg
if ((er = skt->writev(iovs, 2, NULL)) != srs_success) {
return srs_error_wrap(err, "writev");
}
// Notify about perf stat.
if (perf) {
perf->perf_mw_on_packets(1, payload_size, 2);
}
}
}
@ -4539,6 +4536,11 @@ srs_error_t SrsOnMetaDataPacket::decode(SrsBuffer* stream)
return srs_error_wrap(err, "name");
}
}
// Allows empty body metadata.
if (stream->empty()) {
return err;
}
// the metadata maybe object or ecma array
SrsAmf0Any* any = NULL;

View file

@ -155,11 +155,9 @@ public:
virtual ~ISrsProtocolPerf();
public:
// Stat for packets merged written, nb_msgs is the number of RTMP messages,
// bytes_msgs is the total bytes of RTMP messages, nb_iovs is the total number of iovec.
virtual void perf_mw_on_msgs(int nb_msgs, int bytes_msgs, int nb_iovs) = 0;
// Stat for packets merged written, nb_pkts is the number of or chunk packets,
// bytes_pkts is the total bytes of or chunk packets, nb_iovs is the total number of iovec.
virtual void perf_mw_on_packets(int nb_pkts, int bytes_pkts, int nb_iovs) = 0;
virtual void perf_on_msgs(int nb_msgs) = 0;
// Stat for TCP writev, nb_iovs is the total number of iovec.
virtual void perf_on_writev_iovs(int nb_iovs) = 0;
};
// The protocol provides the rtmp-message-protocol services,

View file

@ -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++) {

View file

@ -462,7 +462,7 @@ VOID TEST(SrsAVCTest, AACMuxSequenceHeader)
codec.sound_rate = SrsAudioSampleRate44100;
codec.sampling_frequency_index = 4;
HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh));
EXPECT_EQ(2, sh.length());
EXPECT_EQ(2, (int)sh.length());
EXPECT_EQ(0x0a, (uint8_t)sh.at(0));
EXPECT_EQ(0x08, (uint8_t)sh.at(1));
}
@ -475,7 +475,7 @@ VOID TEST(SrsAVCTest, AACMuxSequenceHeader)
codec.sound_rate = SrsAudioSampleRate22050;
codec.sampling_frequency_index = 4;
HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh));
EXPECT_EQ(2, sh.length());
EXPECT_EQ(2, (int)sh.length());
EXPECT_EQ(0x0a, (uint8_t)sh.at(0));
EXPECT_EQ(0x08, (uint8_t)sh.at(1));
}

View file

@ -2010,7 +2010,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost)
if (true) {
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF));
EXPECT_EQ(0, conf.get_hls_dispose(""));
EXPECT_EQ(0, (int)conf.get_hls_dispose(""));
EXPECT_EQ(10 * SRS_UTIME_SECONDS, conf.get_hls_fragment(""));
EXPECT_EQ(60 * SRS_UTIME_SECONDS, conf.get_hls_window(""));
@ -2033,7 +2033,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost)
if (true) {
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF));
EXPECT_EQ(30 * SRS_UTIME_SECONDS, conf.get_queue_length(""));
EXPECT_EQ(0, conf.get_send_min_interval(""));
EXPECT_EQ(0, (int)conf.get_send_min_interval(""));
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost v{play{queue_length 100;send_min_interval 10;}}"));
EXPECT_EQ(100 * SRS_UTIME_SECONDS, conf.get_queue_length("v"));
@ -2042,7 +2042,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost)
if (true) {
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF));
EXPECT_EQ(0, conf.get_vhost_http_remux_fast_cache(""));
EXPECT_EQ(0, (int)conf.get_vhost_http_remux_fast_cache(""));
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost v{http_remux{fast_cache 10;}}"));
EXPECT_EQ(10 * SRS_UTIME_SECONDS, conf.get_vhost_http_remux_fast_cache("v"));
@ -2768,19 +2768,19 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF));
EXPECT_EQ(0, conf.get_stream_casters().size());
EXPECT_EQ(0, (int)conf.get_stream_casters().size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;"));
EXPECT_EQ(1, conf.get_stream_casters().size());
EXPECT_EQ(1, (int)conf.get_stream_casters().size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster; stream_caster;"));
EXPECT_EQ(2, conf.get_stream_casters().size());
EXPECT_EQ(2, (int)conf.get_stream_casters().size());
}
if (true) {
@ -2788,7 +2788,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_FALSE(conf.get_stream_caster_enabled(arr.at(0)));
}
@ -2798,7 +2798,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {enabled off;}"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_FALSE(conf.get_stream_caster_enabled(arr.at(0)));
}
@ -2808,7 +2808,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {enabled on;}"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_TRUE(conf.get_stream_caster_enabled(arr.at(0)));
}
@ -2818,7 +2818,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_TRUE(conf.get_stream_caster_output(arr.at(0)).empty());
}
@ -2828,7 +2828,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {output xxx;}"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("xxx", conf.get_stream_caster_output(arr.at(0)).c_str());
}
@ -2838,9 +2838,9 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(0, conf.get_stream_caster_listen(arr.at(0)));
EXPECT_EQ(0, (int)conf.get_stream_caster_listen(arr.at(0)));
}
if (true) {
@ -2848,7 +2848,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {listen 8080;}"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(8080, conf.get_stream_caster_listen(arr.at(0)));
}
@ -2858,9 +2858,9 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(0, conf.get_stream_caster_rtp_port_min(arr.at(0)));
EXPECT_EQ(0, (int)conf.get_stream_caster_rtp_port_min(arr.at(0)));
}
if (true) {
@ -2868,7 +2868,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {rtp_port_min 8080;}"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(8080, conf.get_stream_caster_rtp_port_min(arr.at(0)));
}
@ -2878,9 +2878,9 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster;"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(0, conf.get_stream_caster_rtp_port_max(arr.at(0)));
EXPECT_EQ(0, (int)conf.get_stream_caster_rtp_port_max(arr.at(0)));
}
if (true) {
@ -2888,7 +2888,7 @@ VOID TEST(ConfigMainTest, CheckStreamCaster)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stream_caster {rtp_port_max 8080;}"));
vector<SrsConfDirective*> arr = conf.get_stream_casters();
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(8080, conf.get_stream_caster_rtp_port_max(arr.at(0)));
}
@ -2912,14 +2912,14 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2)
EXPECT_TRUE(conf.get_debug_srs_upnode("ossrs.net"));
EXPECT_FALSE(conf.get_atc("ossrs.net"));
EXPECT_FALSE(conf.get_atc_auto("ossrs.net"));
EXPECT_EQ(1, conf.get_time_jitter("ossrs.net"));
EXPECT_EQ(1, (int)conf.get_time_jitter("ossrs.net"));
EXPECT_FALSE(conf.get_mix_correct("ossrs.net"));
EXPECT_EQ(30 * SRS_UTIME_SECONDS, conf.get_queue_length("ossrs.net"));
EXPECT_FALSE(conf.get_refer_enabled("ossrs.net"));
EXPECT_TRUE(conf.get_refer_all("ossrs.net") == NULL);
EXPECT_TRUE(conf.get_refer_play("ossrs.net") == NULL);
EXPECT_TRUE(conf.get_refer_publish("ossrs.net") == NULL);
EXPECT_EQ(0, conf.get_in_ack_size("ossrs.net"));
EXPECT_EQ(0, (int)conf.get_in_ack_size("ossrs.net"));
EXPECT_EQ(2500000, conf.get_out_ack_size("ossrs.net"));
EXPECT_EQ(60000, conf.get_chunk_size("ossrs.net"));
EXPECT_TRUE(conf.get_parse_sps("ossrs.net"));
@ -2928,7 +2928,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2)
EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mw_sleep("ossrs.net"));
EXPECT_FALSE(conf.get_realtime_enabled("ossrs.net"));
EXPECT_FALSE(conf.get_tcp_nodelay("ossrs.net"));
EXPECT_EQ(0, conf.get_send_min_interval("ossrs.net"));
EXPECT_EQ(0, (int)conf.get_send_min_interval("ossrs.net"));
EXPECT_FALSE(conf.get_reduce_sequence_header("ossrs.net"));
EXPECT_EQ(20000000, conf.get_publish_1stpkt_timeout("ossrs.net"));
EXPECT_EQ(5000000, conf.get_publish_normal_timeout("ossrs.net"));
@ -3065,7 +3065,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2)
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{play{time_jitter zero;}}"));
EXPECT_EQ(2, conf.get_time_jitter("ossrs.net"));
EXPECT_EQ(2, (int)conf.get_time_jitter("ossrs.net"));
}
if (true) {
@ -3132,7 +3132,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig3)
EXPECT_FALSE(conf.get_vhost_edge_token_traverse("ossrs.net"));
EXPECT_STREQ("[vhost]", conf.get_vhost_edge_transform_vhost("ossrs.net").c_str());
EXPECT_FALSE(conf.get_vhost_origin_cluster("ossrs.net"));
EXPECT_EQ(0, conf.get_vhost_coworkers("ossrs.net").size());
EXPECT_EQ(0, (int)conf.get_vhost_coworkers("ossrs.net").size());
EXPECT_FALSE(conf.get_security_enabled("ossrs.net"));
EXPECT_TRUE(conf.get_security_rules("ossrs.net") == NULL);
}
@ -3152,7 +3152,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig3)
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{cluster{coworkers xxx;}}"));
EXPECT_EQ(1, conf.get_vhost_coworkers("ossrs.net").size());
EXPECT_EQ(1, (int)conf.get_vhost_coworkers("ossrs.net").size());
}
if (true) {
@ -3286,14 +3286,14 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
EXPECT_TRUE(conf.get_transcode("ossrs.net", "") == NULL);
EXPECT_FALSE(conf.get_transcode_enabled(conf.get_transcode("ossrs.net", "")));
EXPECT_TRUE(conf.get_transcode_ffmpeg(conf.get_transcode("ossrs.net", "")).empty());
EXPECT_EQ(0, conf.get_transcode_engines(conf.get_transcode("ossrs.net", "")).size());
EXPECT_EQ(0, (int)conf.get_transcode_engines(conf.get_transcode("ossrs.net", "")).size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{output xxx;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("xxx", conf.get_engine_output(arr.at(0)).c_str());
}
@ -3301,7 +3301,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{oformat flv;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("flv", conf.get_engine_oformat(arr.at(0)).c_str());
}
@ -3309,15 +3309,15 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{aparams {i;}}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
EXPECT_EQ(1, conf.get_engine_aparams(arr.at(0)).size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1, (int)conf.get_engine_aparams(arr.at(0)).size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{achannels 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_achannels(arr.at(0)));
}
@ -3325,7 +3325,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{asample_rate 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_asample_rate(arr.at(0)));
}
@ -3333,7 +3333,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{abitrate 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_abitrate(arr.at(0)));
}
@ -3341,7 +3341,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{acodec aac;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("aac", conf.get_engine_acodec(arr.at(0)).c_str());
}
@ -3349,15 +3349,15 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vparams {t;}}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
EXPECT_EQ(1, conf.get_engine_vparams(arr.at(0)).size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1, (int)conf.get_engine_vparams(arr.at(0)).size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vpreset main;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("main", conf.get_engine_vpreset(arr.at(0)).c_str());
}
@ -3365,7 +3365,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vprofile main;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("main", conf.get_engine_vprofile(arr.at(0)).c_str());
}
@ -3373,7 +3373,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vthreads 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_vthreads(arr.at(0)));
}
@ -3381,7 +3381,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vheight 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_vheight(arr.at(0)));
}
@ -3389,7 +3389,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vwidth 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_vwidth(arr.at(0)));
}
@ -3397,7 +3397,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vfps 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_vfps(arr.at(0)));
}
@ -3405,7 +3405,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vbitrate 1000;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1000, conf.get_engine_vbitrate(arr.at(0)));
}
@ -3413,7 +3413,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vcodec x264;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("x264", conf.get_engine_vcodec(arr.at(0)).c_str());
}
@ -3421,23 +3421,23 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vfilter {i;}}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
EXPECT_EQ(1, conf.get_engine_vfilter(arr.at(0)).size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1, (int)conf.get_engine_vfilter(arr.at(0)).size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{vfilter {i logo.png;}}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
EXPECT_EQ(2, conf.get_engine_vfilter(arr.at(0)).size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(2, (int)conf.get_engine_vfilter(arr.at(0)).size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{iformat mp4;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_STREQ("mp4", conf.get_engine_iformat(arr.at(0)).c_str());
}
@ -3445,15 +3445,15 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{perfile {re;}}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
EXPECT_EQ(1, conf.get_engine_perfile(arr.at(0)).size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_EQ(1, (int)conf.get_engine_perfile(arr.at(0)).size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine{enabled on;}}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
EXPECT_TRUE(conf.get_engine_enabled(arr.at(0)));
}
@ -3461,7 +3461,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig4)
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{transcode xxx{engine;}}"));
vector<SrsConfDirective*> arr = conf.get_transcode_engines(conf.get_transcode("ossrs.net", "xxx"));
ASSERT_EQ(1, arr.size());
ASSERT_EQ(1, (int)arr.size());
}
if (true) {
@ -3492,13 +3492,13 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{exec{enabled on;publish xxx;}}"));
EXPECT_TRUE(conf.get_exec("ossrs.net") != NULL);
EXPECT_TRUE(conf.get_exec_enabled("ossrs.net"));
EXPECT_EQ(1, conf.get_exec_publishs("ossrs.net").size());
EXPECT_EQ(1, (int)conf.get_exec_publishs("ossrs.net").size());
}
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "vhost ossrs.net{ingest xxx{enabled on;ffmpeg xxx2;input{type xxx3;url xxx4;}}}"));
EXPECT_EQ(1, conf.get_ingesters("ossrs.net").size());
EXPECT_EQ(1, (int)conf.get_ingesters("ossrs.net").size());
ASSERT_TRUE(conf.get_ingest_by_id("ossrs.net", "xxx") != NULL);
EXPECT_TRUE(conf.get_ingest_enabled(conf.get_ingest_by_id("ossrs.net", "xxx")));
EXPECT_STREQ("xxx2", conf.get_ingest_ffmpeg(conf.get_ingest_by_id("ossrs.net", "xxx")).c_str());
@ -3584,7 +3584,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
EXPECT_STREQ("xxx2", conf.get_dvr_plan("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_dvr_duration("ossrs.net"));
EXPECT_TRUE(conf.get_dvr_wait_keyframe("ossrs.net"));
EXPECT_EQ(1, conf.get_dvr_time_jitter("ossrs.net"));
EXPECT_EQ(1, (int)conf.get_dvr_time_jitter("ossrs.net"));
}
if (true) {
@ -3637,7 +3637,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
if (true) {
MockSrsConfig conf;
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "stats{network 0;disk xxx;}"));
EXPECT_EQ(0, conf.get_stats_network());
EXPECT_EQ(0, (int)conf.get_stats_network());
EXPECT_TRUE(conf.get_stats_disk_device() != NULL);
}
}

View file

@ -4869,20 +4869,20 @@ VOID TEST(KernelMP4Test, CoverMP4CodecSingleFrame)
// Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
// Frame group #0
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
}
@ -4984,20 +4984,20 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleVideos)
// Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
// Frames order by dts asc.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(40, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(40, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
}
}
@ -5082,24 +5082,24 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleCTTs)
// Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
// Frames order by dts asc.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(40, (int)dts); EXPECT_EQ(80, (int)pts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(40, (int)dts); EXPECT_EQ(80, (int)pts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(80, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(80, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
}
}
@ -5194,28 +5194,28 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleAVs)
// Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(41, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(2, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_EQ(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
// Frames order by dts asc.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(0, (int)dts); EXPECT_EQ(87, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(20, (int)dts); EXPECT_EQ(87, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(20, (int)dts); EXPECT_EQ(87, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeSOUN, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample));
EXPECT_EQ(40, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
EXPECT_EQ(40, (int)dts); EXPECT_EQ(40, (int)pts); EXPECT_EQ(127, (int)nb_sample); EXPECT_EQ(SrsMp4HandlerTypeVIDE, ht); EXPECT_NE(SrsAudioAacFrameTraitSequenceHeader, ct);
srs_freepa(sample);
}
}
@ -5338,3 +5338,16 @@ VOID TEST(KernelMP4Test, CoverMP4M2tsSegmentEncoder)
HELPER_EXPECT_SUCCESS(enc.flush(dts));
}
VOID TEST(KernelUtilityTest, CoverStringAssign)
{
string sps = "SRS";
ASSERT_STREQ("SRS", sps.c_str());
sps.assign("Hello", 5);
ASSERT_STREQ("Hello", sps.c_str());
sps.assign("World", 0);
ASSERT_EQ(0, (int)sps.length());
ASSERT_STREQ("", sps.c_str());
}

View file

@ -5855,7 +5855,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
HELPER_EXPECT_SUCCESS(parser.parse("HelloGET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n\r\nWorld"));
EXPECT_EQ(80, (int)parser.parsed);
EXPECT_EQ(0, (int)parser.parser->nread);
EXPECT_EQ(0, parser.parser->content_length);
EXPECT_EQ(0, (int)parser.parser->content_length);
}
if (true) {
@ -5864,7 +5864,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n\r\nHel"));
EXPECT_EQ(73, (int)parser.parsed);
EXPECT_EQ(0, (int)parser.parser->nread);
EXPECT_EQ(2, parser.parser->content_length);
EXPECT_EQ(2, (int)parser.parser->content_length);
}
if (true) {
@ -5881,7 +5881,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 34, nparsed = 34, nread = 34
HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHo"));
EXPECT_EQ(34, (int)parser.parsed);
EXPECT_EQ(34, parser.parser->nread);
EXPECT_EQ(34, (int)parser.parser->nread);
// size = 41, nparsed = 41, nread = 0
HELPER_EXPECT_SUCCESS(parser.parse("st: ossrs.net\r\nContent-Length: 5\r\n\r\nHello"));
@ -5894,7 +5894,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 41, nparsed = 41, nread = 41
HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: oss"));
EXPECT_EQ(41, (int)parser.parsed);
EXPECT_EQ(41, parser.parser->nread);
EXPECT_EQ(41, (int)parser.parser->nread);
// size = 34, nparsed = 34, nread = 0
HELPER_EXPECT_SUCCESS(parser.parse("rs.net\r\nContent-Length: 5\r\n\r\nHello"));
@ -5907,7 +5907,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 48, nparsed = 48, nread = 48
HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r"));
EXPECT_EQ(48, (int)parser.parsed);
EXPECT_EQ(48, parser.parser->nread);
EXPECT_EQ(48, (int)parser.parser->nread);
// size = 27, nparsed = 27, nread = 0
HELPER_EXPECT_SUCCESS(parser.parse("\nContent-Length: 5\r\n\r\nHello"));
@ -5920,7 +5920,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 68, nparsed = 68, nread = 68
HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n"));
EXPECT_EQ(68, (int)parser.parsed);
EXPECT_EQ(68, parser.parser->nread);
EXPECT_EQ(68, (int)parser.parser->nread);
// size = 7, nparsed = 7, nread = 0
HELPER_EXPECT_SUCCESS(parser.parse("\r\nHello"));
@ -5933,7 +5933,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 69, nparsed = 69, nread = 69
HELPER_EXPECT_SUCCESS(parser.parse("GET /gslb/v1/versions HTTP/1.1\r\nHost: ossrs.net\r\nContent-Length: 5\r\n\r"));
EXPECT_EQ(69, (int)parser.parsed);
EXPECT_EQ(69, parser.parser->nread);
EXPECT_EQ(69, (int)parser.parser->nread);
// size = 6, nparsed = 6, nread = 0
HELPER_EXPECT_SUCCESS(parser.parse("\nHello"));
@ -5954,12 +5954,12 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// nparsed = 2, size = 2, nread = 2
HELPER_EXPECT_SUCCESS(parser.parse("GE"));
EXPECT_EQ(2, (int)parser.parsed);
EXPECT_EQ(2, parser.parser->nread);
EXPECT_EQ(2, (int)parser.parser->nread);
// size = 0, nparsed = 1, nread=2
HELPER_EXPECT_FAILED(parser.parse(""));
EXPECT_EQ(1, (int)parser.parsed);
EXPECT_EQ(2, parser.parser->nread);
EXPECT_EQ(2, (int)parser.parser->nread);
}
if (true) {
@ -5967,12 +5967,12 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 2, nparsed = 2, nread = 2
HELPER_EXPECT_SUCCESS(parser.parse("GE"));
EXPECT_EQ(2, (int)parser.parsed);
EXPECT_EQ(2, parser.parser->nread);
EXPECT_EQ(2, (int)parser.parser->nread);
// size = 1, nparsed = 0, nread = 3
HELPER_EXPECT_FAILED(parser.parse("X"));
EXPECT_EQ(0, (int)parser.parsed);
EXPECT_EQ(3, parser.parser->nread);
EXPECT_EQ(3, (int)parser.parser->nread);
}
if (true) {
@ -5980,12 +5980,12 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 2, nparsed = 2, nread = 2
HELPER_EXPECT_SUCCESS(parser.parse("GE"));
EXPECT_EQ(2, (int)parser.parsed);
EXPECT_EQ(2, parser.parser->nread);
EXPECT_EQ(2, (int)parser.parser->nread);
// size = 1, nparsed = 1, nread = 3
HELPER_EXPECT_SUCCESS(parser.parse("T"));
EXPECT_EQ(1, (int)parser.parsed);
EXPECT_EQ(3, parser.parser->nread);
EXPECT_EQ(3, (int)parser.parser->nread);
}
if (true) {
@ -5993,7 +5993,7 @@ VOID TEST(ProtocolHTTPTest, HTTPParser)
// size = 3, nparsed = 3, nread = 3
HELPER_EXPECT_SUCCESS(parser.parse("GET"));
EXPECT_EQ(3, (int)parser.parsed);
EXPECT_EQ(3, parser.parser->nread);
EXPECT_EQ(3, (int)parser.parser->nread);
}
}