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:
commit
65b5081c7d
51 changed files with 3396 additions and 1076 deletions
|
@ -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
|
||||
|
|
8
trunk/3rdparty/st-srs/README.md
vendored
8
trunk/3rdparty/st-srs/README.md
vendored
|
@ -22,6 +22,8 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche
|
|||
- [x] Patch [st.osx10.14.build.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/6.st.osx10.14.build.patch), for osx 10.14 build.
|
||||
- [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8).
|
||||
- [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9).
|
||||
- [x] Support OSX for Apple Darwin, macOS, [#11](https://github.com/ossrs/state-threads/issues/11).
|
||||
- [x] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12).
|
||||
|
||||
## Docs
|
||||
|
||||
|
@ -85,4 +87,10 @@ Important cli options:
|
|||
1. `--track-origins=<yes|no> [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem.
|
||||
1. `--show-reachable=<yes|no> , --show-possibly-lost=<yes|no>`, to show the using memory.
|
||||
|
||||
## Analysis
|
||||
|
||||
1. About setjmp and longjmp, read [setjmp](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-setjmp.jpg).
|
||||
1. About the stack structure, read [stack](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-stack.jpg)
|
||||
1. About asm code comments, read [#91d530e](https://github.com/ossrs/state-threads/commit/91d530e#diff-ed9428b14ff6afda0e9ab04cc91d4445R25).
|
||||
|
||||
Winlin 2016
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
12
trunk/configure
vendored
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
97
trunk/scripts/perf_gso.py
Executable 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']),
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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*)×tamp;
|
||||
*p++ = pp[3];
|
||||
*p++ = pp[2];
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
|
||||
// The SSRC, 4 bytes.
|
||||
pp = (char*)&ssrc;
|
||||
*p++ = pp[3];
|
||||
*p++ = pp[2];
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
|
||||
// The CSRC list: 0 to 15 items, each is 4 bytes.
|
||||
for (size_t i = 0; i < cc; ++i) {
|
||||
stream->write_4bytes(csrc[i]);
|
||||
pp = (char*)&csrc[i];
|
||||
*p++ = pp[3];
|
||||
*p++ = pp[2];
|
||||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
}
|
||||
|
||||
// TODO: Write exteinsion field.
|
||||
if (extension) {
|
||||
}
|
||||
|
||||
// Consume the data.
|
||||
stream->skip(p - op);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue