1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-15 04:42:04 +00:00

Merge branch 'feature/rtc' into develop

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

View file

@ -149,7 +149,6 @@ For previous versions, please read:
- [ ] Support publishing stream by WebRTC, [#307][bug #307]. - [ ] Support publishing stream by WebRTC, [#307][bug #307].
- [ ] Support change user to run SRS, [#1111][bug #1111]. - [ ] Support change user to run SRS, [#1111][bug #1111].
- [ ] Support HLS variant, [#463][bug #463]. - [ ] 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. > 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 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-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, 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 * v4.0, 2020-04-04, For [#307][bug #307], refine RTC latency from 600ms to 200ms. 4.0.20

View file

@ -22,6 +22,8 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche
- [x] Patch [st.osx10.14.build.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/6.st.osx10.14.build.patch), for osx 10.14 build. - [x] 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] 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] 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 ## 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. `--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. 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 Winlin 2016

View file

@ -171,6 +171,12 @@ else
srs_undefine_macro "SRS_AUTO_HAS_SENDMMSG" $SRS_AUTO_HEADERS_H srs_undefine_macro "SRS_AUTO_HAS_SENDMMSG" $SRS_AUTO_HEADERS_H
fi 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 # prefix
echo "" >> $SRS_AUTO_HEADERS_H echo "" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H echo "#define SRS_AUTO_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H

View file

@ -84,15 +84,6 @@ function Ubuntu_prepare()
echo "The unzip is installed." echo "The unzip is installed."
fi 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 if [[ $SRS_VALGRIND == YES ]]; then
valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
echo "Installing valgrind." echo "Installing valgrind."
@ -171,13 +162,6 @@ function Centos_prepare()
echo "The unzip is installed." echo "The unzip is installed."
fi 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 if [[ $SRS_VALGRIND == YES ]]; then
valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
echo "Installing valgrind." echo "Installing valgrind."
@ -230,15 +214,16 @@ function OSX_prepare()
fi fi
OS_IS_OSX=YES OS_IS_OSX=YES
echo "OSX detected, install tools if needed"
# requires the osx when os # requires the osx when os
if [ $OS_IS_OSX = YES ]; then if [ $OS_IS_OSX = YES ]; then
if [ $SRS_OSX = NO ]; then if [ $SRS_OSX = NO ]; then
echo "OSX detected, must specifies the --osx" echo "OSX detected, please use: ./configure --osx"
exit 1 exit 1
fi fi
fi fi
echo "OSX detected, install tools if needed"
brew --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then brew --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
echo "install brew" echo "install brew"
echo "ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"" echo "ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\""
@ -281,6 +266,10 @@ function OSX_prepare()
echo "install unzip success" echo "install unzip success"
fi 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" echo "OSX install tools success"
return 0 return 0
} }
@ -614,9 +603,16 @@ fi
##################################################################################### #####################################################################################
if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then
FFMPEG_OPTIONS="" FFMPEG_OPTIONS=""
# If disable nasm, disable all ASMs.
if [[ $SRS_NASM == NO ]]; then if [[ $SRS_NASM == NO ]]; then
FFMPEG_OPTIONS="--disable-asm --disable-x86asm --disable-inline-asm" FFMPEG_OPTIONS="--disable-asm --disable-x86asm --disable-inline-asm"
fi 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 if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg/lib/libavcodec.a ]]; then
echo "The ffmpeg-4.2-fit is ok."; echo "The ffmpeg-4.2-fit is ok.";
else 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-programs --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \
--disable-avdevice --disable-avformat --disable-swscale --disable-postproc --disable-avfilter --disable-network \ --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-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-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-cuda-llvm --disable-cuvid \
--disable-avfoundation --disable-securetransport --disable-iconv --disable-lzma --disable-sdl2 --disable-everything \ --disable-d3d11va --disable-dxva2 --disable-ffnvcodec --disable-nvdec --disable-nvenc --disable-v4l2-m2m --disable-vaapi \
--enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm --enable-decoder=libopus --enable-encoder=aac \ --disable-vdpau --disable-appkit --disable-coreimage --disable-avfoundation --disable-securetransport --disable-iconv \
--enable-encoder=opus --enable-encoder=libopus --enable-libopus && --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 && make ${SRS_JOBS} && make install &&
cd .. && rm -rf ffmpeg && ln -sf ffmpeg-4.2-fit/${SRS_PLATFORM}/_release ffmpeg cd .. && rm -rf ffmpeg && ln -sf ffmpeg-4.2-fit/${SRS_PLATFORM}/_release ffmpeg
) )

View file

@ -122,6 +122,7 @@ SRS_NASM=YES
SRS_SRTP_ASM=YES SRS_SRTP_ASM=YES
SRS_SENDMMSG=YES SRS_SENDMMSG=YES
SRS_HAS_SENDMMSG=YES SRS_HAS_SENDMMSG=YES
SRS_DEBUG=NO
##################################################################################### #####################################################################################
# menu # menu
@ -162,6 +163,7 @@ Features:
--prefix=<path> The absolute installation path for srs. Default: $SRS_PREFIX --prefix=<path> The absolute installation path for srs. Default: $SRS_PREFIX
--static Whether add '-static' to link options. --static Whether add '-static' to link options.
--gcov Whether enable the GCOV compiler 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. --jobs[=N] Allow N jobs at once; infinite jobs with no arg.
Used for make in the configure, for example, to make ffmpeg. Used for make in the configure, for example, to make ffmpeg.
--log-verbose Whether enable the log verbose level. default: no. --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-info) SRS_LOG_INFO=YES ;;
--log-trace) SRS_LOG_TRACE=YES ;; --log-trace) SRS_LOG_TRACE=YES ;;
--gcov) SRS_GCOV=YES ;; --gcov) SRS_GCOV=YES ;;
--debug) SRS_DEBUG=YES ;;
--arm) SRS_CROSS_BUILD=YES ;; --arm) SRS_CROSS_BUILD=YES ;;
--mips) SRS_CROSS_BUILD=YES ;; --mips) SRS_CROSS_BUILD=YES ;;
@ -566,6 +569,7 @@ function apply_user_detail_options() {
# Detect whether has sendmmsg. # Detect whether has sendmmsg.
# @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html # @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 "#include <sys/socket.h>" > ${SRS_OBJS}/_tmp_sendmmsg_detect.c
echo "int main(int argc, char** argv) {" >> ${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 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_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_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_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_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_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 if [[ $SRS_TOOL_CC != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cc=$SRS_TOOL_CC"; fi

View file

@ -430,6 +430,34 @@ rtc_server {
# @remark Should always turn it on, or Chrome will fail. # @remark Should always turn it on, or Chrome will fail.
# default: on # default: on
encrypt 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 { vhost rtc.vhost.srs.com {
@ -456,12 +484,17 @@ vhost rtc.vhost.srs.com {
stun_strict_check on; stun_strict_check on;
} }
# whether enable min delay mode for vhost. # whether enable min delay mode for vhost.
# For RTC, we recommend to set to on. # default: on, for RTC.
min_latency on; min_latency on;
play { play {
# set the MW(merged-write) latency in ms. # 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; 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. # SRS always set mw on, so we just set the latency value.
# the latency of stream >= mw_latency + mr_latency # the latency of stream >= mw_latency + mr_latency
# the value recomment is [300, 1800] # the value recomment is [300, 1800]
# default: 350 (for RTMP/HTTP-FLV) # @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config.
# default: 0 (for WebRTC) # default: 350 (For RTMP/HTTP-FLV)
# default: 0 (For WebRTC)
mw_latency 350; 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, # the minimal packets send interval in ms,
# used to control the ndiff of stream by srs_rtmp_dump, # used to control the ndiff of stream by srs_rtmp_dump,
# for example, some device can only accept some stream which # for example, some device can only accept some stream which
@ -748,6 +788,7 @@ vhost mrw.srs.com {
# @see play.srs.com # @see play.srs.com
play { play {
mw_latency 350; mw_latency 350;
mw_msgs 8;
} }
# @see publish.srs.com # @see publish.srs.com
@ -767,6 +808,7 @@ vhost min.delay.com {
# @see play.srs.com # @see play.srs.com
play { play {
mw_latency 100; mw_latency 100;
mw_msgs 4;
gop_cache off; gop_cache off;
queue_length 10; queue_length 10;
} }
@ -795,6 +837,7 @@ vhost stream.control.com {
# @see play.srs.com # @see play.srs.com
play { play {
mw_latency 100; mw_latency 100;
mw_msgs 4;
queue_length 10; queue_length 10;
send_min_interval 10.0; send_min_interval 10.0;
reduce_sequence_header on; reduce_sequence_header on;

12
trunk/configure vendored
View file

@ -444,7 +444,7 @@ mv ${SRS_WORKDIR}/${SRS_MAKEFILE} ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk
# generate phony header # generate phony header
cat << END > ${SRS_WORKDIR}/${SRS_MAKEFILE} 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: 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 .PHONY: st ffmpeg
# install prefix. # install prefix.
@ -481,6 +481,8 @@ help:
@echo " clean_openssl Remove the openssl cache." @echo " clean_openssl Remove the openssl cache."
@echo " clean_srtp2 Remove the libsrtp2 cache." @echo " clean_srtp2 Remove the libsrtp2 cache."
@echo " clean_opus Remove the opus 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 "For example:"
@echo " make" @echo " make"
@echo " make help" @echo " make help"
@ -519,6 +521,14 @@ clean_opus:
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf opus-1.3.1) (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf opus-1.3.1)
@echo "Please rebuild opus by: ./configure" @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: clean_nginx:
(cd ${SRS_OBJS_DIR} && rm -rf nginx) (cd ${SRS_OBJS_DIR} && rm -rf nginx)

View file

@ -207,6 +207,14 @@ function build_default_hls_url() {
} }
function build_default_rtc_url(query) { 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 server = (!query.server)? window.location.hostname:query.server;
var vhost = (!query.vhost)? window.location.hostname:query.vhost; var vhost = (!query.vhost)? window.location.hostname:query.vhost;
var app = (!query.app)? "live":query.app; var app = (!query.app)? "live":query.app;

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

@ -0,0 +1,97 @@
#!/usr/bin/python
'''
The MIT License (MIT)
Copyright (c) 2013-2016 SRS(ossrs)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''
import urllib, sys, json
url = "http://localhost:1985/api/v1/perf"
if len(sys.argv) < 2:
print "Usage: %s <url>"%(sys.argv[0])
print "For example:"
print " %s http://localhost:1985/api/v1/perf"%(sys.argv[0])
sys.exit(-1)
url = sys.argv[1]
print "Open %s"%(url)
f = urllib.urlopen(url)
s = f.read()
f.close()
print "Repsonse %s"%(s)
obj = json.loads(s)
print ""
p = obj['data']['dropped']
print('Frame-Dropped: %.1f%s'%(10000.0 * p['rtc_dropeed'] / p['rtc_frames'], '%%'))
p = obj['data']['bytes']
print('Padding-Overload: %.1f%s %dMB'%(10000.0 * p['rtc_padding'] / p['rtc_bytes'], '%%', p['rtc_padding']/1024/1024))
# 2, 3, 5, 9, 16, 32, 64, 128, 256
keys = ['lt_2', 'lt_3', 'lt_5', 'lt_9', 'lt_16', 'lt_32', 'lt_64', 'lt_128', 'lt_256', 'gt_256']
print("\n----------- 1 2 [3,4] [5,8] [9,15] [16,31] [32,63] [64,127] [128,255] [256,+) Packets"),
print ""
print("AV---Frames"),
p = obj['data']['avframes']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),
print ""
print("RTC--Frames"),
p = obj['data']['rtc']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),
print ""
print("RTP-Packets"),
p = obj['data']['rtp']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),
print ""
print("GSO-Packets"),
p = obj['data']['gso']
for k in keys:
k2 = '%s'%(k)
if k2 in p:
print(p[k2]),
else:
print(0),
print(p['nn']),

View file

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

View file

@ -33,6 +33,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#ifdef __linux__
#include <linux/version.h>
#include <sys/utsname.h>
#endif
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@ -1540,6 +1544,11 @@ srs_error_t SrsConfig::reload_conf(SrsConfig* conf)
if ((err = reload_http_stream(old_root)) != srs_success) { if ((err = reload_http_stream(old_root)) != srs_success) {
return srs_error_wrap(err, "http steram");; 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. // TODO: FIXME: support reload stream_caster.
@ -1697,6 +1706,40 @@ srs_error_t SrsConfig::reload_http_stream(SrsConfDirective* old_root)
return err; 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 SrsConfig::reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost)
{ {
srs_error_t err = srs_success; 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++) { for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
string n = conf->at(i)->name; string n = conf->at(i)->name;
if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" 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()); 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++) { for (int j = 0; j < (int)conf->directives.size(); j++) {
string m = conf->at(j)->name; string m = conf->at(j)->name;
if (m != "time_jitter" && m != "mix_correct" && m != "atc" && m != "atc_auto" && m != "mw_latency" 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()); 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 #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* SrsConfig::get_rtc(string vhost)
{ {
SrsConfDirective* conf = get_vhost(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()) { if (!conf || conf->arg0().empty()) {
return DEFAULT; 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) bool SrsConfig::get_realtime_enabled(string vhost, bool is_rtc)

View file

@ -333,6 +333,8 @@ private:
// Reload the http_stream section of config. // Reload the http_stream section of config.
// TODO: FIXME: rename to http_server. // TODO: FIXME: rename to http_server.
virtual srs_error_t reload_http_stream(SrsConfDirective* old_root); 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. // Reload the transcode section of vhost of config.
virtual srs_error_t reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost); virtual srs_error_t reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost);
// Reload the ingest section of vhost of config. // Reload the ingest section of vhost of config.
@ -525,7 +527,20 @@ public:
virtual bool get_rtc_server_ecdsa(); virtual bool get_rtc_server_ecdsa();
virtual int get_rtc_server_sendmmsg(); virtual int get_rtc_server_sendmmsg();
virtual bool get_rtc_server_encrypt(); 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); SrsConfDirective* get_rtc(std::string vhost);
bool get_rtc_enabled(std::string vhost); bool get_rtc_enabled(std::string vhost);
bool get_rtc_bframe_discard(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. // @param vhost, the vhost to get the mw sleep time.
// TODO: FIXME: add utest for mw config. // TODO: FIXME: add utest for mw config.
virtual srs_utime_t get_mw_sleep(std::string vhost, bool is_rtc = false); 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. // Whether min latency mode enabled.
// @param vhost, the vhost to get the min_latency. // @param vhost, the vhost to get the min_latency.
// TODO: FIXME: add utest for min_latency. // TODO: FIXME: add utest for min_latency.

View file

@ -869,6 +869,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
api = prop->to_str(); api = prop->to_str();
} }
// TODO: FIXME: Parse vhost.
// Parse app and stream from streamurl. // Parse app and stream from streamurl.
string app; string app;
string stream_name; string stream_name;
@ -909,6 +910,13 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
request.app = app; request.app = app;
request.stream = stream_name; 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: Maybe need a better name?
// TODO: FIXME: When server enabled, but vhost disabled, should report error. // 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); 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(); SrsStatistic* stat = SrsStatistic::instance();
string target = r->query_get("target"); 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) { if (true) {
SrsJsonObject* p = SrsJsonAny::object(); SrsJsonObject* p = SrsJsonAny::object();
data->set("query", p); data->set("query", p);
p->set("target", SrsJsonAny::str(target.c_str())); 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(); SrsJsonObject* p = SrsJsonAny::object();
data->set("writev", p); data->set("avframes", p);
if ((err = stat->dumps_perf_writev(p)) != srs_success) { 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); int code = srs_error_code(err); srs_error_reset(err);
return srs_api_response_code(w, r, code); 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()); return srs_api_response(w, r, obj->dumps());
} }

View file

@ -660,7 +660,8 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
if ((err = consumer->dump_packets(&msgs, count)) != srs_success) { if ((err = consumer->dump_packets(&msgs, count)) != srs_success) {
return srs_error_wrap(err, "consumer dump packets"); return srs_error_wrap(err, "consumer dump packets");
} }
// TODO: FIXME: Support merged-write wait.
if (count <= 0) { if (count <= 0) {
// Directly use sleep, donot use consumer wait, because we couldn't awake consumer. // Directly use sleep, donot use consumer wait, because we couldn't awake consumer.
srs_usleep(mw_sleep); 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); err = streaming_send_messages(enc, msgs.msgs, count);
} }
// TODO: FIXME: Update the stat.
// free the messages. // free the messages.
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
SrsSharedPtrMessage* msg = msgs.msgs[i]; SrsSharedPtrMessage* msg = msgs.msgs[i];

View file

@ -40,6 +40,7 @@ using namespace std;
#include <srs_kernel_error.hpp> #include <srs_kernel_error.hpp>
#include <srs_app_server.hpp> #include <srs_app_server.hpp>
#include <srs_app_utility.hpp> #include <srs_app_utility.hpp>
#include <srs_kernel_utility.hpp>
// set the max packet size. // set the max packet size.
#define SRS_UDP_MAX_PACKET_SIZE 65535 #define SRS_UDP_MAX_PACKET_SIZE 65535
@ -235,12 +236,21 @@ srs_error_t SrsTcpListener::cycle()
return err; 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; nb_buf = SRS_UDP_MAX_PACKET_SIZE;
buf = new char[nb_buf]; buf = new char[nb_buf];
nread = 0; nread = 0;
handler = h;
lfd = fd; lfd = fd;
fromlen = 0; fromlen = 0;
@ -253,7 +263,7 @@ SrsUdpMuxSocket::~SrsUdpMuxSocket()
SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly() SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly()
{ {
SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(lfd); SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(handler, lfd);
// Don't copy buffer // Don't copy buffer
srs_freepa(sendonly->buf); srs_freepa(sendonly->buf);
@ -339,16 +349,18 @@ std::string SrsUdpMuxSocket::get_peer_id()
return string(id_buf, len); 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; handler = h;
sender = s;
ip = i; ip = i;
port = p; port = p;
lfd = NULL; lfd = NULL;
nb_buf = SRS_UDP_MAX_PACKET_SIZE; nb_buf = SRS_UDP_MAX_PACKET_SIZE;
buf = new char[nb_buf]; buf = new char[nb_buf];
trd = new SrsDummyCoroutine(); trd = new SrsDummyCoroutine();
} }
@ -390,60 +402,108 @@ srs_error_t SrsUdpMuxListener::listen()
void SrsUdpMuxListener::set_socket_buffer() void SrsUdpMuxListener::set_socket_buffer()
{ {
int sndbuf_size = 0; int default_sndbuf = 0;
socklen_t opt_len = sizeof(sndbuf_size); // TODO: FIXME: Config it.
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len); int expect_sndbuf = 1024*1024*10; // 10M
srs_trace("default udp remux socket sndbuf=%d", sndbuf_size); 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 ((r0_sndbuf = setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, sizeof(actual_sndbuf))) < 0) {
if (setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, sizeof(sndbuf_size)) < 0) { srs_warn("set SO_SNDBUF failed, expect=%d, r0=%d", expect_sndbuf, r0_sndbuf);
srs_warn("set sock opt SO_SNDBUFFORCE failed"); }
opt_len = sizeof(actual_sndbuf);
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, &opt_len);
} }
opt_len = sizeof(sndbuf_size); int default_rcvbuf = 0;
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len); // TODO: FIXME: Config it.
srs_trace("udp remux socket sndbuf=%d", sndbuf_size); 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; if ((r0_rcvbuf = setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, sizeof(actual_rcvbuf))) < 0) {
opt_len = sizeof(rcvbuf_size); srs_warn("set SO_RCVBUF failed, expect=%d, r0=%d", expect_rcvbuf, r0_rcvbuf);
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len); }
srs_trace("default udp remux socket rcvbuf=%d", rcvbuf_size);
rcvbuf_size = 1024*1024*10; // 10M opt_len = sizeof(actual_rcvbuf);
if (setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, sizeof(rcvbuf_size)) < 0) { getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, &opt_len);
srs_warn("set sock opt SO_RCVBUFFORCE failed");
} }
opt_len = sizeof(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)",
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len); 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_trace("udp remux socket rcvbuf=%d", rcvbuf_size);
} }
srs_error_t SrsUdpMuxListener::cycle() srs_error_t SrsUdpMuxListener::cycle()
{ {
srs_error_t err = srs_success; 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) { while (true) {
if ((err = trd->pull()) != srs_success) { if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "udp listener"); 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) {
if (nread < 0) { if (nread < 0) {
srs_warn("udp recv error"); srs_warn("udp recv error");
} }
// remux udp never return // remux udp never return
continue; 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 // remux udp never return
srs_warn("udp packet handler error:%s", srs_error_desc(err).c_str()); 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) { if (SrsUdpPacketRecvCycleInterval > 0) {
srs_usleep(SrsUdpPacketRecvCycleInterval); srs_usleep(SrsUdpPacketRecvCycleInterval);

View file

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

View file

@ -112,6 +112,10 @@ SrsPithyPrint::SrsPithyPrint(int _stage_id)
#define SRS_CONSTS_STAGE_EXEC 11 #define SRS_CONSTS_STAGE_EXEC 11
// for the rtc play // for the rtc play
#define SRS_CONSTS_STAGE_RTC_PLAY 12 #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() SrsPithyPrint* SrsPithyPrint::create_rtmp_play()
{ {
@ -173,6 +177,16 @@ SrsPithyPrint* SrsPithyPrint::create_rtc_play()
return new SrsPithyPrint(SRS_CONSTS_STAGE_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() SrsPithyPrint::~SrsPithyPrint()
{ {
leave_stage(); leave_stage();

View file

@ -88,6 +88,9 @@ public:
static SrsPithyPrint* create_http_stream(); static SrsPithyPrint* create_http_stream();
static SrsPithyPrint* create_http_stream_cache(); static SrsPithyPrint* create_http_stream_cache();
static SrsPithyPrint* create_rtc_play(); 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(); virtual ~SrsPithyPrint();
private: private:
// Enter the specified stage, return the client id. // Enter the specified stage, return the client id.

View file

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

View file

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

View file

@ -54,7 +54,7 @@ using namespace std;
#include <srs_app_audio_recode.hpp> #include <srs_app_audio_recode.hpp>
// TODO: Add this function into SrsRtpMux class. // 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; srs_error_t err = srs_success;
@ -62,37 +62,33 @@ srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFor
return err; return err;
} }
if (stream_ptr == NULL) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "adts");
}
if (format->audio->nb_samples != 1) { if (format->audio->nb_samples != 1) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "adts"); return srs_error_new(ERROR_RTC_RTP_MUXER, "adts");
} }
int nb_buf = format->audio->samples[0].size + 7; int nb_buf = format->audio->samples[0].size + 7;
char* buf = new char[nb_buf]; char* buf = new char[nb_buf];
SrsBuffer* stream = new SrsBuffer(buf, nb_buf); SrsBuffer stream(buf, nb_buf);
// TODO: Add comment. // TODO: Add comment.
stream->write_1bytes(0xFF); stream.write_1bytes(0xFF);
stream->write_1bytes(0xF9); 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_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(((format->acodec->aac_channels & 0x03) << 6) | ((nb_buf >> 11) & 0x03));
stream->write_1bytes((nb_buf >> 3) & 0xFF); stream.write_1bytes((nb_buf >> 3) & 0xFF);
stream->write_1bytes(((nb_buf & 0x07) << 5) | 0x1F); stream.write_1bytes(((nb_buf & 0x07) << 5) | 0x1F);
stream->write_1bytes(0xFC); 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; return err;
} }
SrsRtpH264Muxer::SrsRtpH264Muxer() SrsRtpH264Muxer::SrsRtpH264Muxer()
{ {
sequence = 0;
discard_bframe = false; 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; srs_error_t err = srs_success;
if (format->is_avc_sequence_header()) { // If IDR, we will insert SPS/PPS before IDR frame.
sps.assign(format->vcodec->sequenceParameterSetNALUnit.data(), format->vcodec->sequenceParameterSetNALUnit.size()); if (format->video && format->video->has_idr) {
pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size()); shared_frame->set_has_idr(true);
// only collect SPS/PPS. }
// 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; return err;
} }
vector<SrsRtpSharedPacket*> rtp_packet_vec; shared_frame->set_samples(format->video->samples, format->video->nb_samples);
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);
return err; return err;
} }
SrsRtpOpusMuxer::SrsRtpOpusMuxer() SrsRtpOpusMuxer::SrsRtpOpusMuxer()
{ {
sequence = 0; codec = NULL;
timestamp = 0;
transcode = NULL;
} }
SrsRtpOpusMuxer::~SrsRtpOpusMuxer() SrsRtpOpusMuxer::~SrsRtpOpusMuxer()
{ {
if (transcode) { srs_freep(codec);
delete transcode;
transcode = NULL;
}
} }
srs_error_t SrsRtpOpusMuxer::initialize() srs_error_t SrsRtpOpusMuxer::initialize()
{ {
srs_error_t err = srs_success; srs_error_t err = srs_success;
transcode = new SrsAudioRecode(kChannel, kSamplerate); codec = new SrsAudioRecode(kChannel, kSamplerate);
if (!transcode) { if (!codec) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "SrsAacOpus init failed"); 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; 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; srs_error_t err = srs_success;
vector<SrsRtpSharedPacket*> rtp_packet_vec; // Opus packet cache.
static char* opus_payloads[kMaxOpusPackets];
char* data_ptr[kArrayLength]; static bool initialized = false;
static char data_array[kArrayLength][kArrayBuffer]; if (!initialized) {
int elen[kArrayLength], number = 0; initialized = true;
data_ptr[0] = &data_array[0][0]; static char opus_packets_cache[kMaxOpusPackets][kMaxOpusPacketSize];
for (int i = 1; i < kArrayLength; i++) { opus_payloads[0] = &opus_packets_cache[0][0];
data_ptr[i] = data_array[i]; for (int i = 1; i < kMaxOpusPackets; i++) {
opus_payloads[i] = opus_packets_cache[i];
}
} }
SrsSample pkt; // Transcode an aac packet to many opus packets.
pkt.bytes = stream->data(); SrsSample aac;
pkt.size = stream->pos(); 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"); return srs_error_wrap(err, "recode error");
} }
for (int i = 0; i < number; i++) { // Save OPUS packets in shared message.
SrsSample sample; if (nn_opus_packets <= 0) {
sample.size = elen[i]; return err;
sample.bytes = data_ptr[i];
packet_opus(shared_audio, &sample, rtp_packet_vec);
} }
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; nn_max_extra_payload = srs_max(nn_max_extra_payload, p->size);
}
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");
} }
// TODO: FIXME: Why 960? Need Refactoring? shared_audio->set_extra_payloads(samples, nn_opus_packets);
timestamp += 960; shared_audio->set_max_extra_payload(nn_max_extra_payload);
rtp_packet_vec.push_back(rtp_shared_pkt);
return err; return err;
} }
@ -485,17 +330,16 @@ srs_error_t SrsRtc::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
// ignore sequence header // ignore sequence header
srs_assert(format->audio); srs_assert(format->audio);
SrsBuffer* stream = NULL; char* adts_audio = NULL;
SrsAutoFree(SrsBuffer, stream); int nn_adts_audio = 0;
if ((err = aac_raw_append_adts_header(shared_audio, format, &stream)) != srs_success) { // 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"); return srs_error_wrap(err, "aac append header");
} }
if (stream) { if (adts_audio) {
char* stream_data = stream->data(); err = rtp_opus_muxer->transcode(shared_audio, adts_audio, nn_adts_audio);
SrsAutoFreeA(char, stream_data); srs_freep(adts_audio);
return rtp_opus_muxer->frame_to_packet(shared_audio, format, stream);
} }
return err; return err;
@ -522,5 +366,5 @@ srs_error_t SrsRtc::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma
// ignore info frame, // ignore info frame,
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909 // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
srs_assert(format->video); srs_assert(format->video);
return rtp_h264_muxer->frame_to_packet(shared_video, format); return rtp_h264_muxer->filter(shared_video, format);
} }

View file

@ -39,30 +39,15 @@ class SrsOriginHub;
class SrsAudioRecode; class SrsAudioRecode;
class SrsBuffer; class SrsBuffer;
// Rtp packet max payload size, not include rtp header. // The RTP packet max size, should never exceed this size.
// Must left some bytes to payload header, rtp header, udp header, ip header.
const int kRtpMaxPayloadSize = 1200;
const int kRtpPacketSize = 1500; const int kRtpPacketSize = 1500;
// Payload type will rewrite in srs_app_rtc_conn.cpp when send to client. // Payload type will rewrite in srs_app_rtc_conn.cpp when send to client.
const uint8_t kOpusPayloadType = 111; const uint8_t kOpusPayloadType = 111;
const uint8_t kH264PayloadType = 102; 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 kChannel = 2;
const int kSamplerate = 48000; 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. // SSRC will rewrite in srs_app_rtc_conn.cpp when send to client.
const uint32_t kAudioSSRC = 1; const uint32_t kAudioSSRC = 1;
@ -71,39 +56,26 @@ const uint32_t kVideoSSRC = 2;
// TODO: Define interface class like ISrsRtpMuxer // TODO: Define interface class like ISrsRtpMuxer
class SrsRtpH264Muxer class SrsRtpH264Muxer
{ {
private:
uint16_t sequence;
std::string sps;
std::string pps;
public: public:
bool discard_bframe; bool discard_bframe;
public: public:
SrsRtpH264Muxer(); SrsRtpH264Muxer();
virtual ~SrsRtpH264Muxer(); virtual ~SrsRtpH264Muxer();
public: public:
srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); srs_error_t filter(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);
}; };
// TODO: FIXME: It's not a muxer, but a transcoder. // TODO: FIXME: It's not a muxer, but a transcoder.
class SrsRtpOpusMuxer class SrsRtpOpusMuxer
{ {
private: private:
// TODO: FIXME: How to handle timestamp overflow? SrsAudioRecode* codec;
uint32_t timestamp;
uint16_t sequence;
SrsAudioRecode* transcode;
public: public:
SrsRtpOpusMuxer(); SrsRtpOpusMuxer();
virtual ~SrsRtpOpusMuxer(); virtual ~SrsRtpOpusMuxer();
virtual srs_error_t initialize(); virtual srs_error_t initialize();
public: public:
srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream); srs_error_t transcode(SrsSharedPtrMessage* shared_audio, char* adts_audio, int nn_adts_audio);
private:
srs_error_t packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector<SrsRtpSharedPacket*>& rtp_packet_vec);
}; };
class SrsRtc class SrsRtc

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,7 @@
#include <srs_app_hybrid.hpp> #include <srs_app_hybrid.hpp>
#include <srs_app_hourglass.hpp> #include <srs_app_hourglass.hpp>
#include <srs_app_sdp.hpp> #include <srs_app_sdp.hpp>
#include <srs_app_reload.hpp>
#include <string> #include <string>
#include <map> #include <map>
@ -48,6 +49,8 @@ class SrsRtcServer;
class SrsRtcSession; class SrsRtcSession;
class SrsSharedPtrMessage; class SrsSharedPtrMessage;
class SrsSource; class SrsSource;
class SrsRtpPacket2;
class ISrsUdpSender;
const uint8_t kSR = 200; const uint8_t kSR = 200;
const uint8_t kRR = 201; const uint8_t kRR = 201;
@ -98,23 +101,75 @@ public:
srs_error_t initialize(const SrsRequest& req); srs_error_t initialize(const SrsRequest& req);
srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* skt);
srs_error_t on_dtls_application_data(const char* data, const int len); srs_error_t on_dtls_application_data(const char* data, const int len);
public: public:
srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); 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 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 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); srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf);
private: private:
srs_error_t handshake(SrsUdpMuxSocket* udp_mux_skt); srs_error_t handshake(SrsUdpMuxSocket* skt);
private: private:
srs_error_t srtp_initialize(); srs_error_t srtp_initialize();
srs_error_t srtp_send_init(); srs_error_t srtp_send_init();
srs_error_t srtp_recv_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: protected:
SrsCoroutine* trd; SrsCoroutine* trd;
@ -125,13 +180,34 @@ private:
uint32_t audio_ssrc; uint32_t audio_ssrc;
uint16_t video_payload_type; uint16_t video_payload_type;
uint16_t audio_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: public:
SrsUdpMuxSocket* sendonly_ukt; 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: public:
SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid);
virtual ~SrsRtcSenderThread(); virtual ~SrsRtcSenderThread();
public: public:
srs_error_t initialize(const uint32_t& vssrc, const uint32_t& assrc, const uint16_t& v_pt, const uint16_t& a_pt); 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: public:
virtual int cid(); virtual int cid();
public: public:
@ -139,11 +215,21 @@ public:
virtual void stop(); virtual void stop();
virtual void stop_loop(); virtual void stop_loop();
public: public:
virtual srs_error_t cycle(); void update_sendonly_socket(SrsUdpMuxSocket* skt);
public: public:
void update_sendonly_socket(SrsUdpMuxSocket* ukt); virtual srs_error_t cycle();
private: 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 class SrsRtcSession
@ -194,37 +280,75 @@ public:
void switch_to_context(); void switch_to_context();
public: public:
srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req);
srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_rtcp(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_rtcp(SrsUdpMuxSocket* skt);
public: public:
srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt); srs_error_t send_client_hello(SrsUdpMuxSocket* skt);
srs_error_t on_connection_established(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_connection_established(SrsUdpMuxSocket* skt);
srs_error_t start_play(SrsUdpMuxSocket* udp_mux_skt); srs_error_t start_play(SrsUdpMuxSocket* skt);
public: public:
bool is_stun_timeout(); bool is_stun_timeout();
private: private:
srs_error_t check_source(); srs_error_t check_source();
private: 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: private:
srs_error_t on_rtcp_feedback(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* udp_mux_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* udp_mux_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: private:
SrsUdpMuxListener* listener; srs_netfd_t lfd;
SrsHourGlass* timer; SrsRtcServer* server;
private:
SrsCoroutine* trd; SrsCoroutine* trd;
private:
srs_cond_t cond; srs_cond_t cond;
bool waiting_msgs; bool waiting_msgs;
// TODO: FIXME: Support multiple stfd. bool gso;
srs_netfd_t mmstfd; int nn_senders;
std::vector<mmsghdr> mmhdrs; 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: private:
std::map<std::string, SrsRtcSession*> map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) 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) 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 gracefully quit.
// TODO: FIXME: Support reload. // TODO: FIXME: Support reload.
virtual srs_error_t listen_udp(); 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: public:
virtual srs_error_t listen_api(); 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); 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); bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session);
void check_and_clean_timeout_session(); void check_and_clean_timeout_session();
int nn_sessions() { return (int)map_username_session.size(); }
private: private:
srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_stun(SrsUdpMuxSocket* skt);
srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* skt);
private: private:
SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag); SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag);
SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id);
// interface ISrsHourGlass // interface ISrsHourGlass
public: public:
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick); 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. // The RTC server adapter.

View file

@ -116,7 +116,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* svr, srs_netfd_t c, string cip) : SrsConnect
wakable = NULL; wakable = NULL;
mw_sleep = SRS_PERF_MW_SLEEP; mw_sleep = SRS_PERF_MW_SLEEP;
mw_enabled = false; mw_msgs = 0;
realtime = SRS_PERF_MIN_LATENCY_ENABLED; realtime = SRS_PERF_MIN_LATENCY_ENABLED;
send_min_interval = 0; send_min_interval = 0;
tcp_nodelay = false; tcp_nodelay = false;
@ -264,6 +264,10 @@ srs_error_t SrsRtmpConn::on_reload_vhost_play(string vhost)
send_min_interval = v; 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; 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); srs_trace("realtime changed %d=>%d", realtime, realtime_enabled);
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; return err;
} }
@ -689,18 +697,19 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr
SrsMessageArray msgs(SRS_PERF_MW_MSGS); SrsMessageArray msgs(SRS_PERF_MW_MSGS);
bool user_specified_duration_to_stop = (req->duration > 0); bool user_specified_duration_to_stop = (req->duration > 0);
int64_t starttime = -1; int64_t starttime = -1;
// setup the realtime. // setup the realtime.
realtime = _srs_config->get_realtime_enabled(req->vhost); realtime = _srs_config->get_realtime_enabled(req->vhost);
// setup the mw config. // setup the mw config.
// when mw_sleep changed, resize the socket send buffer. // when mw_sleep changed, resize the socket send buffer.
mw_enabled = true; mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime);
change_mw_sleep(_srs_config->get_mw_sleep(req->vhost)); mw_sleep = _srs_config->get_mw_sleep(req->vhost);
set_socket_buffer(mw_sleep);
// initialize the send_min_interval // initialize the send_min_interval
send_min_interval = _srs_config->get_send_min_interval(req->vhost); 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", 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_enabled, realtime, tcp_nodelay); srsu2msi(send_min_interval), srsu2msi(mw_sleep), mw_msgs, realtime, tcp_nodelay);
while (true) { while (true) {
// when source is set to expired, disconnect it. // 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. // wait for message to incoming.
// @see https://github.com/ossrs/srs/issues/251 // @see https://github.com/ossrs/srs/issues/251
// @see https://github.com/ossrs/srs/issues/257 // @see https://github.com/ossrs/srs/issues/257
if (realtime) { consumer->wait(mw_msgs, mw_sleep);
// 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);
}
#endif #endif
// get messages from consumer. // get messages from consumer.
@ -750,9 +753,9 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr
// reportable // reportable
if (pprint->can_print()) { if (pprint->can_print()) {
kbps->sample(); 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(), (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) { if (count <= 0) {
@ -1114,16 +1117,6 @@ srs_error_t SrsRtmpConn::process_play_control_msg(SrsConsumer* consumer, SrsComm
return err; 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() void SrsRtmpConn::set_sock_options()
{ {
SrsRequest* req = info->req; SrsRequest* req = info->req;

View file

@ -102,8 +102,7 @@ private:
srs_utime_t duration; srs_utime_t duration;
// The MR(merged-write) sleep time in srs_utime_t. // The MR(merged-write) sleep time in srs_utime_t.
srs_utime_t mw_sleep; srs_utime_t mw_sleep;
// The MR(merged-write) only enabled for play. int mw_msgs;
int mw_enabled;
// For realtime // For realtime
// @see https://github.com/ossrs/srs/issues/257 // @see https://github.com/ossrs/srs/issues/257
bool realtime; bool realtime;
@ -149,7 +148,6 @@ private:
virtual srs_error_t handle_publish_message(SrsSource* source, SrsCommonMessage* msg); 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_publish_message(SrsSource* source, SrsCommonMessage* msg);
virtual srs_error_t process_play_control_msg(SrsConsumer* consumer, 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(); virtual void set_sock_options();
private: private:
virtual srs_error_t check_edge_token_traverse_auth(); virtual srs_error_t check_edge_token_traverse_auth();

View file

@ -78,6 +78,14 @@ srs_error_t parse_h264_fmtp(const std::string& fmtp, H264SpecificParam& h264_par
if (kv[0] == "profile-level-id") { if (kv[0] == "profile-level-id") {
h264_param.profile_level_id = kv[1]; h264_param.profile_level_id = kv[1];
} else if (kv[0] == "packetization-mode") { } 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]; h264_param.packetization_mode = kv[1];
} else if (kv[0] == "level-asymmetry-allowed") { } else if (kv[0] == "level-asymmetry-allowed") {
h264_param.level_asymmerty_allow = kv[1]; h264_param.level_asymmerty_allow = kv[1];

View file

@ -269,9 +269,17 @@ void SrsMessageQueue::set_queue_size(srs_utime_t queue_size)
max_queue_size = queue_size; 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; 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 (msg->is_av()) {
if (av_start_time == -1) { 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); 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) { while (av_end_time - av_start_time > max_queue_size) {
// notice the caller queue already overflow and shrinked. // notice the caller queue already overflow and shrinked.
if (is_overflow) { if (is_overflow) {
@ -295,7 +301,7 @@ srs_error_t SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg, bool* is_overflow
return err; 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; 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); count = srs_min(max_count, nb_msgs);
SrsSharedPtrMessage** omsgs = msgs.data(); SrsSharedPtrMessage** omsgs = msgs.data();
for (int i = 0; i < count; i++) { memcpy(pmsgs, omsgs, count * sizeof(SrsSharedPtrMessage*));
pmsgs[i] = omsgs[i];
// 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) { if (count >= nb_msgs) {
// the pmsgs is big enough and clear msgs at most time. // the pmsgs is big enough and clear msgs at most time.
msgs.clear(); msgs.clear();
@ -433,6 +441,8 @@ SrsConsumer::SrsConsumer(SrsSource* s, SrsConnection* c)
mw_duration = 0; mw_duration = 0;
mw_waiting = false; mw_waiting = false;
#endif #endif
pass_timestamp = false;
} }
SrsConsumer::~SrsConsumer() SrsConsumer::~SrsConsumer()
@ -466,20 +476,35 @@ srs_error_t SrsConsumer::enqueue(SrsSharedPtrMessage* shared_msg, bool atc, SrsR
srs_error_t err = srs_success; srs_error_t err = srs_success;
SrsSharedPtrMessage* msg = shared_msg->copy(); 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) { if ((err = jitter->correct(msg, ag)) != srs_success) {
return srs_error_wrap(err, "consume message"); 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"); return srs_error_wrap(err, "enqueue message");
} }
#ifdef SRS_PERF_QUEUE_COND_WAIT #ifdef SRS_PERF_QUEUE_COND_WAIT
// fire the mw when msgs is enough. // fire the mw when msgs is enough.
if (mw_waiting) { 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(); srs_utime_t duration = queue->duration();
bool match_min_msgs = queue->size() > mw_min_msgs; 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. // 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"); 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? // TODO: FIXME: Refactor to move to rtp?
// Save the RTP packets for find_rtp_packet() to rtx or restore it. // 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 #endif
if ((err = hls->on_video(msg, format)) != srs_success) { 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); return rtp_queue->find(seq);
} }
SrsMetaCache* SrsSource::cached_meta()
{
return meta;
}
#endif #endif

View file

@ -151,12 +151,13 @@ public:
// Enqueue the message, the timestamp always monotonically. // Enqueue the message, the timestamp always monotonically.
// @param msg, the msg to enqueue, user never free it whatever the return code. // @param msg, the msg to enqueue, user never free it whatever the return code.
// @param is_overflow, whether overflow and shrinked. NULL to ignore. // @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. // Get packets in consumer queue.
// @pmsgs SrsSharedPtrMessage*[], used to store the msgs, user must alloc it. // @pmsgs SrsSharedPtrMessage*[], used to store the msgs, user must alloc it.
// @count the count in array, output param. // @count the count in array, output param.
// @max_count the max count to dequeue, must be positive. // @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. // Dumps packets to consumer, use specified args.
// @remark the atc/tba/tbv/ag are same to SrsConsumer.enqueue(). // @remark the atc/tba/tbv/ag are same to SrsConsumer.enqueue().
virtual srs_error_t dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag); virtual srs_error_t dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag);
@ -203,10 +204,17 @@ private:
int mw_min_msgs; int mw_min_msgs;
srs_utime_t mw_duration; srs_utime_t mw_duration;
#endif #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: public:
SrsConsumer(SrsSource* s, SrsConnection* c); SrsConsumer(SrsSource* s, SrsConnection* c);
virtual ~SrsConsumer(); virtual ~SrsConsumer();
public: public:
// Use pass timestamp mode.
void enable_pass_timestamp() { pass_timestamp = true; }
// Set the size of queue. // Set the size of queue.
virtual void set_queue_size(srs_utime_t queue_size); virtual void set_queue_size(srs_utime_t queue_size);
// when source id changed, notice client to print. // when source id changed, notice client to print.
@ -327,6 +335,7 @@ public:
#ifdef SRS_AUTO_RTC #ifdef SRS_AUTO_RTC
// To find the RTP packet for RTX or restore. // To find the RTP packet for RTX or restore.
// TODO: FIXME: Should queue RTP packets in connection level.
class SrsRtpPacketQueue class SrsRtpPacketQueue
{ {
private: private:
@ -634,6 +643,8 @@ public:
#ifdef SRS_AUTO_RTC #ifdef SRS_AUTO_RTC
// Find rtp packet by sequence // Find rtp packet by sequence
SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq); SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq);
// Get the cached meta, as such the sps/pps.
SrsMetaCache* cached_meta();
#endif #endif
}; };

View file

@ -236,6 +236,8 @@ srs_error_t SrsStatisticClient::dumps(SrsJsonObject* obj)
SrsStatisticCategory::SrsStatisticCategory() SrsStatisticCategory::SrsStatisticCategory()
{ {
nn = 0;
a = 0; a = 0;
b = 0; b = 0;
c = 0; c = 0;
@ -265,8 +267,12 @@ SrsStatistic::SrsStatistic()
perf_iovs = new SrsStatisticCategory(); perf_iovs = new SrsStatisticCategory();
perf_msgs = new SrsStatisticCategory(); perf_msgs = new SrsStatisticCategory();
perf_sys = new SrsStatisticCategory();
perf_sendmmsg = 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() SrsStatistic::~SrsStatistic()
@ -303,8 +309,12 @@ SrsStatistic::~SrsStatistic()
srs_freep(perf_iovs); srs_freep(perf_iovs);
srs_freep(perf_msgs); srs_freep(perf_msgs);
srs_freep(perf_sys);
srs_freep(perf_sendmmsg); 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() SrsStatistic* SrsStatistic::instance()
@ -585,225 +595,202 @@ srs_error_t SrsStatistic::dumps_clients(SrsJsonArray* arr, int start, int count)
return err; 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. perf_on_packets(perf_msgs, nb_msgs);
// 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++;
} }
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. return dumps_perf(perf_msgs, obj);
// a: number of syscalls of msgs.
// b: number of syscalls of pkts.
perf_sys->b++;
} }
srs_error_t SrsStatistic::dumps_perf_writev(SrsJsonObject* obj) void SrsStatistic::perf_on_rtc_packets(int nb_packets)
{ {
srs_error_t err = srs_success; perf_on_packets(perf_rtc, nb_packets);
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;
} }
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. return dumps_perf(perf_rtc, obj);
// a: =1 }
// b: <10
// c: <100 void SrsStatistic::perf_on_rtp_packets(int nb_packets)
// d: <200 {
// e: <300 perf_on_packets(perf_rtp, nb_packets);
// f: <400 }
// g: <500
// h: <600 srs_error_t SrsStatistic::dumps_perf_rtp_packets(SrsJsonObject* obj)
// i: <1000 {
// j: >=1000 return dumps_perf(perf_rtp, obj);
if (nb_msgs == 1) { }
perf_sendmmsg->a++;
} else if (nb_msgs < 10) { void SrsStatistic::perf_on_gso_packets(int nb_packets)
perf_sendmmsg->b++; {
} else if (nb_msgs < 100) { perf_on_packets(perf_gso, nb_packets);
perf_sendmmsg->c++; }
} else if (nb_msgs < 200) {
perf_sendmmsg->d++; srs_error_t SrsStatistic::dumps_perf_gso(SrsJsonObject* obj)
} else if (nb_msgs < 300) { {
perf_sendmmsg->e++; return dumps_perf(perf_gso, obj);
} else if (nb_msgs < 400) { }
perf_sendmmsg->f++;
} else if (nb_msgs < 500) { void SrsStatistic::perf_on_writev_iovs(int nb_iovs)
perf_sendmmsg->g++; {
} else if (nb_msgs < 600) { perf_on_packets(perf_iovs, nb_iovs);
perf_sendmmsg->h++; }
} else if (nb_msgs < 1000) {
perf_sendmmsg->i++; srs_error_t SrsStatistic::dumps_perf_writev_iovs(SrsJsonObject* obj)
} else { {
perf_sendmmsg->j++; 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) 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; srs_error_t err = srs_success;
if (true) { // The range for stat:
SrsJsonObject* p = SrsJsonAny::object(); // 2, 3, 5, 9, 16, 32, 64, 128, 256
obj->set("msgs", p); // 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. obj->set("nn", SrsJsonAny::integer(p->nn));
// 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));
}
return err; return err;
} }

View file

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

View file

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

View file

@ -127,8 +127,12 @@
*/ */
#define SRS_PERF_QUEUE_COND_WAIT #define SRS_PERF_QUEUE_COND_WAIT
#ifdef 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 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 #endif
/** /**
* the default value of vhost for * the default value of vhost for
@ -188,5 +192,27 @@
#define SRS_PERF_GLIBC_MEMORY_CHECK #define SRS_PERF_GLIBC_MEMORY_CHECK
#undef 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 #endif

View file

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

View file

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

View file

@ -31,6 +31,24 @@
class SrsBuffer; 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: * the srs codec, to code and decode object with bytes:
* code: to encode/serialize object to bytes in buffer, * 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. * @remark protocol or amf0 or json should implements this interface.
*/ */
// TODO: FIXME: protocol, amf0, json should implements it. // TODO: FIXME: protocol, amf0, json should implements it.
class ISrsCodec class ISrsCodec : public ISrsEncoder
{ {
public: public:
ISrsCodec(); ISrsCodec();
virtual ~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: public:
/** /**
* decode object from bytes in SrsBuffer. * decode object from bytes in SrsBuffer.
@ -105,7 +113,8 @@ public:
* get data of stream, set by initialize. * get data of stream, set by initialize.
* current bytes = data() + pos() * current bytes = data() + pos()
*/ */
virtual char* data(); inline char* data() { return bytes; }
inline char* head() { return p; }
/** /**
* the total stream size, set by initialize. * the total stream size, set by initialize.
* left bytes = size() - pos(). * left bytes = size() - pos().

View file

@ -32,6 +32,7 @@ using namespace std;
#include <srs_kernel_buffer.hpp> #include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#include <srs_kernel_rtp.hpp>
string srs_video_codec_id2str(SrsVideoCodecId codec) string srs_video_codec_id2str(SrsVideoCodecId codec)
{ {
@ -364,12 +365,58 @@ SrsSample::SrsSample()
{ {
size = 0; size = 0;
bytes = NULL; bytes = NULL;
bframe = false;
} }
SrsSample::~SrsSample() 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() SrsCodecConfig::SrsCodecConfig()
{ {
} }
@ -458,6 +505,7 @@ srs_error_t SrsFrame::add_sample(char* bytes, int size)
SrsSample* sample = &samples[nb_samples++]; SrsSample* sample = &samples[nb_samples++];
sample->bytes = bytes; sample->bytes = bytes;
sample->size = size; sample->size = size;
sample->bframe = false;
return err; 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 SrsVideoFrame::add_sample(char* bytes, int size)
{ {
srs_error_t err = srs_success; srs_error_t err = srs_success;

View file

@ -532,11 +532,18 @@ class SrsSample
public: public:
// The size of unit. // The size of unit.
int size; int size;
// The ptr of unit, user must manage it. // The ptr of unit, user must free it.
char* bytes; char* bytes;
// Whether is B frame.
bool bframe;
public: public:
SrsSample(); 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(); SrsVideoFrame();
virtual ~SrsVideoFrame(); virtual ~SrsVideoFrame();
public: 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. // Add the sample without ANNEXB or IBMF header, or RAW AAC or MP3 data.
virtual srs_error_t add_sample(char* bytes, int size); virtual srs_error_t add_sample(char* bytes, int size);
public: public:

View file

@ -422,7 +422,7 @@ public:
}; };
// Error helpers, should use these functions to new or wrap an error. // 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_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_wrap(err, fmt, ...) SrsCplxError::wrap(__FUNCTION__, __FILE__, __LINE__, err, fmt, ##__VA_ARGS__)
#define srs_error_copy(err) SrsCplxError::copy(err) #define srs_error_copy(err) SrsCplxError::copy(err)

View file

@ -194,8 +194,11 @@ srs_error_t SrsCommonMessage::create(SrsMessageHeader* pheader, char* body, int
return srs_success; 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() SrsSharedMessageHeader::~SrsSharedMessageHeader()
@ -207,6 +210,16 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()
payload = NULL; payload = NULL;
size = 0; size = 0;
shared_count = 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() SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
@ -215,6 +228,17 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
srs_memory_unwatch(payload); srs_memory_unwatch(payload);
#endif #endif
srs_freepa(payload); 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) SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL)
@ -231,12 +255,6 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage()
ptr->shared_count--; 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) srs_error_t SrsSharedPtrMessage::create(SrsCommonMessage* msg)
@ -355,19 +373,30 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy()
copy->payload = ptr->payload; copy->payload = ptr->payload;
copy->size = ptr->size; 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; return copy;
} }
#ifdef SRS_AUTO_RTC #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 #endif

View file

@ -40,6 +40,7 @@ class ISrsReader;
class SrsFileReader; class SrsFileReader;
class SrsPacket; class SrsPacket;
class SrsRtpSharedPacket; class SrsRtpSharedPacket;
class SrsSample;
#define SRS_FLV_TAG_HEADER_SIZE 11 #define SRS_FLV_TAG_HEADER_SIZE 11
#define SRS_FLV_PREVIOUS_TAG_SIZE 4 #define SRS_FLV_PREVIOUS_TAG_SIZE 4
@ -288,10 +289,6 @@ public:
// video/audio packet use raw bytes, no video/audio packet. // video/audio packet use raw bytes, no video/audio packet.
char* payload; char* payload;
#ifdef SRS_AUTO_RTC
std::vector<SrsRtpSharedPacket*> rtp_packets;
#endif
private: private:
class SrsSharedPtrPayload class SrsSharedPtrPayload
{ {
@ -305,6 +302,23 @@ private:
int size; int size;
// The reference count // The reference count
int shared_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: public:
SrsSharedPtrPayload(); SrsSharedPtrPayload();
virtual ~SrsSharedPtrPayload(); virtual ~SrsSharedPtrPayload();
@ -348,7 +362,21 @@ public:
virtual SrsSharedPtrMessage* copy(); virtual SrsSharedPtrMessage* copy();
public: public:
#ifdef SRS_AUTO_RTC #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 #endif
}; };

View file

@ -32,6 +32,15 @@ using namespace std;
#include <srs_kernel_buffer.hpp> #include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.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() SrsRtpHeader::SrsRtpHeader()
{ {
@ -46,27 +55,15 @@ SrsRtpHeader::SrsRtpHeader()
extension_length = 0; extension_length = 0;
} }
SrsRtpHeader::SrsRtpHeader(const SrsRtpHeader& rhs) void SrsRtpHeader::reset()
{ {
operator=(rhs); // We only reset the optional fields, the required field such as ssrc
} // will always be set by user.
padding = false;
SrsRtpHeader& SrsRtpHeader::operator=(const SrsRtpHeader& rhs) extension = false;
{ cc = 0;
padding = rhs.padding; marker = false;
extension = rhs.extension; extension_length = 0;
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;
} }
SrsRtpHeader::~SrsRtpHeader() SrsRtpHeader::~SrsRtpHeader()
@ -77,7 +74,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* stream)
{ {
srs_error_t err = srs_success; srs_error_t err = srs_success;
// TODO: // TODO: FIXME: Implements it.
return err; return err;
} }
@ -86,30 +83,63 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream)
{ {
srs_error_t err = srs_success; 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) { if (padding) {
first |= 0x40; v |= 0x20;
} }
if (extension) { if (extension) {
first |= 0x10; v |= 0x10;
} }
stream->write_1bytes(first); *p++ = v;
uint8_t second = payload_type;
// The marker and payload type, total 1 byte.
v = payload_type;
if (marker) { if (marker) {
payload_type |= kRtpMarker; v |= kRtpMarker;
} }
stream->write_1bytes(second); *p++ = v;
stream->write_2bytes(sequence);
stream->write_4bytes(timestamp); // The sequence number, 2 bytes.
stream->write_4bytes(ssrc); char* pp = (char*)&sequence;
*p++ = pp[1];
*p++ = pp[0];
// The timestamp, 4 bytes.
pp = (char*)&timestamp;
*p++ = pp[3];
*p++ = pp[2];
*p++ = pp[1];
*p++ = pp[0];
// The SSRC, 4 bytes.
pp = (char*)&ssrc;
*p++ = pp[3];
*p++ = pp[2];
*p++ = pp[1];
*p++ = pp[0];
// The CSRC list: 0 to 15 items, each is 4 bytes.
for (size_t i = 0; i < cc; ++i) { 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. // TODO: Write exteinsion field.
if (extension) { if (extension) {
} }
// Consume the data.
stream->skip(p - op);
return err; return err;
} }
@ -118,29 +148,408 @@ size_t SrsRtpHeader::header_size()
return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0); 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() SrsRtpSharedPacket::SrsRtpSharedPacketPayload::SrsRtpSharedPacketPayload()

View file

@ -26,12 +26,20 @@
#include <srs_core.hpp> #include <srs_core.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_codec.hpp>
#include <string> #include <string>
const int kRtpHeaderFixedSize = 12; const int kRtpHeaderFixedSize = 12;
const uint8_t kRtpMarker = 0x80; const uint8_t kRtpMarker = 0x80;
// H.264 nalu header type mask.
const uint8_t kNalTypeMask = 0x1F;
class SrsBuffer; class SrsBuffer;
class SrsRtpRawPayload;
class SrsRtpFUAPayload2;
class SrsRtpHeader class SrsRtpHeader
{ {
@ -42,7 +50,7 @@ private:
bool marker; bool marker;
uint8_t payload_type; uint8_t payload_type;
uint16_t sequence; uint16_t sequence;
int64_t timestamp; int32_t timestamp;
uint32_t ssrc; uint32_t ssrc;
uint32_t csrc[15]; uint32_t csrc[15];
uint16_t extension_length; uint16_t extension_length;
@ -50,24 +58,158 @@ private:
public: public:
SrsRtpHeader(); SrsRtpHeader();
virtual ~SrsRtpHeader(); virtual ~SrsRtpHeader();
SrsRtpHeader(const SrsRtpHeader& rhs); void reset();
SrsRtpHeader& operator=(const SrsRtpHeader& rhs);
public: public:
srs_error_t decode(SrsBuffer* stream); srs_error_t decode(SrsBuffer* stream);
srs_error_t encode(SrsBuffer* stream); srs_error_t encode(SrsBuffer* stream);
public: public:
size_t header_size(); size_t header_size();
public: public:
void set_marker(bool marker); inline void set_marker(bool v) { marker = v; }
bool get_marker() const { return marker; } 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; } 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; } 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; } 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; } 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 class SrsRtpSharedPacket

View file

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

View file

@ -548,7 +548,8 @@ srs_error_t SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msg
// Notify about perf stat. // Notify about perf stat.
if (perf) { 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; 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. // Notify about perf stat.
if (perf) { 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; 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) { if ((er = skt->writev(iovs, 2, NULL)) != srs_success) {
return srs_error_wrap(err, "writev"); 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"); return srs_error_wrap(err, "name");
} }
} }
// Allows empty body metadata.
if (stream->empty()) {
return err;
}
// the metadata maybe object or ecma array // the metadata maybe object or ecma array
SrsAmf0Any* any = NULL; SrsAmf0Any* any = NULL;

View file

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

View file

@ -436,6 +436,8 @@ int srs_sendmmsg(srs_netfd_t stfd, struct mmsghdr *msgvec, unsigned int vlen, in
} }
msgvec->msg_len = r0; msgvec->msg_len = r0;
#else #else
msgvec->msg_len = 0;
int tolen = (int)msgvec->msg_hdr.msg_namelen; int tolen = (int)msgvec->msg_hdr.msg_namelen;
const struct sockaddr* to = (const struct sockaddr*)msgvec->msg_hdr.msg_name; const struct sockaddr* to = (const struct sockaddr*)msgvec->msg_hdr.msg_name;
for (int i = 0; i < (int)msgvec->msg_hdr.msg_iovlen; i++) { for (int i = 0; i < (int)msgvec->msg_hdr.msg_iovlen; i++) {

View file

@ -462,7 +462,7 @@ VOID TEST(SrsAVCTest, AACMuxSequenceHeader)
codec.sound_rate = SrsAudioSampleRate44100; codec.sound_rate = SrsAudioSampleRate44100;
codec.sampling_frequency_index = 4; codec.sampling_frequency_index = 4;
HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); 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(0x0a, (uint8_t)sh.at(0));
EXPECT_EQ(0x08, (uint8_t)sh.at(1)); EXPECT_EQ(0x08, (uint8_t)sh.at(1));
} }
@ -475,7 +475,7 @@ VOID TEST(SrsAVCTest, AACMuxSequenceHeader)
codec.sound_rate = SrsAudioSampleRate22050; codec.sound_rate = SrsAudioSampleRate22050;
codec.sampling_frequency_index = 4; codec.sampling_frequency_index = 4;
HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); 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(0x0a, (uint8_t)sh.at(0));
EXPECT_EQ(0x08, (uint8_t)sh.at(1)); EXPECT_EQ(0x08, (uint8_t)sh.at(1));
} }

View file

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

View file

@ -4869,20 +4869,20 @@ VOID TEST(KernelMP4Test, CoverMP4CodecSingleFrame)
// Sequence header. // Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
// Frame group #0 // Frame group #0
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
} }
@ -4984,20 +4984,20 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleVideos)
// Sequence header. // Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
// Frames order by dts asc. // Frames order by dts asc.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
} }
} }
@ -5082,24 +5082,24 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleCTTs)
// Sequence header. // Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
// Frames order by dts asc. // Frames order by dts asc.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
} }
} }
@ -5194,28 +5194,28 @@ VOID TEST(KernelMP4Test, CoverMP4MultipleAVs)
// Sequence header. // Sequence header.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
// Frames order by dts asc. // Frames order by dts asc.
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_sample)); 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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
HELPER_EXPECT_SUCCESS(dec.read_sample(&ht, &ft, &ct, &dts, &pts, &sample, &nb_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); srs_freepa(sample);
} }
} }
@ -5338,3 +5338,16 @@ VOID TEST(KernelMP4Test, CoverMP4M2tsSegmentEncoder)
HELPER_EXPECT_SUCCESS(enc.flush(dts)); HELPER_EXPECT_SUCCESS(enc.flush(dts));
} }
VOID TEST(KernelUtilityTest, CoverStringAssign)
{
string sps = "SRS";
ASSERT_STREQ("SRS", sps.c_str());
sps.assign("Hello", 5);
ASSERT_STREQ("Hello", sps.c_str());
sps.assign("World", 0);
ASSERT_EQ(0, (int)sps.length());
ASSERT_STREQ("", sps.c_str());
}

View file

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