1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Merge branch 'develop' into 4.0release

This commit is contained in:
winlin 2020-05-12 13:19:51 +08:00
commit c768a8ccd9
86 changed files with 5945 additions and 2276 deletions

View file

@ -55,6 +55,9 @@ docker run -p 1935:1935 -p 1985:1985 -p 8080:8080 \
* Usage: How to delivery HTTP-FLV?([CN][v3_CN_SampleHttpFlv], [EN][v3_EN_SampleHttpFlv])
* Usage: How to delivery HTTP-FLV Cluster?([CN][v3_CN_SampleHttpFlvCluster], [EN][v3_EN_SampleHttpFlvCluster])
* Usage: How to delivery HLS?([CN][v3_CN_SampleHLS], [EN][v3_EN_SampleHLS])
* Usage: How to publish GB28181 to SRS? [#1500](https://github.com/ossrs/srs/issues/1500#issuecomment-606695679)
* Usage: How to play WebRTC from SRS? [#307](https://github.com/ossrs/srs/issues/307#issuecomment-602193458)
* Usage: How to publish SRT(Experimental) to SRS?([CN][v4_CN_SampleSRT], [EN][v4_EN_SampleSRT])
* Usage: How to transcode to h.264+aac for HLS?([CN][v3_CN_SampleTranscode2HLS], [EN][v3_EN_SampleTranscode2HLS])
* Usage: How to transode stream by FFMPEG?([CN][v2_CN_SampleFFMPEG], [EN][v2_EN_SampleFFMPEG])
* Usage: How to forward stream to other servers?([CN][v3_CN_SampleForward], [EN][v3_EN_SampleForward])
@ -62,7 +65,6 @@ docker run -p 1935:1935 -p 1985:1985 -p 8080:8080 \
* Usage: How to ingest file/stream/device to SRS?([CN][v1_CN_SampleIngest], [EN][v1_EN_SampleIngest])
* Usage: How to delivery HLS by SRS HTTP server?([CN][v3_CN_SampleHTTP], [EN][v3_EN_SampleHTTP])
* Usage: How to delivery DASH(Experimental)?([CN][v3_CN_SampleDASH], [EN][v3_EN_SampleDASH])
* Usage: How to transmux SRT(Experimental) to live streaming?([CN][v4_CN_SampleSRT], [EN][v4_EN_SampleSRT])
* Usage: How to publish h.264 raw stream as RTMP? ([CN][v3_CN_SrsLibrtmp2], [EN][v3_EN_SrsLibrtmp2])
* Usage: How to enable multiple processes? ([CN][v3_CN_REUSEPORT], [EN][v3_EN_REUSEPORT])
* Usage: Why SRS? What's the milestones? ([CN][v1_CN_Product], [EN][v1_EN_Product])
@ -157,6 +159,7 @@ For previous versions, please read:
## V4 changes
* v4.0, 2020-04-30, For [#307][bug #307], support publish RTC with passing opus. 4.0.24
* v4.0, 2020-04-14, For [#307][bug #307], support sendmmsg, GSO and reuseport. 4.0.23
* v4.0, 2020-04-05, For [#307][bug #307], SRTP ASM only works with openssl-1.0, auto detect it. 4.0.22
* v4.0, 2020-04-04, Merge RTC and GB28181, with bugs fixed. 4.0.21

View file

@ -4,9 +4,6 @@ http-parser-2.1.zip
nginx-1.5.7.zip
for srs to support hls streaming.
st-1.9.zip
basic framework for srs.
openssl-1.1.0e.zip
openssl-OpenSSL_1_0_2u.tar.gz
openssl for SRS(with-ssl) RTMP complex handshake to delivery h264+aac stream.
@ -35,8 +32,11 @@ gtest-1.6.0.zip
gperftools-2.1.zip
gperf tools for performance benchmark.
state-threads-1.9.1.tar.gz:
patched st from https://github.com/ossrs/state-threads/releases/tag/v1.9.1
st-srs
st-1.9.zip
state-threads
state-threads-1.9.1.tar.gz
Patched ST from https://github.com/ossrs/state-threads
links:
nginx:
@ -44,7 +44,7 @@ links:
http-parser:
https://github.com/joyent/http-parser
state-threads:
http://sourceforge.net/projects/state-threads
https://github.com/ossrs/state-threads
ffmpeg:
http://ffmpeg.org/
http://ffmpeg.org/releases/ffmpeg-3.2.4.tar.gz

View file

@ -189,10 +189,6 @@ OTHER_FLAGS = -Wall
ifeq ($(shell test -f /usr/include/sys/epoll.h && echo yes), yes)
DEFINES += -DMD_HAVE_EPOLL
endif
# For SRS, sendmmsg
ifeq ($(shell grep -qs sendmmsg /usr/include/sys/socket.h && echo yes), yes)
DEFINES += -DMD_HAVE_SENDMMSG -D_GNU_SOURCE
endif
endif
ifeq ($(OS), NETBSD)

View file

@ -742,17 +742,16 @@ int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t
return n;
}
#if defined(MD_HAVE_SENDMMSG) && defined(_GNU_SOURCE)
int st_sendmmsg(st_netfd_t fd, struct mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout)
int st_sendmmsg(st_netfd_t fd, struct st_mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout)
{
#if defined(MD_HAVE_SENDMMSG) && defined(_GNU_SOURCE)
int n;
int left;
struct mmsghdr *p;
left = (int)vlen;
while (left > 0) {
p = msgvec + (vlen - left);
p = (struct mmsghdr*)msgvec + (vlen - left);
if ((n = sendmmsg(fd->osfd, p, left, flags)) < 0) {
if (errno == EINTR)
@ -772,8 +771,30 @@ int st_sendmmsg(st_netfd_t fd, struct mmsghdr *msgvec, unsigned int vlen, int fl
return n;
}
return (int)vlen - left;
}
#else
struct st_mmsghdr *p;
int i, n;
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
for (i = 0; i < (int)vlen; ++i) {
p = msgvec + i;
n = st_sendmsg(fd, &p->msg_hdr, flags, timeout);
if (n < 0) {
// An error is returned only if no datagrams could be sent.
if (i == 0) {
return n;
}
return i + 1;
}
p->msg_len = n;
}
// Returns the number of messages sent from msgvec; if this is less than vlen, the caller can retry with a
// further sendmmsg() call to send the remaining messages.
return vlen;
#endif
}
/*

View file

@ -151,7 +151,15 @@ extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from,
extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout);
extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout);
extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout);
extern int st_sendmmsg(st_netfd_t fd, struct mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout);
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
#include <sys/socket.h>
struct st_mmsghdr {
struct msghdr msg_hdr; /* Message header */
unsigned int msg_len; /* Number of bytes transmitted */
};
extern int st_sendmmsg(st_netfd_t fd, struct st_mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout);
extern st_netfd_t st_open(const char *path, int oflags, mode_t mode);
#ifdef DEBUG

View file

@ -11,11 +11,11 @@ echo "#ifndef SRS_AUTO_HEADER_HPP" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_HEADER_HPP" >> $SRS_AUTO_HEADERS_H
echo "" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_BUILD_TS \"`date +%s`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_BUILD_DATE \"`date \"+%Y-%m-%d %H:%M:%S\"`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_UNAME \"`uname -a`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_USER_CONFIGURE \"${SRS_AUTO_USER_CONFIGURE}\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_CONFIGURE \"${SRS_AUTO_CONFIGURE}\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_BUILD_TS \"`date +%s`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_BUILD_DATE \"`date \"+%Y-%m-%d %H:%M:%S\"`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_UNAME \"`uname -a`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_USER_CONFIGURE \"${SRS_AUTO_USER_CONFIGURE}\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_CONFIGURE \"${SRS_AUTO_CONFIGURE}\"" >> $SRS_AUTO_HEADERS_H
echo "" >> $SRS_AUTO_HEADERS_H
function srs_define_macro()
@ -62,73 +62,79 @@ echo "" >> $SRS_AUTO_HEADERS_H
#####################################################################################
# auto headers in depends.
if [ $SRS_HDS = YES ]; then
srs_define_macro "SRS_AUTO_HDS" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_HDS" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_HDS" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_HDS" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_SRT = YES ]; then
srs_define_macro "SRS_AUTO_SRT" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_SRT" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_SRT" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_SRT" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_RTC = YES ]; then
srs_define_macro "SRS_AUTO_RTC" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_RTC" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_RTC" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_RTC" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_SIMULATOR = YES ]; then
srs_define_macro "SRS_SIMULATOR" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_SIMULATOR" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_GB28181 = YES ]; then
srs_define_macro "SRS_AUTO_GB28181" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_GB28181" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_GB28181" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_GB28181" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_MEM_WATCH = YES ]; then
srs_define_macro "SRS_AUTO_MEM_WATCH" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_MEM_WATCH" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_MEM_WATCH" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_MEM_WATCH" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_UTEST = YES ]; then
srs_define_macro "SRS_AUTO_UTEST" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_UTEST" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_UTEST" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_UTEST" $SRS_AUTO_HEADERS_H
fi
# whatever the FFMPEG tools, if transcode and ingest specified,
# srs always compile the FFMPEG tool stub which used to start the FFMPEG process.
if [ $SRS_FFMPEG_STUB = YES ]; then
srs_define_macro "SRS_AUTO_FFMPEG_STUB" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_FFMPEG_STUB" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_FFMPEG_STUB" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_FFMPEG_STUB" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_GPERF = YES ]; then
srs_define_macro "SRS_AUTO_GPERF" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_GPERF" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_GPERF" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_GPERF" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_GPERF_MC = YES ]; then
srs_define_macro "SRS_AUTO_GPERF_MC" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_GPERF_MC" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_GPERF_MC" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_GPERF_MC" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_GPERF_MD = YES ]; then
srs_define_macro "SRS_AUTO_GPERF_MD" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_GPERF_MD" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_GPERF_MD" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_GPERF_MD" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_GPERF_MP = YES ]; then
srs_define_macro "SRS_AUTO_GPERF_MP" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_GPERF_MP" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_GPERF_MP" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_GPERF_MP" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_GPERF_CP = YES ]; then
srs_define_macro "SRS_AUTO_GPERF_CP" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_GPERF_CP" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_GPERF_CP" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_GPERF_CP" $SRS_AUTO_HEADERS_H
fi
#####################################################################################
@ -136,50 +142,45 @@ fi
#####################################################################################
# for log level compile settings
if [ $SRS_LOG_VERBOSE = YES ]; then
srs_define_macro "SRS_AUTO_VERBOSE" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_VERBOSE" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_VERBOSE" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_VERBOSE" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_LOG_INFO = YES ]; then
srs_define_macro "SRS_AUTO_INFO" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_INFO" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_INFO" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_INFO" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_LOG_TRACE = YES ]; then
srs_define_macro "SRS_AUTO_TRACE" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_TRACE" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_TRACE" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_TRACE" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_CROSS_BUILD = YES ]; then
srs_define_macro "SRS_AUTO_CROSSBUILD" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_CROSSBUILD" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_CROSSBUILD" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_CROSSBUILD" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_OSX = YES ]; then
srs_define_macro "SRS_AUTO_OSX" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_OSX" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_OSX" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_OSX" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_SENDMMSG = YES ]; then
srs_define_macro "SRS_AUTO_SENDMMSG" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_SENDMMSG" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_SENDMMSG" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_HAS_SENDMMSG = YES ]; then
srs_define_macro "SRS_AUTO_HAS_SENDMMSG" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_HAS_SENDMMSG" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_SENDMMSG" $SRS_AUTO_HEADERS_H
fi
if [ $SRS_DEBUG = YES ]; then
srs_define_macro "SRS_AUTO_DEBUG" $SRS_AUTO_HEADERS_H
srs_define_macro "SRS_DEBUG" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_AUTO_DEBUG" $SRS_AUTO_HEADERS_H
srs_undefine_macro "SRS_DEBUG" $SRS_AUTO_HEADERS_H
fi
# prefix
echo "" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H
echo "" >> $SRS_AUTO_HEADERS_H
@ -188,13 +189,13 @@ echo "" >> $SRS_AUTO_HEADERS_H
#####################################################################################
if [[ -f ../AUTHORS.txt ]]; then
SRS_CONSTRIBUTORS=`cat ../AUTHORS.txt|grep "*"|awk '{print $2}'`
echo "#define SRS_AUTO_CONSTRIBUTORS \"\\" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_CONSTRIBUTORS \"\\" >> $SRS_AUTO_HEADERS_H
for CONTRIBUTOR in $SRS_CONSTRIBUTORS; do
echo "${CONTRIBUTOR} \\" >> $SRS_AUTO_HEADERS_H
done
echo "\"" >> $SRS_AUTO_HEADERS_H
else
echo "#define SRS_AUTO_CONSTRIBUTORS \"ossrs\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_CONSTRIBUTORS \"ossrs\"" >> $SRS_AUTO_HEADERS_H
fi
# new empty line to auto headers file.

View file

@ -338,18 +338,21 @@ fi
#####################################################################################
if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
# check the cross build flag file, if flag changed, need to rebuild the st.
_ST_MAKE=linux-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_EPOLL" && _ST_LD=${SRS_TOOL_LD} && _ST_OBJ="LINUX_*"
_ST_MAKE=linux-debug && _ST_EXTRA_CFLAGS="-O0" && _ST_LD=${SRS_TOOL_LD} && _ST_OBJ="LINUX_`uname -r`_DBG"
if [[ $SRS_VALGRIND == YES ]]; then
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_VALGRIND"
fi
# for osx, use darwin for st, donot use epoll.
if [[ $SRS_OSX == YES ]]; then
_ST_MAKE=darwin-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_KQUEUE" && _ST_LD=${SRS_TOOL_CC} && _ST_OBJ="DARWIN_*"
_ST_MAKE=darwin-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_KQUEUE" && _ST_LD=${SRS_TOOL_CC} && _ST_OBJ="DARWIN_`uname -r`_DBG"
fi
# For UDP sendmmsg, disable it if not suppported.
if [[ $SRS_SENDMMSG == YES ]]; then
echo "Build ST with UDP sendmmsg support."
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_HAVE_SENDMMSG -D_GNU_SOURCE"
else
echo "Build ST without UDP sendmmsg support."
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -UMD_HAVE_SENDMMSG -U_GNU_SOURCE"
fi
# Pass the global extra flags.
if [[ $SRS_EXTRA_FLAGS != '' ]]; then
@ -379,7 +382,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
# Build source code.
make ${_ST_MAKE} EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" \
CC=${SRS_TOOL_CC} AR=${SRS_TOOL_AR} LD=${_ST_LD} RANDLIB=${SRS_TOOL_RANDLIB} &&
cd .. && rm -f st && ln -sf st-srs/${_ST_OBJ} st
cd .. && rm -rf st && ln -sf st-srs/${_ST_OBJ} st
)
fi
# check status
@ -515,7 +518,7 @@ if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL != YES ]]; then
# Which openssl we choose, openssl-1.0.* for SRTP with ASM, others we use openssl-1.1.*
OPENSSL_CANDIDATE="openssl-1.1.0e" && OPENSSL_UNZIP="unzip -q ../../3rdparty/$OPENSSL_CANDIDATE.zip"
if [[ $SRS_SRTP_ASM == YES ]]; then
OPENSSL_CANDIDATE="openssl-OpenSSL_1_0_2u" && OPENSSL_UNZIP="tar xf ../../3rdparty/$OPENSSL_CANDIDATE.tar.gz"
OPENSSL_CANDIDATE="openssl-OpenSSL_1_0_2u" && OPENSSL_UNZIP="tar xf ../../3rdparty/$OPENSSL_CANDIDATE.tar.gz"
fi
# cross build not specified, if exists flag, need to rebuild for no-arm platform.
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/openssl/lib/libssl.a ]]; then
@ -573,13 +576,13 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
rm -rf libsrtp-2.0.0 && unzip -q ../../3rdparty/libsrtp-2.0.0.zip && cd libsrtp-2.0.0 &&
${SRTP_CONFIG} && ./configure ${SRTP_OPTIONS} --prefix=`pwd`/_release &&
make ${SRS_JOBS} && make install &&
cd .. && rm -f srtp2 && ln -sf libsrtp-2.0.0/_release srtp2
cd .. && rm -rf srtp2 && ln -sf libsrtp-2.0.0/_release srtp2
)
fi
# check status
ret=$?; if [[ $ret -ne 0 ]]; then echo "Build srtp2 failed, ret=$ret"; exit $ret; fi
# Always update the links.
(cd ${SRS_OBJS} && rm -f srtp2 && ln -sf ${SRS_PLATFORM}/libsrtp-2.0.0/_release srtp2)
(cd ${SRS_OBJS} && rm -rf srtp2 && ln -sf ${SRS_PLATFORM}/libsrtp-2.0.0/_release srtp2)
if [ ! -f ${SRS_OBJS}/srtp2/lib/libsrtp2.a ]; then echo "Build srtp2 static lib failed."; exit -1; fi
fi
@ -601,7 +604,7 @@ if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then
# check status
ret=$?; if [[ $ret -ne 0 ]]; then echo "Build opus-1.3.1 failed, ret=$ret"; exit $ret; fi
# Always update the links.
(cd ${SRS_OBJS} && rm -f opus && ln -sf ${SRS_PLATFORM}/opus-1.3.1/_release opus)
(cd ${SRS_OBJS} && rm -rf opus && ln -sf ${SRS_PLATFORM}/opus-1.3.1/_release opus)
if [ ! -f ${SRS_OBJS}/opus/lib/libopus.a ]; then echo "Build opus-1.3.1 failed."; exit -1; fi
fi
@ -678,7 +681,10 @@ if [ $SRS_FFMPEG_TOOL = YES ]; then
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg/bin/ffmpeg ]]; then
echo "ffmpeg-4.1 is ok.";
else
echo "no ffmpeg found, please use srs-docker or --without-ffmpeg";
echo "Error: no FFmpeg found at /usr/local/bin/ffmpeg";
echo " please copy it from srs-docker";
echo " or download from http://ffmpeg.org/download.html";
echo " or disable it by --without-ffmpeg";
exit -1;
fi
# Always update the links.

View file

@ -80,6 +80,8 @@ SRS_VALGRIND=NO
SRS_BUILD_TAG=
# Whether do "make clean" when configure.
SRS_CLEAN=YES
# Whether enable RTC simulate API.
SRS_SIMULATOR=NO
#
################################################################
# presets
@ -118,10 +120,9 @@ SRS_EXTRA_FLAGS=
#
#####################################################################################
# Performance optimize.
SRS_NASM=YES
SRS_SRTP_ASM=YES
SRS_SENDMMSG=YES
SRS_HAS_SENDMMSG=YES
SRS_NASM=NO
SRS_SRTP_ASM=NO
SRS_SENDMMSG=NO
SRS_DEBUG=NO
#####################################################################################
@ -138,32 +139,20 @@ Presets:
Features:
-h, --help Print this message and exit 0.
--with-ssl Enable rtmp complex handshake, requires openssl-devel installed.
--with-hds Enable hds streaming, mux RTMP to F4M/F4V files.
--with-stream-caster Enable stream caster to serve other stream over other protocol.
--with-stat Enable the data statistic, for http api.
--with-librtmp Enable srs-librtmp, library for client.
--with-research Build the research tools.
--with-utest Build the utest for SRS.
--with-srt Build the SRT support for SRS.
--with-rtc Build the WebRTC support for SRS.
--with-gb28181 Build the GB28181 support for SRS.
--without-ssl Disable rtmp complex handshake.
--without-hds Disable hds, the adobe http dynamic streaming.
--without-stream-caster Disable stream caster, only listen and serve RTMP/HTTP.
--without-stat Disable the data statistic feature.
--without-librtmp Disable srs-librtmp, library for client.
--without-research Disable the research tools.
--without-utest Disable the utest for SRS.
--without-srt Disable the SRT support for SRS.
--without-rtc Disable the WebRTC support for SRS.
--without-gb28181 Disable the GB28181 support for SRS.
--ssl=on|off Whether build the rtmp complex handshake, requires openssl-devel installed.
--hds=on|off Whether build the hds streaming, mux RTMP to F4M/F4V files.
--stream-caster=on|off Whether build the stream caster to serve other stream over other protocol.
--stat=on|off Whether build the the data statistic, for http api.
--librtmp=on|off Whether build the srs-librtmp, library for client.
--research=on|off Whether build the research tools.
--utest=on|off Whether build the utest for SRS.
--srt=on|off Whether build the SRT support for SRS.
--rtc=on|off Whether build the WebRTC support for SRS.
--gb28181=on|off Whether build the GB28181 support for SRS.
--prefix=<path> The absolute installation path for srs. Default: $SRS_PREFIX
--static Whether add '-static' to link options.
--gcov Whether enable the GCOV compiler options.
--debug Whether enable the debug code, may hurt performance.
--gcov=on|off Whether enable the GCOV compiler options.
--debug=on|off Whether enable the debug code, may hurt performance.
--jobs[=N] Allow N jobs at once; infinite jobs with no arg.
Used for make in the configure, for example, to make ffmpeg.
--log-verbose Whether enable the log verbose level. default: no.
@ -171,30 +160,20 @@ Features:
--log-trace Whether enable the log trace level. default: yes.
Performance: @see https://blog.csdn.net/win_lin/article/details/53503869
--with-valgrind Support valgrind for memory check.
--with-gperf Build SRS with gperf tools(no gmd/gmc/gmp/gcp, with tcmalloc only).
--with-gmc Build memory check for SRS with gperf tools.
--with-gmd Build memory defense(corrupt memory) for SRS with gperf tools.
--with-gmp Build memory profile for SRS with gperf tools.
--with-gcp Build cpu profile for SRS with gperf tools.
--with-gprof Build SRS with gprof(GNU profile tool).
--valgrind=on|off Whether build valgrind for memory check.
--gperf=on|off Whether build SRS with gperf tools(no gmd/gmc/gmp/gcp, with tcmalloc only).
--gmc=on|off Whether build memory check for SRS with gperf tools.
--gmd=on|off Whether build memory defense(corrupt memory) for SRS with gperf tools.
--gmp=on|off Whether build memory profile for SRS with gperf tools.
--gcp=on|off Whether build cpu profile for SRS with gperf tools.
--gprof=on|off Whether build SRS with gprof(GNU profile tool).
--without-valgrind Do not support valgrind for memory check.
--without-gperf Do not build SRS with gperf tools(without tcmalloc and gmd/gmc/gmp/gcp).
--without-gmc Do not build memory check for SRS with gperf tools.
--without-gmd Do not build memory defense for SRS with gperf tools.
--without-gmp Do not build memory profile for SRS with gperf tools.
--without-gcp Do not build cpu profile for SRS with gperf tools.
--without-gprof Do not build srs with gprof(GNU profile tool).
--with-nasm Build FFMPEG for RTC with nasm support.
--without-nasm Build FFMPEG for RTC without nasm support, for CentOS6 nasm is too old.
--with-srtp-nasm Build SRTP with ASM(openssl-asm) support, requires RTC and openssl-1.0.*.
--without-srtp-nasm Disable SRTP ASM support.
--with-sendmmsg Enable UDP sendmmsg support. @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
--without-sendmmsg Disable UDP sendmmsg support.
--nasm=on|off Whether build FFMPEG for RTC with nasm support.
--srtp-nasm=on|off Whether build SRTP with ASM(openssl-asm) support, requires RTC and openssl-1.0.*.
--sendmmsg=on|off Whether enable UDP sendmmsg support. @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
Toolchain options: @see https://github.com/ossrs/srs/issues/1547#issuecomment-576078411
--static Whether add '-static' to link options.
--arm Enable crossbuild for ARM.
--mips Enable crossbuild for MIPS.
--cc=<CC> Use c compiler CC, default is gcc.
@ -213,14 +192,17 @@ Conflicts:
The complex tools not available for arm.
Experts:
--use-sys-ssl Do not compile ssl, use system ssl(-lssl) if required.
--sys-ssl=on|off Do not compile ssl, use system ssl(-lssl) if required.
--use-shared-st Use link shared libraries for ST which uses MPL license.
--use-shared-srt Use link shared libraries for SRT which uses MPL license.
--export-librtmp-project=<path> Export srs-librtmp to specified project in path.
--export-librtmp-single=<path> Export srs-librtmp to a single file(.h+.cpp) in path.
--build-tag=<TAG> Set the build object directory suffix.
--with-clean Configure SRS and do make clean if possible.
--without-clean Configure SRS and never make clean even possible..
--build-tag=<TAG> Set the build object directory suffix.
--with-clean Configure SRS and do make clean if possible.
--without-clean Configure SRS and never make clean even possible.
--detect-sendmmsg=on|off Whether detect the sendmmsg API.
--has-sendmmsg=on|off Whether OS supports sendmmsg API.
--simulator=on|off Whether enable RTC network simulator.
Workflow:
1. Apply "Presets". if not specified, use default preset.
@ -239,55 +221,6 @@ function parse_user_option() {
-h) help=yes ;;
--help) help=yes ;;
--with-ssl) SRS_SSL=YES ;;
--with-hds) SRS_HDS=YES ;;
--with-nginx) SRS_NGINX=YES ;;
--with-ffmpeg) SRS_FFMPEG_TOOL=YES ;;
--with-transcode) SRS_TRANSCODE=YES ;;
--with-ingest) SRS_INGEST=YES ;;
--with-stat) SRS_STAT=YES ;;
--with-stream-caster) SRS_STREAM_CASTER=YES ;;
--with-librtmp) SRS_LIBRTMP=YES ;;
--with-research) SRS_RESEARCH=YES ;;
--with-utest) SRS_UTEST=YES ;;
--with-srt) SRS_SRT=YES ;;
--with-rtc) SRS_RTC=YES ;;
--with-gb28181) SRS_GB28181=YES ;;
--with-nasm) SRS_NASM=YES ;;
--with-srtp-nasm) SRS_SRTP_ASM=YES ;;
--with-sendmmsg) SRS_SENDMMSG=YES ;;
--with-clean) SRS_CLEAN=YES ;;
--with-gperf) SRS_GPERF=YES ;;
--with-gmc) SRS_GPERF_MC=YES ;;
--with-gmd) SRS_GPERF_MD=YES ;;
--with-gmp) SRS_GPERF_MP=YES ;;
--with-gcp) SRS_GPERF_CP=YES ;;
--with-gprof) SRS_GPROF=YES ;;
--with-arm-ubuntu12) SRS_CROSS_BUILD=YES ;;
--with-mips-ubuntu12) SRS_CROSS_BUILD=YES ;;
--without-hds) SRS_HDS=NO ;;
--without-nginx) SRS_NGINX=NO ;;
--without-ffmpeg) SRS_FFMPEG_TOOL=NO ;;
--without-librtmp) SRS_LIBRTMP=NO ;;
--without-research) SRS_RESEARCH=NO ;;
--without-utest) SRS_UTEST=NO ;;
--without-srt) SRS_SRT=NO ;;
--without-rtc) SRS_RTC=NO ;;
--without-gb28181) SRS_GB28181=NO ;;
--without-nasm) SRS_NASM=NO ;;
--without-srtp-nasm) SRS_SRTP_ASM=NO ;;
--without-sendmmsg) SRS_SENDMMSG=NO ;;
--without-clean) SRS_CLEAN=NO ;;
--without-gperf) SRS_GPERF=NO ;;
--without-gmc) SRS_GPERF_MC=NO ;;
--without-gmd) SRS_GPERF_MD=NO ;;
--without-gmp) SRS_GPERF_MP=NO ;;
--without-gcp) SRS_GPERF_CP=NO ;;
--without-gprof) SRS_GPROF=NO ;;
--without-arm-ubuntu12) SRS_CROSS_BUILD=NO ;;
--without-mips-ubuntu12) SRS_CROSS_BUILD=NO ;;
--jobs) SRS_JOBS=${value} ;;
--prefix) SRS_PREFIX=${value} ;;
--static) SRS_STATIC=YES ;;
@ -321,32 +254,145 @@ function parse_user_option() {
--pure-rtmp) SRS_PURE_RTMP=YES ;;
--full) SRS_ENABLE_ALL=YES ;;
--use-sys-ssl) SRS_USE_SYS_SSL=YES ;;
--use-shared-st) SRS_SHARED_ST=YES ;;
--use-shared-srt) SRS_SHARED_SRT=YES ;;
--memory-watch) SRS_MEM_WATCH=YES ;;
--export-librtmp-project) SRS_EXPORT_LIBRTMP_PROJECT=${value} ;;
--export-librtmp-single) SRS_EXPORT_LIBRTMP_SINGLE=${value} ;;
--sendmmsg) if [[ $value == off ]]; then SRS_SENDMMSG=NO; else SRS_SENDMMSG=YES; fi ;;
--without-srtp-nasm) SRS_SRTP_ASM=NO ;;
--with-srtp-nasm) SRS_SRTP_ASM=YES ;;
--srtp-nasm) if [[ $value == off ]]; then SRS_SRTP_ASM=NO; else SRS_SRTP_ASM=YES; fi ;;
--without-nasm) SRS_NASM=NO ;;
--with-nasm) SRS_NASM=YES ;;
--nasm) if [[ $value == off ]]; then SRS_NASM=NO; else SRS_NASM=YES; fi ;;
--with-ssl) SRS_SSL=YES ;;
--ssl) if [[ $value == off ]]; then SRS_SSL=NO; else SRS_SSL=YES; fi ;;
--with-hds) SRS_HDS=YES ;;
--without-hds) SRS_HDS=NO ;;
--hds) if [[ $value == off ]]; then SRS_HDS=NO; else SRS_HDS=YES; fi ;;
--with-nginx) SRS_NGINX=YES ;;
--without-nginx) SRS_NGINX=NO ;;
--nginx) if [[ $value == off ]]; then SRS_NGINX=NO; else SRS_NGINX=YES; fi ;;
--with-ffmpeg) SRS_FFMPEG_TOOL=YES ;;
--without-ffmpeg) SRS_FFMPEG_TOOL=NO ;;
--ffmpeg) if [[ $value == off ]]; then SRS_FFMPEG_TOOL=NO; else SRS_FFMPEG_TOOL=YES; fi ;;
--with-transcode) SRS_TRANSCODE=YES ;;
--without-transcode) echo "ignore option \"$option\"" ;;
--transcode) if [[ $value == off ]]; then SRS_TRANSCODE=NO; else SRS_TRANSCODE=YES; fi ;;
--with-ingest) SRS_INGEST=YES ;;
--without-ingest) echo "ignore option \"$option\"" ;;
--ingest) if [[ $value == off ]]; then SRS_INGEST=NO; else SRS_INGEST=YES; fi ;;
--with-stat) SRS_STAT=YES ;;
--without-stat) echo "ignore option \"$option\"" ;;
--stat) if [[ $value == off ]]; then SRS_STAT=NO; else SRS_STAT=YES; fi ;;
--with-stream-caster) SRS_STREAM_CASTER=YES ;;
--without-stream-caster) echo "ignore option \"$option\"" ;;
--stream-caster) if [[ $value == off ]]; then SRS_STREAM_CASTER=NO; else SRS_STREAM_CASTER=YES; fi ;;
--with-librtmp) SRS_LIBRTMP=YES ;;
--without-librtmp) SRS_LIBRTMP=NO ;;
--librtmp) if [[ $value == off ]]; then SRS_LIBRTMP=NO; else SRS_LIBRTMP=YES; fi ;;
--with-research) SRS_RESEARCH=YES ;;
--without-research) SRS_RESEARCH=NO ;;
--research) if [[ $value == off ]]; then SRS_RESEARCH=NO; else SRS_RESEARCH=YES; fi ;;
--with-utest) SRS_UTEST=YES ;;
--without-utest) SRS_UTEST=NO ;;
--utest) if [[ $value == off ]]; then SRS_UTEST=NO; else SRS_UTEST=YES; fi ;;
--with-srt) SRS_SRT=YES ;;
--without-srt) SRS_SRT=NO ;;
--srt) if [[ $value == off ]]; then SRS_SRT=NO; else SRS_SRT=YES; fi ;;
--with-rtc) SRS_RTC=YES ;;
--without-rtc) SRS_RTC=NO ;;
--rtc) if [[ $value == off ]]; then SRS_RTC=NO; else SRS_RTC=YES; fi ;;
--simulator) if [[ $value == off ]]; then SRS_SIMULATOR=NO; else SRS_SIMULATOR=YES; fi ;;
--with-gb28181) SRS_GB28181=YES ;;
--without-gb28181) SRS_GB28181=NO ;;
--gb28181) if [[ $value == off ]]; then SRS_GB28181=NO; else SRS_GB28181=YES; fi ;;
--with-clean) SRS_CLEAN=YES ;;
--without-clean) SRS_CLEAN=NO ;;
--clean) if [[ $value == off ]]; then SRS_CLEAN=NO; else SRS_CLEAN=YES; fi ;;
--with-gperf) SRS_GPERF=YES ;;
--without-gperf) SRS_GPERF=NO ;;
--gperf) if [[ $value == off ]]; then SRS_GPERF=NO; else SRS_GPERF=YES; fi ;;
--with-gmc) SRS_GPERF_MC=YES ;;
--without-gmc) SRS_GPERF_MC=NO ;;
--gmc) if [[ $value == off ]]; then SRS_GPERF_MC=NO; else SRS_GPERF_MC=YES; fi ;;
--with-gmd) SRS_GPERF_MD=YES ;;
--without-gmd) SRS_GPERF_MD=NO ;;
--gmd) if [[ $value == off ]]; then SRS_GPERF_MD=NO; else SRS_GPERF_MD=YES; fi ;;
--with-gmp) SRS_GPERF_MP=YES ;;
--without-gmp) SRS_GPERF_MP=NO ;;
--gmp) if [[ $value == off ]]; then SRS_GPERF_MP=NO; else SRS_GPERF_MP=YES; fi ;;
--with-gcp) SRS_GPERF_CP=YES ;;
--without-gcp) SRS_GPERF_CP=NO ;;
--gcp) if [[ $value == off ]]; then SRS_GPERF_CP=NO; else SRS_GPERF_CP=YES; fi ;;
--with-gprof) SRS_GPROF=YES ;;
--without-gprof) SRS_GPROF=NO ;;
--gprof) if [[ $value == off ]]; then SRS_GPROF=NO; else SRS_GPROF=YES; fi ;;
--with-arm-ubuntu12) SRS_CROSS_BUILD=YES ;;
--without-arm-ubuntu12) SRS_CROSS_BUILD=NO ;;
--arm-ubuntu12) if [[ $value == off ]]; then SRS_CROSS_BUILD=NO; else SRS_CROSS_BUILD=YES; fi ;;
--with-mips-ubuntu12) SRS_CROSS_BUILD=YES ;;
--without-mips-ubuntu12) SRS_CROSS_BUILD=NO ;;
--mips-ubuntu12) if [[ $value == off ]]; then SRS_CROSS_BUILD=NO; else SRS_CROSS_BUILD=YES; fi ;;
--use-sys-ssl) SRS_USE_SYS_SSL=YES ;;
--without-ssl) echo "ignore option \"$option\"" ;;
--sys-ssl) if [[ $value == off ]]; then SRS_USE_SYS_SSL=NO; else SRS_USE_SYS_SSL=YES; fi ;;
--use-shared-st) SRS_SHARED_ST=YES ;;
--shared-st) if [[ $value == off ]]; then SRS_SHARED_ST=NO; else SRS_SHARED_ST=YES; fi ;;
--use-shared-srt) SRS_SHARED_SRT=YES ;;
--shared-srt) if [[ $value == off ]]; then SRS_SHARED_SRT=NO; else SRS_SHARED_SRT=YES; fi ;;
--with-valgrind) SRS_VALGRIND=YES ;;
--without-valgrind) SRS_VALGRIND=NO ;;
--valgrind) if [[ $value == off ]]; then SRS_VALGRIND=NO; else SRS_VALGRIND=YES; fi ;;
--with-http-callback) SRS_HTTP_CALLBACK=YES ;;
--with-http-api) SRS_HTTP_API=YES ;;
--with-http-server) SRS_HTTP_SERVER=YES ;;
--with-hls) SRS_HLS=YES ;;
--with-dvr) SRS_DVR=YES ;;
--without-stream-caster) echo "ignore option \"$option\"" ;;
--without-ingest) echo "ignore option \"$option\"" ;;
--without-ssl) echo "ignore option \"$option\"" ;;
--without-stat) echo "ignore option \"$option\"" ;;
--without-transcode) echo "ignore option \"$option\"" ;;
--without-http-callback) echo "ignore option \"$option\"" ;;
--without-http-server) echo "ignore option \"$option\"" ;;
--http-callback) if [[ $value == off ]]; then SRS_HTTP_CALLBACK=NO; else SRS_HTTP_CALLBACK=YES; fi ;;
--with-http-api) SRS_HTTP_API=YES ;;
--without-http-api) echo "ignore option \"$option\"" ;;
--http-api) if [[ $value == off ]]; then SRS_HTTP_API=NO; else SRS_HTTP_API=YES; fi ;;
--with-http-server) SRS_HTTP_SERVER=YES ;;
--without-http-server) echo "ignore option \"$option\"" ;;
--http-server) if [[ $value == off ]]; then SRS_HTTP_SERVER=NO; else SRS_HTTP_SERVER=YES; fi ;;
--with-hls) SRS_HLS=YES ;;
--without-hls) echo "ignore option \"$option\"" ;;
--hls) if [[ $value == off ]]; then SRS_HLS=NO; else SRS_HLS=YES; fi ;;
--with-dvr) SRS_DVR=YES ;;
--without-dvr) echo "ignore option \"$option\"" ;;
--dvr) if [[ $value == off ]]; then SRS_DVR=NO; else SRS_DVR=YES; fi ;;
*)
echo "$0: error: invalid option \"$option\""
@ -567,23 +613,9 @@ function apply_user_detail_options() {
SRS_SRTP_ASM=NO
fi
# Detect whether has sendmmsg.
# @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
mkdir -p ${SRS_OBJS} &&
echo " #include <sys/socket.h> " > ${SRS_OBJS}/_tmp_sendmmsg_detect.c
echo " int main(int argc, char** argv) { " >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
echo " struct mmsghdr hdr; " >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
echo " hdr.msg_len = 0; " >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
echo " return 0; " >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
echo " } " >> ${SRS_OBJS}/_tmp_sendmmsg_detect.c
${SRS_TOOL_CC} -c ${SRS_OBJS}/_tmp_sendmmsg_detect.c -D_GNU_SOURCE -o /dev/null >/dev/null 2>&1
ret=$?; rm -f ${SRS_OBJS}/_tmp_sendmmsg_detect.c;
if [[ $ret -ne 0 ]]; then
SRS_HAS_SENDMMSG=NO
if [[ $SRS_SENDMMSG == YES ]]; then
echo "Disable UDP sendmmsg automatically"
SRS_SENDMMSG=NO
fi
if [[ $SRS_OSX == YES && $SRS_SENDMMSG == YES ]]; then
echo "Disable sendmmsg for OSX"
SRS_SENDMMSG=NO
fi
}
apply_user_detail_options
@ -593,48 +625,50 @@ function regenerate_options() {
SRS_AUTO_USER_CONFIGURE=`echo $opt`
# regenerate the options for default values.
SRS_AUTO_CONFIGURE="--prefix=${SRS_PREFIX}"
if [ $SRS_HLS = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-hls"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-hls"; fi
if [ $SRS_HDS = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-hds"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-hds"; fi
if [ $SRS_DVR = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-dvr"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-dvr"; fi
if [ $SRS_SSL = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-ssl"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-ssl"; fi
if [ $SRS_TRANSCODE = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-transcode"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-transcode"; fi
if [ $SRS_INGEST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-ingest"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-ingest"; fi
if [ $SRS_STAT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-stat"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-stat"; fi
if [ $SRS_HTTP_CALLBACK = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-http-callback"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-http-callback"; fi
if [ $SRS_HTTP_SERVER = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-http-server"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-http-server"; fi
if [ $SRS_STREAM_CASTER = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-stream-caster"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-stream-caster"; fi
if [ $SRS_HTTP_API = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-http-api"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-http-api"; fi
if [ $SRS_LIBRTMP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-librtmp"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-librtmp"; fi
if [ $SRS_RESEARCH = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-research"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-research"; fi
if [ $SRS_UTEST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-utest"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-utest"; fi
if [ $SRS_SRT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-srt"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-srt"; fi
if [ $SRS_RTC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-rtc"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-rtc"; fi
if [ $SRS_GB28181 = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gb28181"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gb28181"; fi
if [ $SRS_NASM = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-nasm"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-nasm"; fi
if [ $SRS_SRTP_ASM = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-srtp-nasm"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-srtp-nasm"; fi
if [ $SRS_SENDMMSG = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-sendmmsg"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-sendmmsg"; fi
if [ $SRS_CLEAN = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-clean"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-clean"; fi
if [ $SRS_GPERF = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gperf"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gperf"; fi
if [ $SRS_GPERF_MC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmc"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmc"; fi
if [ $SRS_GPERF_MD = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmd"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmd"; fi
if [ $SRS_GPERF_MP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmp"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmp"; fi
if [ $SRS_GPERF_CP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gcp"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gcp"; fi
if [ $SRS_GPROF = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gprof"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gprof"; fi
if [ $SRS_STATIC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --static"; fi
if [ $SRS_SHARED_ST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --use-shared-st"; fi
if [ $SRS_SHARED_SRT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --use-shared-srt"; fi
if [ $SRS_LOG_VERBOSE = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --log-verbose"; 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_GCOV = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gcov"; fi
if [ $SRS_DEBUG = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --debug"; fi
if [[ $SRS_EXTRA_FLAGS != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --extra-flags=\\\"$SRS_EXTRA_FLAGS\\\""; fi
if [[ $SRS_BUILD_TAG != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --build-tag=\\\"$SRS_BUILD_TAG\\\""; fi
if [[ $SRS_TOOL_CC != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cc=$SRS_TOOL_CC"; fi
if [[ $SRS_TOOL_CXX != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cxx=$SRS_TOOL_CXX"; fi
if [[ $SRS_TOOL_AR != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ar=$SRS_TOOL_AR"; fi
if [[ $SRS_TOOL_LD != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ld=$SRS_TOOL_LD"; fi
if [[ $SRS_TOOL_RANDLIB != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --randlib=$SRS_TOOL_RANDLIB"; fi
if [ $SRS_HLS = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --hls=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --hls=off"; fi
if [ $SRS_HDS = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --hds=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --hds=off"; fi
if [ $SRS_DVR = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --dvr=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --dvr=off"; fi
if [ $SRS_SSL = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ssl=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ssl=off"; fi
if [ $SRS_USE_SYS_SSL = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --sys-ssl=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --sys-ssl=off"; fi
if [ $SRS_TRANSCODE = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --transcode=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --transcode=off"; fi
if [ $SRS_INGEST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ingest=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ingest=off"; fi
if [ $SRS_STAT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --stat=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --stat=off"; fi
if [ $SRS_HTTP_CALLBACK = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --http-callback=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --http-callback=off"; fi
if [ $SRS_HTTP_SERVER = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --http-server=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --http-server=off"; fi
if [ $SRS_STREAM_CASTER = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --stream-caster=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --stream-caster=off"; fi
if [ $SRS_HTTP_API = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --http-api=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --http-api=off"; fi
if [ $SRS_LIBRTMP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --librtmp=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --librtmp=off"; fi
if [ $SRS_RESEARCH = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --research=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --research=off"; fi
if [ $SRS_UTEST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --utest=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --utest=off"; fi
if [ $SRS_SRT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srt=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srt=off"; fi
if [ $SRS_RTC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --rtc=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --rtc=off"; fi
if [ $SRS_SIMULATOR = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --simulator=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --simulator=off"; fi
if [ $SRS_GB28181 = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gb28181=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gb28181=off"; fi
if [ $SRS_NASM = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --nasm=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --nasm=off"; fi
if [ $SRS_SRTP_ASM = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srtp-nasm=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srtp-nasm=off"; fi
if [ $SRS_SENDMMSG = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --sendmmsg=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --sendmmsg=off"; fi
if [ $SRS_CLEAN = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --clean=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --clean=off"; fi
if [ $SRS_GPERF = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gperf=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gperf=off"; fi
if [ $SRS_GPERF_MC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmc=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmc=off"; fi
if [ $SRS_GPERF_MD = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmd=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmd=off"; fi
if [ $SRS_GPERF_MP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmp=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmp=off"; fi
if [ $SRS_GPERF_CP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gcp=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gcp=off"; fi
if [ $SRS_GPROF = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gprof=on"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gprof=off"; fi
if [ $SRS_STATIC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --static"; fi
if [ $SRS_SHARED_ST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --use-shared-st"; fi
if [ $SRS_SHARED_SRT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --use-shared-srt"; fi
if [ $SRS_LOG_VERBOSE = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --log-verbose"; 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_GCOV = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gcov"; fi
if [ $SRS_DEBUG = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --debug"; fi
if [[ $SRS_EXTRA_FLAGS != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --extra-flags=\\\"$SRS_EXTRA_FLAGS\\\""; fi
if [[ $SRS_BUILD_TAG != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --build-tag=\\\"$SRS_BUILD_TAG\\\""; fi
if [[ $SRS_TOOL_CC != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cc=$SRS_TOOL_CC"; fi
if [[ $SRS_TOOL_CXX != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cxx=$SRS_TOOL_CXX"; fi
if [[ $SRS_TOOL_AR != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ar=$SRS_TOOL_AR"; fi
if [[ $SRS_TOOL_LD != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ld=$SRS_TOOL_LD"; fi
if [[ $SRS_TOOL_RANDLIB != '' ]]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --randlib=$SRS_TOOL_RANDLIB"; fi
echo "User config: $SRS_AUTO_USER_CONFIGURE"
echo "Detail config: ${SRS_AUTO_CONFIGURE}"
}

View file

@ -421,6 +421,13 @@ rtc_server {
# $CANDIDATE $EIP # TODO: Implements it.
# default: *
candidate *;
# The IP family filter for candidate, it can be:
# ipv4 Filter IP v4 candidates.
# ipv6 Filter IP v6 candidates.
# all Filter all IP v4 or v6 candidates.
# For example, if set to ipv4, we only use the IPv4 address as candidate.
# default: ipv4
ip_family ipv4;
# Whether use ECDSA certificate.
# If not, use RSA certificate.
# default: on
@ -461,6 +468,16 @@ rtc_server {
# then system queue is 2000*4 = 8k, user can incrase reuseport to incrase the queue.
# default: 2000
queue_length 2000;
# The black-hole to copy packet to, for debugging.
# For example, when debugging Chrome publish stream, the received packets are encrypted cipher,
# we can set the publisher black-hole, SRS will copy the plaintext packets to black-hole, and
# we are able to capture the plaintext packets by wireshark.
black_hole {
# Whether enable the black-hole.
enabled off;
# The black-hole address for publisher, or SRS as receiver.
publisher 127.0.0.1:10000;
}
}
vhost rtc.vhost.srs.com {
@ -499,6 +516,12 @@ vhost rtc.vhost.srs.com {
# default: 1 (For WebRTC, min_latency off)
mw_msgs 0;
}
# For NACK.
nack {
# Whether support NACK.
# default: on
enabled on;
}
}
#############################################################################################

9
trunk/configure vendored
View file

@ -188,7 +188,7 @@ if [[ $SRS_GCOV == YES ]]; then
SrsLinkOptions="${SrsLinkOptions} ${SrsGcov}";
fi
# For FFMPEG/RTC.
if [[ $SRS_RTC == YES && $SRS_NASM == NO ]]; then
if [[ $SRS_RTC == YES && $SRS_NASM == NO && $SRS_OSX == NO ]]; then
SrsLinkOptions="${SrsLinkOptions} -lrt";
fi
@ -213,7 +213,7 @@ MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_buffer"
"srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts"
"srs_kernel_stream" "srs_kernel_balance" "srs_kernel_mp4" "srs_kernel_file")
if [[ $SRS_RTC == YES ]]; then
MODULE_FILES+=("srs_kernel_rtp")
MODULE_FILES+=("srs_kernel_rtc_rtp")
fi
KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . auto/modules.sh
KERNEL_OBJS="${MODULE_OBJS[@]}"
@ -227,7 +227,7 @@ MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack"
"srs_raw_avc" "srs_rtsp_stack" "srs_sip_stack" "srs_http_stack" "srs_protocol_kbps" "srs_protocol_json"
"srs_protocol_format")
if [[ $SRS_RTC == YES ]]; then
MODULE_FILES+=("srs_stun_stack")
MODULE_FILES+=("srs_rtc_stun_stack")
fi
PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh
PROTOCOL_OBJS="${MODULE_OBJS[@]}"
@ -279,7 +279,8 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
"srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr"
"srs_app_coworkers" "srs_app_hybrid")
if [[ $SRS_RTC == YES ]]; then
MODULE_FILES+=("srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_audio_recode" "srs_app_sdp")
MODULE_FILES+=("srs_app_rtc" "srs_app_rtc_conn" "srs_app_rtc_dtls" "srs_app_rtc_codec" "srs_app_rtc_sdp"
"srs_app_rtc_queue" "srs_app_rtc_server")
fi
if [[ $SRS_GB28181 == YES ]]; then
MODULE_FILES+=("srs_app_gb28181" "srs_app_gb28181_sip")

View file

@ -30,6 +30,7 @@ function update_nav() {
$("#srs_index").attr("href", "index.html" + window.location.search);
$("#nav_srs_player").attr("href", "srs_player.html" + window.location.search);
$("#nav_rtc_player").attr("href", "rtc_player.html" + window.location.search);
$("#nav_rtc_publisher").attr("href", "rtc_publisher.html" + window.location.search);
$("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search);
$("#nav_srs_chat").attr("href", "srs_chat.html" + window.location.search);
$("#nav_srs_bwt").attr("href", "srs_bwt.html" + window.location.search);

View file

@ -15,7 +15,7 @@
<script type="text/javascript" src="js/srs.page.js"></script>
</head>
<body>
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtc'/>
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtcplayer'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
@ -24,6 +24,7 @@
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li class="active"><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>-->
<!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>-->
<!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>-->
@ -47,6 +48,12 @@
<label></label>
<video id="rtc_media_player" controls autoplay></video>
<label></label>
SessionID: <span id='sessionid'></span>
<label></label>
Simulator: <a href='#' id='simulator-drop'>Drop</a>
<footer>
<p></p>
<p><a href="https://github.com/ossrs/srs">SRS Team &copy; 2020</a></p>
@ -67,6 +74,7 @@
pc = new RTCPeerConnection(null);
pc.onaddstream = function (event) {
console.log('Start play, event: ', event);
$('#rtc_media_player').prop('srcObject', event.stream);
};
new Promise(function(resolve, reject) {
@ -103,13 +111,20 @@
var data = {
api: url, streamurl: urlObject.url, clientip: null, sdp: offer.sdp
};
console.log("offer: " + JSON.stringify(data));
console.log("Generated offer: ", data);
$.ajax({
type: "POST", url: url, data: JSON.stringify(data),
contentType:'application/json', dataType: 'json'
}).done(function(data) {
console.log("answer: " + JSON.stringify(data));
console.log("Got answer: ", data);
if (data.code) {
reject(data); return;
}
var simulator = schema + '//' + urlObject.server + ':' + port + '/rtc/v1/nack/';
$('#sessionid').html(data.sessionid);
$('#simulator-drop').attr('href', simulator + '?drop=1&username=' + data.sessionid);
resolve(data.sdp);
}).fail(function(reason){
reject(reason);
@ -118,6 +133,7 @@
}).then(function(answer) {
return pc.setRemoteDescription(new RTCSessionDescription({type: 'answer', sdp: answer}));
}).catch(function(reason) {
pc.close(); $('#rtc_media_player').hide();
throw reason;
});
};

View file

@ -0,0 +1,169 @@
<!DOCTYPE html>
<html>
<head>
<title>SRS</title>
<meta charset="utf-8">
<style>
body{
padding-top: 55px;
}
</style>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/adapter-7.4.0.min.js"></script>
<script type="text/javascript" src="js/winlin.utility.js"></script>
<script type="text/javascript" src="js/srs.page.js"></script>
</head>
<body>
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtcpublisher'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a id="srs_index" class="brand" href="https://github.com/ossrs/srs">SRS</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li class="active"><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>-->
<!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>-->
<!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>-->
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
<!--<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>-->
<li><a id="nav_gb28181" href="srs_gb28181.html">GB28181</a></li>
<li><a href="https://github.com/ossrs/srs">源码</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
<div class="form-inline">
URL:
<input type="text" id="txt_url" class="input-xxlarge" value="">
<button class="btn btn-primary" id="btn_publish">开始推流</button>
</div>
<label></label>
<video id="rtc_media_player" width="320" autoplay muted></video>
<label></label>
SessionID: <span id='sessionid'></span>
<label></label>
Simulator: <a href='#' id='simulator-drop'>Drop</a>
<footer>
<p></p>
<p><a href="https://github.com/ossrs/srs">SRS Team &copy; 2020</a></p>
</footer>
</div>
<script type="text/javascript">
var pc = null; // Global handler to do cleanup when replaying.
$(function(){
var startPublish = function() {
$('#rtc_media_player').show();
var urlObject = parse_rtmp_url($("#txt_url").val());
var schema = window.location.protocol;
// Close PC when user replay.
if (pc) {
pc.close();
}
pc = new RTCPeerConnection(null);
pc.addTransceiver("audio", {direction: "sendonly"});
pc.addTransceiver("video", {direction: "sendonly"});
var constraints = {
audio: true, video: {
height: { max: 320 }
}
};
navigator.mediaDevices.getUserMedia(
constraints
).then(function(stream) {
console.log('Got stream with constraints: ', constraints);
$('#rtc_media_player').prop('srcObject', stream);
pc.addStream(stream);
return new Promise(function(resolve, reject) {
pc.createOffer(function(offer){
resolve(offer);
},function(reason){
reject(reason);
});
});
}).then(function(offer) {
return pc.setLocalDescription(offer).then(function(){ return offer; });
}).then(function(offer) {
return new Promise(function(resolve, reject) {
var port = urlObject.port || 1985;
// @see https://github.com/rtcdn/rtcdn-draft
var api = urlObject.user_query.publish || '/rtc/v1/publish/';
if (api.lastIndexOf('/') != api.length - 1) {
api += '/';
}
var url = schema + '//' + urlObject.server + ':' + port + api;
for (var key in urlObject.user_query) {
if (key != 'api' && key != 'publish') {
url += '&' + key + '=' + urlObject.user_query[key];
}
}
// Replace /rtc/v1/publish/&k=v to /rtc/v1/publish/?k=v
url = url.replace(api + '&', api + '?');
// @see https://github.com/rtcdn/rtcdn-draft
var data = {
api: url, streamurl: urlObject.url, clientip: null, sdp: offer.sdp
};
console.log("Generated offer: ", data);
$.ajax({
type: "POST", url: url, data: JSON.stringify(data),
contentType:'application/json', dataType: 'json'
}).done(function(data) {
console.log("Got answer: ", data);
if (data.code) {
reject(data); return;
}
var simulator = schema + '//' + urlObject.server + ':' + port + '/rtc/v1/nack/';
$('#sessionid').html(data.sessionid);
$('#simulator-drop').attr('href', simulator + '?drop=1&username=' + data.sessionid);
resolve(data.sdp);
}).fail(function(reason){
reject(reason);
});
});
}).then(function(answer) {
return pc.setRemoteDescription(new RTCSessionDescription({type: 'answer', sdp: answer}));
}).catch(function(reason) {
pc.getLocalStreams().forEach(function(stream){
stream.getTracks().forEach(function(track) {
track.stop();
});
});
pc.close(); $('#rtc_media_player').hide();
throw reason;
});
};
$('#rtc_media_player').hide();
var query = parse_query_string();
srs_init_rtc("#txt_url", query);
$("#btn_publish").click(startPublish);
if (query.autostart === 'true') {
startPublish();
}
});
</script>
</body>
</html>
</html>

View file

@ -24,6 +24,7 @@
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
<li class="active"><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>

View file

@ -23,6 +23,7 @@
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
<li class="active"><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>

View file

@ -37,6 +37,7 @@
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>-->
<!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>-->
<!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>-->

View file

@ -34,6 +34,7 @@
<ul class="nav">
<li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>-->
<!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>-->
<!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>-->

View file

@ -23,6 +23,7 @@
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<li class="active"><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>

View file

@ -20,6 +20,7 @@
<ul class="nav">
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
<li><a id="nav_rtc_publisher" href="rtc_publisher.html">RTC推流</a></li>
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>

View file

@ -3645,7 +3645,8 @@ srs_error_t SrsConfig::check_normal_config()
string n = conf->at(i)->name;
if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa"
&& n != "sendmmsg" && n != "encrypt" && n != "reuseport" && n != "gso" && n != "merge_nalus"
&& n != "padding" && n != "perf_stat" && n != "queue_length") {
&& n != "padding" && n != "perf_stat" && n != "queue_length" && n != "black_hole"
&& n != "ip_family") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str());
}
}
@ -3682,13 +3683,15 @@ srs_error_t SrsConfig::check_normal_config()
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d", get_stats_network());
}
if (true) {
vector<std::string> ips = srs_get_local_ips();
vector<SrsIPAddress*> ips = srs_get_local_ips();
int index = get_stats_network();
if (index >= (int)ips.size()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d of %d",
index, (int)ips.size());
}
srs_warn("stats network use index=%d, ip=%s", index, ips.at(index).c_str());
SrsIPAddress* addr = ips.at(index);
srs_warn("stats network use index=%d, ip=%s, ifname=%s", index, addr->ip.c_str(), addr->ifname.c_str());
}
if (true) {
SrsConfDirective* conf = get_stats_disk_device();
@ -3782,7 +3785,7 @@ srs_error_t SrsConfig::check_normal_config()
&& n != "play" && n != "publish" && n != "cluster"
&& n != "security" && n != "http_remux" && n != "dash"
&& n != "http_static" && n != "hds" && n != "exec"
&& n != "in_ack_size" && n != "out_ack_size" && n != "rtc") {
&& n != "in_ack_size" && n != "out_ack_size" && n != "rtc" && n != "nack") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.%s", n.c_str());
}
// for each sub directives of vhost.
@ -4679,7 +4682,7 @@ srs_utime_t SrsConfig::get_stream_caster_gb28181_sip_query_catalog_interval(SrsC
return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_SECONDS);
}
int SrsConfig::get_rtc_server_enabled()
bool SrsConfig::get_rtc_server_enabled()
{
SrsConfDirective* conf = root->get("rtc_server");
return get_rtc_server_enabled(conf);
@ -4742,7 +4745,24 @@ std::string SrsConfig::get_rtc_server_candidates()
return DEFAULT;
}
return (conf->arg0().c_str());
return conf->arg0();
}
std::string SrsConfig::get_rtc_server_ip_family()
{
static string DEFAULT = "ipv4";
SrsConfDirective* conf = root->get("rtc_server");
if (!conf) {
return DEFAULT;
}
conf = conf->get("ip_family");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return conf->arg0();
}
bool SrsConfig::get_rtc_server_ecdsa()
@ -4781,7 +4801,7 @@ bool SrsConfig::get_rtc_server_encrypt()
int SrsConfig::get_rtc_server_sendmmsg()
{
#if !defined(SRS_AUTO_HAS_SENDMMSG) || !defined(SRS_AUTO_SENDMMSG)
#if !defined(SRS_SENDMMSG)
return 1;
#else
static int DEFAULT = 256;
@ -4943,6 +4963,50 @@ int SrsConfig::get_rtc_server_queue_length()
return ::atoi(conf->arg0().c_str());
}
bool SrsConfig::get_rtc_server_black_hole()
{
static bool DEFAULT = false;
SrsConfDirective* conf = root->get("rtc_server");
if (!conf) {
return DEFAULT;
}
conf = conf->get("black_hole");
if (!conf) {
return DEFAULT;
}
conf = conf->get("enabled");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
std::string SrsConfig::get_rtc_server_black_hole_publisher()
{
static string DEFAULT = "";
SrsConfDirective* conf = root->get("rtc_server");
if (!conf) {
return DEFAULT;
}
conf = conf->get("black_hole");
if (!conf) {
return DEFAULT;
}
conf = conf->get("publisher");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return conf->arg0();
}
SrsConfDirective* SrsConfig::get_rtc(string vhost)
{
SrsConfDirective* conf = get_vhost(vhost);
@ -5039,6 +5103,29 @@ bool SrsConfig::get_rtc_stun_strict_check(string vhost)
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
bool SrsConfig::get_rtc_nack_enabled(string vhost)
{
static bool DEFAULT = true;
SrsConfDirective* conf = get_vhost(vhost);
if (!conf) {
return DEFAULT;
}
conf = conf->get("nack");
if (!conf) {
return DEFAULT;
}
conf = conf->get("enabled");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost)
{
srs_assert(root);

View file

@ -521,10 +521,11 @@ public:
// rtc section
public:
virtual int get_rtc_server_enabled();
virtual bool get_rtc_server_enabled();
virtual bool get_rtc_server_enabled(SrsConfDirective* conf);
virtual int get_rtc_server_listen();
virtual std::string get_rtc_server_candidates();
virtual std::string get_rtc_server_ip_family();
virtual bool get_rtc_server_ecdsa();
virtual int get_rtc_server_sendmmsg();
virtual bool get_rtc_server_encrypt();
@ -534,6 +535,8 @@ public:
virtual int get_rtc_server_padding();
virtual bool get_rtc_server_perf_stat();
virtual int get_rtc_server_queue_length();
virtual bool get_rtc_server_black_hole();
virtual std::string get_rtc_server_black_hole_publisher();
private:
virtual int get_rtc_server_reuseport2();
virtual bool get_rtc_server_gso2();
@ -545,6 +548,7 @@ public:
bool get_rtc_aac_discard(std::string vhost);
srs_utime_t get_rtc_stun_timeout(std::string vhost);
bool get_rtc_stun_strict_check(std::string vhost);
bool get_rtc_nack_enabled(std::string vhost);
// vhost specified section
public:

View file

@ -45,7 +45,7 @@ using namespace std;
#include <srs_core_autofree.hpp>
#include <srs_kernel_utility.hpp>
#ifdef SRS_AUTO_FFMPEG_STUB
#ifdef SRS_FFMPEG_STUB
#define SRS_RTMP_ENCODER_COPY "copy"
#define SRS_RTMP_ENCODER_NO_VIDEO "vn"

View file

@ -26,7 +26,7 @@
#include <srs_core.hpp>
#ifdef SRS_AUTO_FFMPEG_STUB
#ifdef SRS_FFMPEG_STUB
#include <vector>
#include <string>

View file

@ -621,9 +621,10 @@ static std::string get_host_candidate_ips(SrsConfDirective* c)
{
string candidate = _srs_config->get_stream_caster_gb28181_host(c);
if (candidate == "*" || candidate == "0.0.0.0") {
std::vector<std::string> ips = srs_get_local_ips();
std::vector<SrsIPAddress*>& ips = srs_get_local_ips();
int index = _srs_config->get_stats_network();
return ips.at(index);
SrsIPAddress* ip = ips.at(index);
return ip->ip;
} else {
return candidate;
}

View file

@ -23,7 +23,7 @@
#include <srs_app_hds.hpp>
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
#include <unistd.h>
#include <string>

View file

@ -26,7 +26,7 @@
#include <srs_core.hpp>
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
#include <list>

View file

@ -65,10 +65,10 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
return srs_error_wrap(err, "http uri parse hartbeart url failed. url=%s", url.c_str());
}
std::string ip = "";
SrsIPAddress* ip = NULL;
std::string device_id = _srs_config->get_heartbeat_device_id();
vector<string>& ips = srs_get_local_ips();
vector<SrsIPAddress*>& ips = srs_get_local_ips();
if (!ips.empty()) {
ip = ips[_srs_config->get_stats_network() % (int)ips.size()];
}
@ -77,7 +77,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
SrsAutoFree(SrsJsonObject, obj);
obj->set("device_id", SrsJsonAny::str(device_id.c_str()));
obj->set("ip", SrsJsonAny::str(ip.c_str()));
obj->set("ip", SrsJsonAny::str(ip->ip.c_str()));
if (_srs_config->get_heartbeat_summaries()) {
SrsJsonObject* summaries = SrsJsonAny::object();

View file

@ -55,7 +55,7 @@ using namespace std;
// drop the segment when duration of ts too small.
// TODO: FIXME: Refine to time unit.
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION (100 * SRS_UTIME_MILLISECONDS)
#define SRS_HLS_SEGMENT_MIN_DURATION (100 * SRS_UTIME_MILLISECONDS)
// fragment plus the deviation percent.
#define SRS_HLS_FLOOR_REAP_PERCENT 0.3
@ -498,7 +498,7 @@ bool SrsHlsMuxer::is_segment_overflow()
srs_assert(current);
// to prevent very small segment.
if (current->duration() < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION) {
if (current->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
return false;
}
@ -518,7 +518,7 @@ bool SrsHlsMuxer::is_segment_absolutely_overflow()
srs_assert(current);
// to prevent very small segment.
if (current->duration() < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION) {
if (current->duration() < 2 * SRS_HLS_SEGMENT_MIN_DURATION) {
return false;
}
@ -619,7 +619,7 @@ srs_error_t SrsHlsMuxer::do_segment_close()
// when too small, it maybe not enough data to play.
// when too large, it maybe timestamp corrupt.
// make the segment more acceptable, when in [min, max_td * 2], it's ok.
bool matchMinDuration = current->duration() >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION;
bool matchMinDuration = current->duration() >= SRS_HLS_SEGMENT_MIN_DURATION;
bool matchMaxDuration = current->duration() <= max_td * 2 * 1000;
if (matchMinDuration && matchMaxDuration) {
// use async to call the http hooks, for it will cause thread switch.

View file

@ -26,6 +26,7 @@
#include <sstream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
using namespace std;
#include <srs_kernel_log.hpp>
@ -46,8 +47,9 @@ using namespace std;
#include <srs_protocol_amf0.hpp>
#include <srs_protocol_utility.hpp>
#include <srs_app_coworkers.hpp>
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtc_server.hpp>
#endif
srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data)
@ -203,6 +205,18 @@ srs_error_t SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
urls->set("api", SrsJsonAny::str("the api root"));
if (true) {
SrsJsonObject* rtc = SrsJsonAny::object();
urls->set("rtc", rtc);
SrsJsonObject* v1 = SrsJsonAny::object();
rtc->set("v1", v1);
v1->set("play", SrsJsonAny::str("Play stream"));
v1->set("publish", SrsJsonAny::str("Publish stream"));
v1->set("nack", SrsJsonAny::str("Simulate the NACK"));
}
return srs_api_response(w, r, obj->dumps());
}
@ -556,7 +570,7 @@ srs_error_t SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
obj->set("data", data);
data->set("license", SrsJsonAny::str(RTMP_SIG_SRS_LICENSE));
data->set("contributors", SrsJsonAny::str(SRS_AUTO_CONSTRIBUTORS));
data->set("contributors", SrsJsonAny::str(SRS_CONSTRIBUTORS));
return srs_api_response(w, r, obj->dumps());
}
@ -582,17 +596,17 @@ srs_error_t SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
SrsJsonObject* data = SrsJsonAny::object();
obj->set("data", data);
data->set("options", SrsJsonAny::str(SRS_AUTO_USER_CONFIGURE));
data->set("options2", SrsJsonAny::str(SRS_AUTO_CONFIGURE));
data->set("build", SrsJsonAny::str(SRS_AUTO_BUILD_DATE));
data->set("build2", SrsJsonAny::str(SRS_AUTO_BUILD_TS));
data->set("options", SrsJsonAny::str(SRS_USER_CONFIGURE));
data->set("options2", SrsJsonAny::str(SRS_CONFIGURE));
data->set("build", SrsJsonAny::str(SRS_BUILD_DATE));
data->set("build2", SrsJsonAny::str(SRS_BUILD_TS));
SrsJsonObject* features = SrsJsonAny::object();
data->set("features", features);
features->set("ssl", SrsJsonAny::boolean(true));
features->set("hls", SrsJsonAny::boolean(true));
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
features->set("hds", SrsJsonAny::boolean(true));
#else
features->set("hds", SrsJsonAny::boolean(false));
@ -785,12 +799,12 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
return srs_api_response(w, r, obj->dumps());
}
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
uint32_t SrsGoApiRtcPlay::ssrc_num = 0;
SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsRtcServer* rtc_svr)
SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsRtcServer* server)
{
rtc_server = rtc_svr;
server_ = server;
}
SrsGoApiRtcPlay::~SrsGoApiRtcPlay()
@ -841,7 +855,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
SrsJsonAny* json = SrsJsonAny::loads(req_json);
if (!json || !json->is_object()) {
return srs_error_wrap(err, "not json");
return srs_error_new(ERROR_RTC_API_BODY, "invalid body %s", req_json.c_str());
}
req = json->to_object();
@ -901,11 +915,6 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
return srs_error_wrap(err, "remote sdp check failed");
}
SrsSdp local_sdp;
if ((err = exchange_sdp(app, stream_name, remote_sdp, local_sdp)) != srs_success) {
return srs_error_wrap(err, "remote sdp have error or unsupport attributes");
}
SrsRequest request;
request.app = app;
request.stream = stream_name;
@ -917,13 +926,31 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
request.vhost = parsed_vhost->arg0();
}
// TODO: FIXME: Maybe need a better name?
SrsSdp local_sdp;
if ((err = exchange_sdp(&request, remote_sdp, local_sdp)) != srs_success) {
return srs_error_wrap(err, "remote sdp have error or unsupport attributes");
}
// Whether enabled.
bool server_enabled = _srs_config->get_rtc_server_enabled();
bool rtc_enabled = _srs_config->get_rtc_enabled(request.vhost);
if (server_enabled && !rtc_enabled) {
srs_warn("RTC disabled in vhost %s", request.vhost.c_str());
}
if (!server_enabled || !rtc_enabled) {
return srs_error_new(ERROR_RTC_DISABLED, "Disabled server=%d, rtc=%d, vhost=%s",
server_enabled, rtc_enabled, request.vhost.c_str());
}
// 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* session = NULL;
if ((err = server_->create_session(&request, remote_sdp, local_sdp, eip, false, &session)) != srs_success) {
return srs_error_wrap(err, "create session");
}
if (encrypt.empty()) {
rtc_session->set_encrypt(_srs_config->get_rtc_server_encrypt());
session->set_encrypt(_srs_config->get_rtc_server_encrypt());
} else {
rtc_session->set_encrypt(encrypt != "false");
session->set_encrypt(encrypt != "false");
}
ostringstream os;
@ -941,9 +968,10 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
// TODO: add candidates in response json?
res->set("sdp", SrsJsonAny::str(local_sdp_str.c_str()));
res->set("sessionid", SrsJsonAny::str(rtc_session->id().c_str()));
res->set("sessionid", SrsJsonAny::str(session->username().c_str()));
srs_trace("RTC sid=%s, offer=%dB, answer=%dB", rtc_session->id().c_str(), remote_sdp_str.length(), local_sdp_str.length());
srs_trace("RTC username=%s, offer=%dB, answer=%dB", session->username().c_str(),
remote_sdp_str.length(), local_sdp_str.length());
return err;
}
@ -979,7 +1007,7 @@ srs_error_t SrsGoApiRtcPlay::check_remote_sdp(const SrsSdp& remote_sdp)
return err;
}
srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::string& stream, const SrsSdp& remote_sdp, SrsSdp& local_sdp)
srs_error_t SrsGoApiRtcPlay::exchange_sdp(SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp)
{
srs_error_t err = srs_success;
local_sdp.version_ = "0";
@ -991,13 +1019,15 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::str
local_sdp.addrtype_ = "IP4";
local_sdp.unicast_address_ = "0.0.0.0";
local_sdp.session_name_ = "live_play_session";
local_sdp.session_name_ = "SRSPlaySession";
local_sdp.msid_semantic_ = "WMS";
local_sdp.msids_.push_back(app + "/" + stream);
local_sdp.msids_.push_back(req->app + "/" + req->stream);
local_sdp.group_policy_ = "BUNDLE";
bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost);
for (size_t i = 0; i < remote_sdp.media_descs_.size(); ++i) {
const SrsMediaDesc& remote_media_desc = remote_sdp.media_descs_[i];
@ -1013,15 +1043,27 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::str
// TODO: check opus format specific param
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("opus");
for (std::vector<SrsMediaPayloadType>::iterator iter = payloads.begin(); iter != payloads.end(); ++iter) {
// Only choose one match opus codec.
local_media_desc.payload_types_.push_back(*iter);
SrsMediaPayloadType& payload_type = local_media_desc.payload_types_.back();
// TODO: FIXME: Only support some transport algorithms.
vector<string> rtcp_fb;
payload_type.rtcp_fb_.swap(rtcp_fb);
for (int j = 0; j < (int)rtcp_fb.size(); j++) {
if (nack_enabled) {
if (rtcp_fb.at(j) == "nack" || rtcp_fb.at(j) == "nack pli") {
payload_type.rtcp_fb_.push_back(rtcp_fb.at(j));
}
}
}
// Only choose one match opus codec.
break;
}
if (local_media_desc.payload_types_.empty()) {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no found valid opus payload type");
}
} else if (remote_media_desc.is_video()) {
std::deque<SrsMediaPayloadType> backup_payloads;
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H264");
@ -1037,8 +1079,21 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::str
// Try to pick the "best match" H.264 payload type.
if (h264_param.packetization_mode == "1" && h264_param.level_asymmerty_allow == "1") {
// Only choose first match H.264 payload type.
local_media_desc.payload_types_.push_back(*iter);
SrsMediaPayloadType& payload_type = local_media_desc.payload_types_.back();
// TODO: FIXME: Only support some transport algorithms.
vector<string> rtcp_fb;
payload_type.rtcp_fb_.swap(rtcp_fb);
for (int j = 0; j < (int)rtcp_fb.size(); j++) {
if (nack_enabled) {
if (rtcp_fb.at(j) == "nack" || rtcp_fb.at(j) == "nack pli") {
payload_type.rtcp_fb_.push_back(rtcp_fb.at(j));
}
}
}
// Only choose first match H.264 payload type.
break;
}
@ -1068,6 +1123,11 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::str
local_media_desc.session_info_.setup_ = "active";
} else if (remote_media_desc.session_info_.setup_ == "actpass") {
local_media_desc.session_info_.setup_ = "passive";
} else {
// @see: https://tools.ietf.org/html/rfc4145#section-4.1
// The default value of the setup attribute in an offer/answer exchange
// is 'active' in the offer and 'passive' in the answer.
local_media_desc.session_info_.setup_ = "passive";
}
if (remote_media_desc.sendonly_) {
@ -1081,16 +1141,416 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(const std::string& app, const std::str
local_media_desc.rtcp_mux_ = true;
local_media_desc.rtcp_rsize_ = true;
SrsSSRCInfo ssrc_info;
ssrc_info.ssrc_ = ++ssrc_num;
// TODO:use formated cname
ssrc_info.cname_ = "test_sdp_cname";
local_media_desc.ssrc_infos_.push_back(ssrc_info);
// TODO: FIXME: Avoid SSRC collision.
if (!ssrc_num) {
ssrc_num = ::getpid() * 10000 + ::getpid() * 100 + ::getpid();
}
if (local_media_desc.sendonly_ || local_media_desc.sendrecv_) {
SrsSSRCInfo ssrc_info;
ssrc_info.ssrc_ = ++ssrc_num;
// TODO:use formated cname
ssrc_info.cname_ = "test_sdp_cname";
local_media_desc.ssrc_infos_.push_back(ssrc_info);
}
}
return err;
}
uint32_t SrsGoApiRtcPublish::ssrc_num = 0;
SrsGoApiRtcPublish::SrsGoApiRtcPublish(SrsRtcServer* server)
{
server_ = server;
}
SrsGoApiRtcPublish::~SrsGoApiRtcPublish()
{
}
// Request:
// POST /rtc/v1/publish/
// {
// "sdp":"offer...", "streamurl":"webrtc://r.ossrs.net/live/livestream",
// "api":'http...", "clientip":"..."
// }
// Response:
// {"sdp":"answer...", "sid":"..."}
// @see https://github.com/rtcdn/rtcdn-draft
srs_error_t SrsGoApiRtcPublish::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
srs_error_t err = srs_success;
SrsJsonObject* res = SrsJsonAny::object();
SrsAutoFree(SrsJsonObject, res);
if ((err = do_serve_http(w, r, res)) != srs_success) {
srs_warn("RTC error %s", srs_error_desc(err).c_str()); srs_freep(err);
return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest);
}
return srs_api_response(w, r, res->dumps());
}
srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res)
{
srs_error_t err = srs_success;
// For each RTC session, we use short-term HTTP connection.
SrsHttpHeader* hdr = w->header();
hdr->set("Connection", "Close");
// Parse req, the request json object, from body.
SrsJsonObject* req = NULL;
if (true) {
string req_json;
if ((err = r->body_read_all(req_json)) != srs_success) {
return srs_error_wrap(err, "read body");
}
SrsJsonAny* json = SrsJsonAny::loads(req_json);
if (!json || !json->is_object()) {
return srs_error_new(ERROR_RTC_API_BODY, "invalid body %s", req_json.c_str());
}
req = json->to_object();
}
// Fetch params from req object.
SrsJsonAny* prop = NULL;
if ((prop = req->ensure_property_string("sdp")) == NULL) {
return srs_error_wrap(err, "not sdp");
}
string remote_sdp_str = prop->to_str();
if ((prop = req->ensure_property_string("streamurl")) == NULL) {
return srs_error_wrap(err, "not streamurl");
}
string streamurl = prop->to_str();
string clientip;
if ((prop = req->ensure_property_string("clientip")) != NULL) {
clientip = prop->to_str();
}
string api;
if ((prop = req->ensure_property_string("api")) != NULL) {
api = prop->to_str();
}
// Parse app and stream from streamurl.
string app;
string stream_name;
if (true) {
string tcUrl;
srs_parse_rtmp_url(streamurl, tcUrl, stream_name);
int port;
string schema, host, vhost, param;
srs_discovery_tc_url(tcUrl, schema, host, vhost, app, stream_name, port, param);
}
// For client to specifies the EIP of server.
string eip = r->query_get("eip");
srs_trace("RTC publish %s, api=%s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s",
streamurl.c_str(), api.c_str(), clientip.c_str(), app.c_str(), stream_name.c_str(), remote_sdp_str.length(), eip.c_str());
// TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information.
SrsSdp remote_sdp;
if ((err = remote_sdp.parse(remote_sdp_str)) != srs_success) {
return srs_error_wrap(err, "parse sdp failed: %s", remote_sdp_str.c_str());
}
if ((err = check_remote_sdp(remote_sdp)) != srs_success) {
return srs_error_wrap(err, "remote sdp check failed");
}
SrsRequest request;
request.app = app;
request.stream = stream_name;
// TODO: FIXME: Parse vhost.
// discovery vhost, resolve the vhost from config
SrsConfDirective* parsed_vhost = _srs_config->get_vhost("");
if (parsed_vhost) {
request.vhost = parsed_vhost->arg0();
}
SrsSdp local_sdp;
if ((err = exchange_sdp(&request, remote_sdp, local_sdp)) != srs_success) {
return srs_error_wrap(err, "remote sdp have error or unsupport attributes");
}
// Whether enabled.
bool server_enabled = _srs_config->get_rtc_server_enabled();
bool rtc_enabled = _srs_config->get_rtc_enabled(request.vhost);
if (server_enabled && !rtc_enabled) {
srs_warn("RTC disabled in vhost %s", request.vhost.c_str());
}
if (!server_enabled || !rtc_enabled) {
return srs_error_new(ERROR_RTC_DISABLED, "Disabled server=%d, rtc=%d, vhost=%s",
server_enabled, rtc_enabled, request.vhost.c_str());
}
// TODO: FIXME: When server enabled, but vhost disabled, should report error.
SrsRtcSession* session = NULL;
if ((err = server_->create_session(&request, remote_sdp, local_sdp, eip, true, &session)) != srs_success) {
return srs_error_wrap(err, "create session");
}
ostringstream os;
if ((err = local_sdp.encode(os)) != srs_success) {
return srs_error_wrap(err, "encode sdp");
}
string local_sdp_str = os.str();
srs_verbose("local_sdp=%s", local_sdp_str.c_str());
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
res->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id()));
// TODO: add candidates in response json?
res->set("sdp", SrsJsonAny::str(local_sdp_str.c_str()));
res->set("sessionid", SrsJsonAny::str(session->username().c_str()));
srs_trace("RTC username=%s, offer=%dB, answer=%dB", session->username().c_str(),
remote_sdp_str.length(), local_sdp_str.length());
return err;
}
srs_error_t SrsGoApiRtcPublish::check_remote_sdp(const SrsSdp& remote_sdp)
{
srs_error_t err = srs_success;
if (remote_sdp.group_policy_ != "BUNDLE") {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "now only support BUNDLE, group policy=%s", remote_sdp.group_policy_.c_str());
}
if (remote_sdp.media_descs_.empty()) {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no media descriptions");
}
for (std::vector<SrsMediaDesc>::const_iterator iter = remote_sdp.media_descs_.begin(); iter != remote_sdp.media_descs_.end(); ++iter) {
if (iter->type_ != "audio" && iter->type_ != "video") {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "unsupport media type=%s", iter->type_.c_str());
}
if (! iter->rtcp_mux_) {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "now only suppor rtcp-mux");
}
for (std::vector<SrsMediaPayloadType>::const_iterator iter_media = iter->payload_types_.begin(); iter_media != iter->payload_types_.end(); ++iter_media) {
if (iter->recvonly_) {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "publish API only support sendrecv/sendonly");
}
}
}
return err;
}
srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp)
{
srs_error_t err = srs_success;
local_sdp.version_ = "0";
local_sdp.username_ = RTMP_SIG_SRS_SERVER;
local_sdp.session_id_ = srs_int2str((int64_t)this);
local_sdp.session_version_ = "2";
local_sdp.nettype_ = "IN";
local_sdp.addrtype_ = "IP4";
local_sdp.unicast_address_ = "0.0.0.0";
local_sdp.session_name_ = "SRSPublishSession";
local_sdp.msid_semantic_ = "WMS";
local_sdp.msids_.push_back(req->app + "/" + req->stream);
local_sdp.group_policy_ = "BUNDLE";
bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost);
for (size_t i = 0; i < remote_sdp.media_descs_.size(); ++i) {
const SrsMediaDesc& remote_media_desc = remote_sdp.media_descs_[i];
if (remote_media_desc.is_audio()) {
local_sdp.media_descs_.push_back(SrsMediaDesc("audio"));
} else if (remote_media_desc.is_video()) {
local_sdp.media_descs_.push_back(SrsMediaDesc("video"));
}
SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back();
if (remote_media_desc.is_audio()) {
// TODO: check opus format specific param
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("opus");
for (std::vector<SrsMediaPayloadType>::iterator iter = payloads.begin(); iter != payloads.end(); ++iter) {
local_media_desc.payload_types_.push_back(*iter);
SrsMediaPayloadType& payload_type = local_media_desc.payload_types_.back();
// TODO: FIXME: Only support some transport algorithms.
vector<string> rtcp_fb;
payload_type.rtcp_fb_.swap(rtcp_fb);
for (int j = 0; j < (int)rtcp_fb.size(); j++) {
if (nack_enabled) {
if (rtcp_fb.at(j) == "nack" || rtcp_fb.at(j) == "nack pli") {
payload_type.rtcp_fb_.push_back(rtcp_fb.at(j));
}
}
}
// Only choose one match opus codec.
break;
}
if (local_media_desc.payload_types_.empty()) {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no valid found opus payload type");
}
} else if (remote_media_desc.is_video()) {
std::deque<SrsMediaPayloadType> backup_payloads;
std::vector<SrsMediaPayloadType> payloads = remote_media_desc.find_media_with_encoding_name("H264");
for (std::vector<SrsMediaPayloadType>::iterator iter = payloads.begin(); iter != payloads.end(); ++iter) {
if (iter->format_specific_param_.empty()) {
backup_payloads.push_front(*iter);
continue;
}
H264SpecificParam h264_param;
if ((err = parse_h264_fmtp(iter->format_specific_param_, h264_param)) != srs_success) {
srs_error_reset(err); continue;
}
// Try to pick the "best match" H.264 payload type.
if (h264_param.packetization_mode == "1" && h264_param.level_asymmerty_allow == "1") {
local_media_desc.payload_types_.push_back(*iter);
SrsMediaPayloadType& payload_type = local_media_desc.payload_types_.back();
// TODO: FIXME: Only support some transport algorithms.
vector<string> rtcp_fb;
payload_type.rtcp_fb_.swap(rtcp_fb);
for (int j = 0; j < (int)rtcp_fb.size(); j++) {
if (nack_enabled) {
if (rtcp_fb.at(j) == "nack" || rtcp_fb.at(j) == "nack pli") {
payload_type.rtcp_fb_.push_back(rtcp_fb.at(j));
}
}
}
// Only choose first match H.264 payload type.
break;
}
backup_payloads.push_back(*iter);
}
// Try my best to pick at least one media payload type.
if (local_media_desc.payload_types_.empty() && ! backup_payloads.empty()) {
srs_warn("choose backup H.264 payload type=%d", backup_payloads.front().payload_type_);
local_media_desc.payload_types_.push_back(backup_payloads.front());
}
if (local_media_desc.payload_types_.empty()) {
return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no found valid H.264 payload type");
}
// TODO: FIXME: Support RRTR?
//local_media_desc.payload_types_.back().rtcp_fb_.push_back("rrtr");
}
local_media_desc.mid_ = remote_media_desc.mid_;
local_sdp.groups_.push_back(local_media_desc.mid_);
local_media_desc.port_ = 9;
local_media_desc.protos_ = "UDP/TLS/RTP/SAVPF";
if (remote_media_desc.session_info_.setup_ == "active") {
local_media_desc.session_info_.setup_ = "passive";
} else if (remote_media_desc.session_info_.setup_ == "passive") {
local_media_desc.session_info_.setup_ = "active";
} else if (remote_media_desc.session_info_.setup_ == "actpass") {
local_media_desc.session_info_.setup_ = "passive";
} else {
// @see: https://tools.ietf.org/html/rfc4145#section-4.1
// The default value of the setup attribute in an offer/answer exchange
// is 'active' in the offer and 'passive' in the answer.
local_media_desc.session_info_.setup_ = "passive";
}
local_media_desc.rtcp_mux_ = true;
// For publisher, we are always sendonly.
local_media_desc.sendonly_ = false;
local_media_desc.recvonly_ = true;
local_media_desc.sendrecv_ = false;
}
return err;
}
#ifdef SRS_SIMULATOR
SrsGoApiRtcNACK::SrsGoApiRtcNACK(SrsRtcServer* server)
{
server_ = server;
}
SrsGoApiRtcNACK::~SrsGoApiRtcNACK()
{
}
srs_error_t SrsGoApiRtcNACK::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
srs_error_t err = srs_success;
SrsJsonObject* res = SrsJsonAny::object();
SrsAutoFree(SrsJsonObject, res);
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
if ((err = do_serve_http(w, r, res)) != srs_success) {
srs_warn("RTC NACK err %s", srs_error_desc(err).c_str());
res->set("code", SrsJsonAny::integer(srs_error_code(err)));
srs_freep(err);
}
return srs_api_response(w, r, res->dumps());
}
srs_error_t SrsGoApiRtcNACK::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res)
{
string username = r->query_get("username");
string dropv = r->query_get("drop");
SrsJsonObject* query = SrsJsonAny::object();
res->set("query", query);
query->set("username", SrsJsonAny::str(username.c_str()));
query->set("drop", SrsJsonAny::str(dropv.c_str()));
query->set("help", SrsJsonAny::str("?username=string&drop=int"));
int drop = ::atoi(dropv.c_str());
if (drop <= 0) {
return srs_error_new(ERROR_RTC_INVALID_PARAMS, "invalid drop=%s/%d", dropv.c_str(), drop);
}
SrsRtcSession* session = server_->find_session_by_username(username);
if (!session) {
return srs_error_new(ERROR_RTC_NO_SESSION, "no session username=%s", username.c_str());
}
session->simulate_nack_drop(drop);
srs_trace("RTC NACK session peer_id=%s, username=%s, drop=%s/%d", session->peer_id().c_str(),
username.c_str(), dropv.c_str(), drop);
return srs_success;
}
#endif
#endif
SrsGoApiClients::SrsGoApiClients()
@ -1730,7 +2190,7 @@ srs_error_t SrsGoApiError::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage
return srs_api_response_code(w, r, 100);
}
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
SrsGoApiGb28181::SrsGoApiGb28181()
{
}
@ -1913,7 +2373,7 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
}
#endif
#ifdef SRS_AUTO_GPERF
#ifdef SRS_GPERF
#include <gperftools/malloc_extension.h>
SrsGoApiTcmalloc::SrsGoApiTcmalloc()

View file

@ -34,6 +34,7 @@ class SrsServer;
class SrsRtcServer;
class SrsJsonObject;
class SrsSdp;
class SrsRequest;
#include <srs_app_st.hpp>
#include <srs_app_conn.hpp>
@ -167,23 +168,55 @@ public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
};
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
class SrsGoApiRtcPlay : public ISrsHttpHandler
{
public:
static uint32_t ssrc_num;
private:
SrsRtcServer* rtc_server;
SrsRtcServer* server_;
public:
SrsGoApiRtcPlay(SrsRtcServer* rtc_svr);
SrsGoApiRtcPlay(SrsRtcServer* server);
virtual ~SrsGoApiRtcPlay();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
private:
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res);
srs_error_t exchange_sdp(const std::string& app, const std::string& stream, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
srs_error_t exchange_sdp(SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
srs_error_t check_remote_sdp(const SrsSdp& remote_sdp);
};
class SrsGoApiRtcPublish : public ISrsHttpHandler
{
public:
static uint32_t ssrc_num;
private:
SrsRtcServer* server_;
public:
SrsGoApiRtcPublish(SrsRtcServer* server);
virtual ~SrsGoApiRtcPublish();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
private:
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res);
srs_error_t exchange_sdp(SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
srs_error_t check_remote_sdp(const SrsSdp& remote_sdp);
};
#ifdef SRS_SIMULATOR
class SrsGoApiRtcNACK : public ISrsHttpHandler
{
private:
SrsRtcServer* server_;
public:
SrsGoApiRtcNACK(SrsRtcServer* server);
virtual ~SrsGoApiRtcNACK();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
private:
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res);
};
#endif
#endif
class SrsGoApiClients : public ISrsHttpHandler
@ -241,7 +274,7 @@ public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
};
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
class SrsGoApiGb28181 : public ISrsHttpHandler
{
public:
@ -254,7 +287,7 @@ private:
};
#endif
#ifdef SRS_AUTO_GPERF
#ifdef SRS_GPERF
class SrsGoApiTcmalloc : public ISrsHttpHandler
{
public:

View file

@ -128,10 +128,13 @@ srs_error_t SrsBufferCache::cycle()
// the stream cache will create consumer to cache stream,
// which will trigger to fetch stream from origin for edge.
SrsConsumer* consumer = NULL;
if ((err = source->create_consumer(NULL, consumer, false, false, true)) != srs_success) {
SrsAutoFree(SrsConsumer, consumer);
if ((err = source->create_consumer(NULL, consumer)) != srs_success) {
return srs_error_wrap(err, "create consumer");
}
SrsAutoFree(SrsConsumer, consumer);
if ((err = source->consumer_dumps(consumer, false, false, true)) != srs_success) {
return srs_error_wrap(err, "dumps consumer");
}
SrsPithyPrint* pprint = SrsPithyPrint::create_http_stream_cache();
SrsAutoFree(SrsPithyPrint, pprint);
@ -583,11 +586,13 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
// create consumer of souce, ignore gop cache, use the audio gop cache.
SrsConsumer* consumer = NULL;
if ((err = source->create_consumer(NULL, consumer, true, true, !enc->has_cache())) != srs_success) {
SrsAutoFree(SrsConsumer, consumer);
if ((err = source->create_consumer(NULL, consumer)) != srs_success) {
return srs_error_wrap(err, "create consumer");
}
SrsAutoFree(SrsConsumer, consumer);
srs_verbose("http: consumer created success.");
if ((err = source->consumer_dumps(consumer, true, true, !enc->has_cache())) != srs_success) {
return srs_error_wrap(err, "dumps consumer");
}
SrsPithyPrint* pprint = SrsPithyPrint::create_http_stream();
SrsAutoFree(SrsPithyPrint, pprint);

View file

@ -194,7 +194,7 @@ void SrsIngester::fast_kill()
// when error, ingester sleep for a while and retry.
// ingest never sleep a long time, for we must start the stream ASAP.
#define SRS_AUTO_INGESTER_CIMS (3 * SRS_UTIME_SECONDS)
#define SRS_INGESTER_CIMS (3 * SRS_UTIME_SECONDS)
srs_error_t SrsIngester::cycle()
{
@ -212,7 +212,7 @@ srs_error_t SrsIngester::cycle()
srs_freep(err);
}
srs_usleep(SRS_AUTO_INGESTER_CIMS);
srs_usleep(SRS_INGESTER_CIMS);
}
return err;

View file

@ -261,23 +261,6 @@ SrsUdpMuxSocket::~SrsUdpMuxSocket()
srs_freepa(buf);
}
SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly()
{
SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(handler, lfd);
// Don't copy buffer
srs_freepa(sendonly->buf);
sendonly->nb_buf = 0;
sendonly->nread = 0;
sendonly->lfd = lfd;
sendonly->from = from;
sendonly->fromlen = fromlen;
sendonly->peer_ip = peer_ip;
sendonly->peer_port = peer_port;
return sendonly;
}
int SrsUdpMuxSocket::recvfrom(srs_utime_t timeout)
{
fromlen = sizeof(from);
@ -341,7 +324,27 @@ socklen_t SrsUdpMuxSocket::peer_addrlen()
return (socklen_t)fromlen;
}
std::string SrsUdpMuxSocket::get_peer_id()
char* SrsUdpMuxSocket::data()
{
return buf;
}
int SrsUdpMuxSocket::size()
{
return nread;
}
std::string SrsUdpMuxSocket::get_peer_ip() const
{
return peer_ip;
}
int SrsUdpMuxSocket::get_peer_port() const
{
return peer_port;
}
std::string SrsUdpMuxSocket::peer_id()
{
char id_buf[1024];
int len = snprintf(id_buf, sizeof(id_buf), "%s:%d", peer_ip.c_str(), peer_port);
@ -349,6 +352,28 @@ std::string SrsUdpMuxSocket::get_peer_id()
return string(id_buf, len);
}
SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly()
{
SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(handler, lfd);
// Don't copy buffer
srs_freepa(sendonly->buf);
sendonly->nb_buf = 0;
sendonly->nread = 0;
sendonly->lfd = lfd;
sendonly->from = from;
sendonly->fromlen = fromlen;
sendonly->peer_ip = peer_ip;
sendonly->peer_port = peer_port;
return sendonly;
}
ISrsUdpSender* SrsUdpMuxSocket::sender()
{
return handler;
}
SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, ISrsUdpSender* s, std::string i, int p)
{
handler = h;
@ -460,6 +485,10 @@ srs_error_t SrsUdpMuxListener::cycle()
nn_loop++;
// TODO: FIXME: Refactor the memory cache for receiver.
// Because we have to decrypt the cipher of received packet payload,
// and the size is not determined, so we think there is at least one copy,
// and we can reuse the plaintext h264/opus with players when got plaintext.
SrsUdpMuxSocket skt(sender, lfd);
int nread = skt.recvfrom(SRS_UTIME_NO_TIMEOUT);

View file

@ -138,9 +138,9 @@ public:
virtual ~ISrsUdpSender();
public:
// Fetch a mmsghdr from sender's cache.
virtual srs_error_t fetch(mmsghdr** pphdr) = 0;
virtual srs_error_t fetch(srs_mmsghdr** pphdr) = 0;
// Notify the sender to send out the msg.
virtual srs_error_t sendmmsg(mmsghdr* hdr) = 0;
virtual srs_error_t sendmmsg(srs_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.
@ -163,26 +163,19 @@ private:
public:
SrsUdpMuxSocket(ISrsUdpSender* h, srs_netfd_t fd);
virtual ~SrsUdpMuxSocket();
public:
int recvfrom(srs_utime_t timeout);
srs_error_t sendto(void* data, int size, srs_utime_t timeout);
srs_netfd_t stfd();
sockaddr_in* peer_addr();
socklen_t peer_addrlen();
char* data() { return buf; }
int size() { return nread; }
std::string get_peer_ip() const { return peer_ip; }
int get_peer_port() const { return peer_port; }
std::string get_peer_id();
public:
char* data();
int size();
std::string get_peer_ip() const;
int get_peer_port() const;
std::string peer_id();
SrsUdpMuxSocket* copy_sendonly();
ISrsUdpSender* sender() { return handler; };
private:
// Don't allow copy, user copy_sendonly instead
SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs);
SrsUdpMuxSocket& operator=(const SrsUdpMuxSocket& rhs);
ISrsUdpSender* sender();
};
class SrsUdpMuxListener : public ISrsCoroutineHandler

View file

@ -38,7 +38,7 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_kernel_codec.hpp>
#include <srs_kernel_flv.hpp>
#include <srs_kernel_rtp.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_app_config.hpp>
#include <srs_app_source.hpp>
#include <srs_core_autofree.hpp>
@ -51,7 +51,7 @@ using namespace std;
#include <srs_protocol_format.hpp>
#include <srs_rtmp_stack.hpp>
#include <openssl/rand.h>
#include <srs_app_audio_recode.hpp>
#include <srs_app_rtc_codec.hpp>
// TODO: Add this function into SrsRtpMux class.
srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFormat* format, char** pbuf, int* pnn_buf)
@ -276,7 +276,7 @@ srs_error_t SrsRtc::on_publish()
return err;
}
if (!_srs_config->get_rtc_enabled(req->vhost)) {
if (!_srs_config->get_rtc_enabled(req->vhost)) {
return err;
}

View file

@ -33,7 +33,6 @@
class SrsFormat;
class SrsSample;
class SrsSharedPtrMessage;
class SrsRtpSharedPacket;
class SrsRequest;
class SrsOriginHub;
class SrsAudioRecode;

View file

@ -24,7 +24,7 @@
#include <srs_kernel_codec.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_audio_recode.hpp>
#include <srs_app_rtc_codec.hpp>
static const int kOpusPacketMs = 20;
static const int kOpusMaxbytes = 8000;

View file

@ -21,8 +21,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_APP_AUDIO_RECODE_HPP
#define SRS_APP_AUDIO_RECODE_HPP
#ifndef SRS_APP_RTC_CODEC_HPP
#define SRS_APP_RTC_CODEC_HPP
#include <srs_core.hpp>

File diff suppressed because it is too large Load diff

View file

@ -31,8 +31,10 @@
#include <srs_rtmp_stack.hpp>
#include <srs_app_hybrid.hpp>
#include <srs_app_hourglass.hpp>
#include <srs_app_sdp.hpp>
#include <srs_app_rtc_sdp.hpp>
#include <srs_app_reload.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_app_rtc_queue.hpp>
#include <string>
#include <map>
@ -51,6 +53,13 @@ class SrsSharedPtrMessage;
class SrsSource;
class SrsRtpPacket2;
class ISrsUdpSender;
class SrsRtpQueue;
class SrsRtpAudioQueue;
class SrsRtpVideoQueue;
class SrsRtpPacket2;
class ISrsCodec;
class SrsRtpNackForReceiver;
class SrsRtpIncommingVideoFrame;
const uint8_t kSR = 200;
const uint8_t kRR = 201;
@ -61,6 +70,7 @@ const uint8_t kApp = 204;
// @see: https://tools.ietf.org/html/rfc4585#section-6.1
const uint8_t kRtpFb = 205;
const uint8_t kPsFb = 206;
const uint8_t kXR = 207;
// @see: https://tools.ietf.org/html/rfc4585#section-6.3
const uint8_t kPLI = 1;
@ -68,20 +78,40 @@ const uint8_t kSLI = 2;
const uint8_t kRPSI = 3;
const uint8_t kAFB = 15;
extern std::string gen_random_str(int len);
class SrsNtp
{
public:
uint64_t system_ms_;
uint64_t ntp_;
uint32_t ntp_second_;
uint32_t ntp_fractions_;
public:
SrsNtp();
virtual ~SrsNtp();
public:
static SrsNtp from_time_ms(uint64_t ms);
static SrsNtp to_time_ms(uint64_t ntp);
public:
static uint64_t kMagicNtpFractionalUnit;
};
enum SrsRtcSessionStateType
{
// TODO: FIXME: Should prefixed by enum name.
INIT = -1,
WAITING_STUN = 1,
DOING_DTLS_HANDSHAKE = 2,
ESTABLISHED = 3,
CLOSED = 4,
WAITING_ANSWER = 1,
WAITING_STUN = 2,
DOING_DTLS_HANDSHAKE = 3,
ESTABLISHED = 4,
CLOSED = 5,
};
class SrsDtlsSession
class SrsRtcDtls
{
private:
SrsRtcSession* rtc_session;
SrsRtcSession* session_;
SSL* dtls;
BIO* bio_in;
@ -96,13 +126,13 @@ private:
bool handshake_done;
public:
SrsDtlsSession(SrsRtcSession* s);
virtual ~SrsDtlsSession();
SrsRtcDtls(SrsRtcSession* s);
virtual ~SrsRtcDtls();
srs_error_t initialize(const SrsRequest& req);
srs_error_t initialize(SrsRequest* r);
srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* skt);
srs_error_t on_dtls(char* data, int nb_data);
srs_error_t on_dtls_handshake_done();
srs_error_t on_dtls_application_data(const char* data, const int len);
public:
srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf);
@ -111,15 +141,15 @@ public:
srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf);
srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf);
private:
srs_error_t handshake(SrsUdpMuxSocket* skt);
srs_error_t handshake();
private:
srs_error_t srtp_initialize();
srs_error_t srtp_send_init();
srs_error_t srtp_recv_init();
};
// A group of RTP packets.
class SrsRtcPackets
// A group of RTP packets for outgoing(send to players).
class SrsRtcOutgoingPackets
{
public:
bool use_gso;
@ -158,8 +188,8 @@ private:
int nn_cache;
SrsRtpPacket2* cache;
public:
SrsRtcPackets(int nn_cache_max);
virtual ~SrsRtcPackets();
SrsRtcOutgoingPackets(int nn_cache_max);
virtual ~SrsRtcOutgoingPackets();
public:
void reset(bool gso, bool merge_nalus);
SrsRtpPacket2* fetch();
@ -169,38 +199,42 @@ public:
SrsRtpPacket2* at(int index);
};
class SrsRtcSenderThread : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
class SrsRtcPlayer : virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
{
protected:
SrsCoroutine* trd;
int _parent_cid;
private:
SrsRtcSession* rtc_session;
uint32_t video_ssrc;
uint32_t audio_ssrc;
uint16_t video_payload_type;
uint16_t audio_payload_type;
SrsCoroutine* trd;
SrsRtcSession* session_;
private:
// TODO: FIXME: How to handle timestamp overflow?
// Information for audio.
uint32_t audio_timestamp;
uint16_t audio_sequence;
private:
uint32_t audio_ssrc;
uint16_t audio_payload_type;
// Information for video.
uint16_t video_sequence;
public:
SrsUdpMuxSocket* sendonly_ukt;
private:
ISrsUdpSender* sender;
uint16_t video_payload_type;
uint32_t video_ssrc;
// NACK ARQ ring buffer.
SrsRtpRingBuffer<SrsRtpPacket2*>* audio_queue_;
SrsRtpRingBuffer<SrsRtpPacket2*>* video_queue_;
// Simulators.
int nn_simulate_nack_drop;
private:
// For merged-write and GSO.
bool merge_nalus;
bool gso;
int max_padding;
private:
// For merged-write messages.
srs_utime_t mw_sleep;
int mw_msgs;
bool realtime;
// Whether enabled nack.
bool nack_enabled_;
public:
SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid);
virtual ~SrsRtcSenderThread();
SrsRtcPlayer(SrsRtcSession* s, int parent_cid);
virtual ~SrsRtcPlayer();
public:
srs_error_t initialize(const uint32_t& vssrc, const uint32_t& assrc, const uint16_t& v_pt, const uint16_t& a_pt);
// interface ISrsReloadHandler
@ -214,36 +248,113 @@ public:
virtual srs_error_t start();
virtual void stop();
virtual void stop_loop();
public:
void update_sendonly_socket(SrsUdpMuxSocket* skt);
public:
virtual srs_error_t cycle();
private:
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);
srs_error_t send_messages(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcOutgoingPackets& packets);
srs_error_t messages_to_packets(SrsSource* source, SrsSharedPtrMessage** msgs, int nb_msgs, SrsRtcOutgoingPackets& packets);
srs_error_t send_packets(SrsRtcOutgoingPackets& packets);
srs_error_t send_packets_gso(SrsRtcOutgoingPackets& packets);
private:
srs_error_t packet_opus(SrsSample* sample, SrsRtcPackets& packets, int nn_max_payload);
srs_error_t package_opus(SrsSample* sample, SrsRtcOutgoingPackets& 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);
srs_error_t package_fu_a(SrsSharedPtrMessage* msg, SrsSample* sample, int fu_payload_size, SrsRtcOutgoingPackets& packets);
srs_error_t package_nalus(SrsSharedPtrMessage* msg, SrsRtcOutgoingPackets& packets);
srs_error_t package_single_nalu(SrsSharedPtrMessage* msg, SrsSample* sample, SrsRtcOutgoingPackets& packets);
srs_error_t package_stap_a(SrsSource* source, SrsSharedPtrMessage* msg, SrsRtcOutgoingPackets& packets);
public:
void nack_fetch(std::vector<SrsRtpPacket2*>& pkts, uint32_t ssrc, uint16_t seq);
void simulate_nack_drop(int nn);
private:
void simulate_drop_packet(SrsRtpHeader* h, int nn_bytes);
public:
srs_error_t on_rtcp(char* data, int nb_data);
private:
srs_error_t on_rtcp_sr(char* buf, int nb_buf);
srs_error_t on_rtcp_xr(char* buf, int nb_buf);
srs_error_t on_rtcp_feedback(char* data, int nb_data);
srs_error_t on_rtcp_ps_feedback(char* data, int nb_data);
srs_error_t on_rtcp_rr(char* data, int nb_data);
};
class SrsRtcPublisher : virtual public ISrsHourGlass, virtual public ISrsRtpPacketDecodeHandler
{
private:
SrsHourGlass* report_timer;
uint64_t nn_audio_frames;
private:
SrsRtcSession* session_;
uint32_t video_ssrc;
uint32_t audio_ssrc;
private:
SrsRtpVideoQueue* video_queue_;
SrsRtpNackForReceiver* video_nack_;
SrsRtpAudioQueue* audio_queue_;
SrsRtpNackForReceiver* audio_nack_;
private:
SrsRequest* req;
SrsSource* source;
// Whether enabled nack.
bool nack_enabled_;
// Simulators.
int nn_simulate_nack_drop;
private:
std::map<uint32_t, uint64_t> last_sender_report_sys_time;
std::map<uint32_t, SrsNtp> last_sender_report_ntp;
public:
SrsRtcPublisher(SrsRtcSession* session);
virtual ~SrsRtcPublisher();
public:
srs_error_t initialize(uint32_t vssrc, uint32_t assrc, SrsRequest* req);
private:
void check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc);
srs_error_t send_rtcp_rr(uint32_t ssrc, SrsRtpQueue* rtp_queue);
srs_error_t send_rtcp_xr_rrtr(uint32_t ssrc);
srs_error_t send_rtcp_fb_pli(uint32_t ssrc);
public:
srs_error_t on_rtp(char* buf, int nb_buf);
virtual void on_before_decode_payload(SrsRtpPacket2* pkt, SrsBuffer* buf, ISrsCodec** ppayload);
srs_error_t on_rtcp(char* data, int nb_data);
private:
srs_error_t on_audio(SrsRtpPacket2* pkt);
srs_error_t on_audio_frame(SrsRtpPacket2* frame);
srs_error_t on_video(SrsRtpPacket2* pkt);
srs_error_t on_video_frame(SrsRtpPacket2* frame);
srs_error_t on_rtcp_sr(char* buf, int nb_buf);
srs_error_t on_rtcp_xr(char* buf, int nb_buf);
srs_error_t on_rtcp_feedback(char* data, int nb_data);
srs_error_t on_rtcp_ps_feedback(char* data, int nb_data);
srs_error_t on_rtcp_rr(char* data, int nb_data);
public:
void request_keyframe();
// interface ISrsHourGlass
public:
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick);
public:
void simulate_nack_drop(int nn);
private:
void simulate_drop_packet(SrsRtpHeader* h, int nn_bytes);
};
class SrsRtcSession
{
friend class SrsRtcSenderThread;
friend class SrsRtcDtls;
friend class SrsRtcPlayer;
friend class SrsRtcPublisher;
private:
SrsRtcServer* rtc_server;
SrsSdp remote_sdp;
SrsSdp local_sdp;
SrsRtcSessionStateType session_state;
SrsDtlsSession* dtls_session;
SrsRtcSenderThread* strd;
std::string username;
std::string peer_id;
SrsRtcServer* server_;
SrsRtcSessionStateType state_;
SrsRtcDtls* dtls_;
SrsRtcPlayer* player_;
SrsRtcPublisher* publisher_;
bool is_publisher_;
private:
SrsUdpMuxSocket* sendonly_skt;
std::string username_;
std::string peer_id_;
private:
// The timeout of session, keep alive by STUN ping pong.
srs_utime_t sessionStunTimeout;
srs_utime_t last_stun_time;
private:
// For each RTC session, we use a specified cid for debugging logs.
@ -253,145 +364,49 @@ private:
// Sepcifies by HTTP API, query encrypt, optional.
// TODO: FIXME: Support reload.
bool encrypt;
// The timeout of session, keep alive by STUN ping pong.
srs_utime_t sessionStunTimeout;
SrsRequest* req;
SrsSource* source_;
SrsSdp remote_sdp;
SrsSdp local_sdp;
private:
bool blackhole;
sockaddr_in* blackhole_addr;
srs_netfd_t blackhole_stfd;
public:
SrsRequest request;
SrsSource* source;
public:
SrsRtcSession(SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id);
SrsRtcSession(SrsRtcServer* s);
virtual ~SrsRtcSession();
public:
SrsSdp* get_local_sdp() { return &local_sdp; }
SrsSdp* get_local_sdp();
void set_local_sdp(const SrsSdp& sdp);
SrsSdp* get_remote_sdp() { return &remote_sdp; }
void set_remote_sdp(const SrsSdp& sdp) { remote_sdp = sdp; }
SrsRtcSessionStateType get_session_state() { return session_state; }
void set_session_state(SrsRtcSessionStateType state) { session_state = state; }
std::string id() const { return peer_id + "_" + username; }
std::string get_peer_id() const { return peer_id; }
void set_peer_id(const std::string& id) { peer_id = id; }
void set_encrypt(bool v) { encrypt = v; }
SrsSdp* get_remote_sdp();
void set_remote_sdp(const SrsSdp& sdp);
SrsRtcSessionStateType state();
void set_state(SrsRtcSessionStateType state);
std::string id();
std::string peer_id();
void set_peer_id(std::string v);
std::string username();
void set_encrypt(bool v);
void switch_to_context();
int context_id();
public:
srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req);
srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_rtcp(SrsUdpMuxSocket* skt);
public:
srs_error_t send_client_hello(SrsUdpMuxSocket* skt);
srs_error_t on_connection_established(SrsUdpMuxSocket* skt);
srs_error_t start_play(SrsUdpMuxSocket* skt);
srs_error_t initialize(SrsSource* source, SrsRequest* r, bool is_publisher, std::string username, int context_id);
// The peer address may change, we can identify that by STUN messages.
srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* r);
srs_error_t on_dtls(char* data, int nb_data);
srs_error_t on_rtp(char* data, int nb_data);
srs_error_t on_rtcp(char* data, int nb_data);
public:
srs_error_t on_connection_established();
srs_error_t start_play();
srs_error_t start_publish();
bool is_stun_timeout();
private:
srs_error_t check_source();
private:
srs_error_t on_binding_request(SrsUdpMuxSocket* skt, SrsStunPacket* stun_req);
private:
srs_error_t on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt);
srs_error_t on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* skt);
srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* skt);
};
class SrsUdpMuxSender : virtual public ISrsUdpSender, virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
{
private:
srs_netfd_t lfd;
SrsRtcServer* server;
SrsCoroutine* trd;
private:
srs_cond_t cond;
bool waiting_msgs;
bool gso;
int nn_senders;
private:
// Hotspot msgs, we are working on it.
// @remark We will wait util all messages are ready.
std::vector<mmsghdr> hotspot;
// 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;
void update_sendonly_socket(SrsUdpMuxSocket* skt);
public:
SrsUdpMuxSender(SrsRtcServer* s);
virtual ~SrsUdpMuxSender();
public:
virtual srs_error_t initialize(srs_netfd_t fd, int senders);
// Simulate the NACK to drop nn packets.
void simulate_nack_drop(int nn);
private:
void free_mhdrs(std::vector<mmsghdr>& mhdrs);
public:
virtual srs_error_t fetch(mmsghdr** pphdr);
virtual srs_error_t sendmmsg(mmsghdr* hdr);
virtual bool overflow();
virtual void set_extra_ratio(int r);
public:
virtual srs_error_t cycle();
// interface ISrsReloadHandler
public:
virtual srs_error_t on_reload_rtc_server();
};
class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass
{
private:
SrsHourGlass* timer;
std::vector<SrsUdpMuxListener*> listeners;
std::vector<SrsUdpMuxSender*> senders;
private:
std::map<std::string, SrsRtcSession*> map_username_session; // key: username(local_ufrag + ":" + remote_ufrag)
std::map<std::string, SrsRtcSession*> map_id_session; // key: peerip(ip + ":" + port)
public:
SrsRtcServer();
virtual ~SrsRtcServer();
public:
virtual srs_error_t initialize();
public:
// TODO: FIXME: Support gracefully quit.
// TODO: FIXME: Support reload.
virtual srs_error_t listen_udp();
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt);
public:
virtual srs_error_t listen_api();
SrsRtcSession* create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp, const std::string& mock_eip);
bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session);
void check_and_clean_timeout_session();
int nn_sessions() { return (int)map_username_session.size(); }
private:
srs_error_t on_stun(SrsUdpMuxSocket* skt);
srs_error_t on_dtls(SrsUdpMuxSocket* skt);
srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* skt);
private:
SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag);
SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id);
// interface ISrsHourGlass
public:
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick);
};
// The RTC server adapter.
class RtcServerAdapter : public ISrsHybridServer
{
private:
SrsRtcServer* rtc;
public:
RtcServerAdapter();
virtual ~RtcServerAdapter();
public:
virtual srs_error_t initialize();
virtual srs_error_t run();
virtual void stop();
srs_error_t on_binding_request(SrsStunPacket* r);
};
#endif

View file

@ -21,7 +21,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_app_dtls.hpp>
#include <srs_app_rtc_dtls.hpp>
using namespace std;
@ -46,14 +46,6 @@ SrsDtls::~SrsDtls()
SSL_CTX_free(dtls_ctx);
}
SrsDtls* SrsDtls::instance()
{
if (!_instance) {
_instance = new SrsDtls();
}
return _instance;
}
// The return value of verify_callback controls the strategy of the further verification process. If verify_callback
// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is
// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback
@ -69,7 +61,7 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
return 1;
}
srs_error_t SrsDtls::init(const SrsRequest& req)
srs_error_t SrsDtls::init(SrsRequest* r)
{
srs_error_t err = srs_success;
@ -89,8 +81,8 @@ srs_error_t SrsDtls::init(const SrsRequest& req)
#if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2
dtls_ctx = SSL_CTX_new(DTLSv1_method());
#else
//dtls_ctx = SSL_CTX_new(DTLS_method());
dtls_ctx = SSL_CTX_new(DTLSv1_method());
dtls_ctx = SSL_CTX_new(DTLS_method());
//dtls_ctx = SSL_CTX_new(DTLSv1_method());
//dtls_ctx = SSL_CTX_new(DTLSv1_2_method());
#endif
@ -256,3 +248,22 @@ srs_error_t SrsDtls::init(const SrsRequest& req)
return err;
}
SrsDtls* SrsDtls::instance()
{
if (!_instance) {
_instance = new SrsDtls();
}
return _instance;
}
SSL_CTX* SrsDtls::get_dtls_ctx()
{
return dtls_ctx;
}
std::string SrsDtls::get_fingerprint() const
{
return fingerprint;
}

View file

@ -21,8 +21,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_APP_DTLS_HPP
#define SRS_APP_DTLS_HPP
#ifndef SRS_APP_RTC_DTLS_HPP
#define SRS_APP_RTC_DTLS_HPP
#include <srs_core.hpp>
@ -43,12 +43,12 @@ private:
SrsDtls();
virtual ~SrsDtls();
public:
srs_error_t init(const SrsRequest& req);
srs_error_t init(SrsRequest* r);
public:
static SrsDtls* instance();
SSL_CTX* get_dtls_ctx() { return dtls_ctx; }
SSL_CTX* get_dtls_ctx();
public:
std::string get_fingerprint() const { return fingerprint; }
std::string get_fingerprint() const;
};
#endif

View file

@ -0,0 +1,675 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2013-2020 John
*
* 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.
*/
#include <srs_app_rtc_queue.hpp>
#include <string.h>
#include <unistd.h>
#include <sstream>
using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_app_utility.hpp>
SrsRtpNackInfo::SrsRtpNackInfo()
{
generate_time_ = srs_update_system_time();
pre_req_nack_time_ = 0;
req_nack_count_ = 0;
}
SrsRtpNackForReceiver::SrsRtpNackForReceiver(SrsRtpQueue* rtp_queue, size_t queue_size)
{
max_queue_size_ = queue_size;
rtp_queue_ = rtp_queue;
pre_check_time_ = 0;
srs_info("max_queue_size=%u, nack opt: max_count=%d, max_alive_time=%us, first_nack_interval=%ld, nack_interval=%ld"
max_queue_size_, opts_.max_count, opts_.max_alive_time, opts.first_nack_interval, opts_.nack_interval);
}
SrsRtpNackForReceiver::~SrsRtpNackForReceiver()
{
}
void SrsRtpNackForReceiver::insert(uint16_t seq)
{
// FIXME: full, drop packet, and request key frame.
queue_[seq] = SrsRtpNackInfo();
}
void SrsRtpNackForReceiver::remove(uint16_t seq)
{
queue_.erase(seq);
}
SrsRtpNackInfo* SrsRtpNackForReceiver::find(uint16_t seq)
{
std::map<uint16_t, SrsRtpNackInfo>::iterator iter = queue_.find(seq);
if (iter == queue_.end()) {
return NULL;
}
return &(iter->second);
}
void SrsRtpNackForReceiver::check_queue_size()
{
if (queue_.size() >= max_queue_size_) {
rtp_queue_->notify_nack_list_full();
}
}
void SrsRtpNackForReceiver::get_nack_seqs(vector<uint16_t>& seqs)
{
srs_utime_t now = srs_update_system_time();
srs_utime_t interval = now - pre_check_time_;
if (interval < opts_.nack_interval / 2) {
return;
}
pre_check_time_ = now;
std::map<uint16_t, SrsRtpNackInfo>::iterator iter = queue_.begin();
while (iter != queue_.end()) {
const uint16_t& seq = iter->first;
SrsRtpNackInfo& nack_info = iter->second;
int alive_time = now - nack_info.generate_time_;
if (alive_time > opts_.max_alive_time || nack_info.req_nack_count_ > opts_.max_count) {
rtp_queue_->notify_drop_seq(seq);
queue_.erase(iter++);
continue;
}
// TODO:Statistics unorder packet.
if (now - nack_info.generate_time_ < opts_.first_nack_interval) {
break;
}
if (now - nack_info.pre_req_nack_time_ >= opts_.nack_interval && nack_info.req_nack_count_ <= opts_.max_count) {
++nack_info.req_nack_count_;
nack_info.pre_req_nack_time_ = now;
seqs.push_back(seq);
}
++iter;
}
}
void SrsRtpNackForReceiver::update_rtt(int rtt)
{
rtt_ = rtt * SRS_UTIME_MILLISECONDS;
// FIXME: limit min and max value.
opts_.nack_interval = rtt_;
}
SrsRtpQueue::SrsRtpQueue()
{
jitter_ = 0;
last_trans_time_ = -1;
pre_number_of_packet_received_ = 0;
pre_number_of_packet_lossed_ = 0;
num_of_packet_received_ = 0;
number_of_packet_lossed_ = 0;
}
SrsRtpQueue::~SrsRtpQueue()
{
}
uint8_t SrsRtpQueue::get_fraction_lost()
{
int64_t total = (number_of_packet_lossed_ - pre_number_of_packet_lossed_ + num_of_packet_received_ - pre_number_of_packet_received_);
uint8_t loss = 0;
if (total > 0) {
loss = (number_of_packet_lossed_ - pre_number_of_packet_lossed_) * 256 / total;
}
pre_number_of_packet_lossed_ = number_of_packet_lossed_;
pre_number_of_packet_received_ = num_of_packet_received_;
return loss;
}
uint32_t SrsRtpQueue::get_cumulative_number_of_packets_lost()
{
return number_of_packet_lossed_;
}
uint32_t SrsRtpQueue::get_interarrival_jitter()
{
return static_cast<uint32_t>(jitter_);
}
srs_error_t SrsRtpQueue::on_consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt)
{
srs_error_t err = srs_success;
// TODO: FIXME: Update time for each packet, may hurt performance.
srs_utime_t now = srs_update_system_time();
uint16_t seq = pkt->rtp_header.get_sequence();
SrsRtpNackInfo* nack_info = NULL;
if (nack) {
nack_info = nack->find(seq);
}
if (nack_info) {
int nack_rtt = nack_info->req_nack_count_ ? ((now - nack_info->pre_req_nack_time_) / SRS_UTIME_MILLISECONDS) : 0;
(void)nack_rtt;
nack->remove(seq);
}
// Calc jitter time, ignore nack packets.
// TODO: FIXME: Covert time to srs_utime_t.
if (last_trans_time_ == -1) {
last_trans_time_ = now / 1000 - pkt->rtp_header.get_timestamp() / 90;
} else if (!nack_info) {
int trans_time = now / 1000 - pkt->rtp_header.get_timestamp() / 90;
int cur_jitter = trans_time - last_trans_time_;
if (cur_jitter < 0) {
cur_jitter = -cur_jitter;
}
last_trans_time_ = trans_time;
jitter_ = (jitter_ * 15.0 / 16.0) + (static_cast<double>(cur_jitter) / 16.0);
}
// OK, got new RTP packet.
if (!nack_info) {
++num_of_packet_received_;
}
return err;
}
void SrsRtpQueue::insert_into_nack_list(SrsRtpNackForReceiver* nack, uint16_t first, uint16_t last)
{
if (!nack) {
return;
}
for (uint16_t s = first; s != last; ++s) {
nack->insert(s);
++number_of_packet_lossed_;
}
nack->check_queue_size();
}
SrsRtpAudioPacket::SrsRtpAudioPacket()
{
pkt = NULL;
}
SrsRtpAudioPacket::~SrsRtpAudioPacket()
{
srs_freep(pkt);
}
SrsRtpPacket2* SrsRtpAudioPacket::detach()
{
SrsRtpPacket2* p = pkt;
pkt = NULL;
return p;
}
SrsRtpAudioQueue::SrsRtpAudioQueue(int capacity)
{
queue_ = new SrsRtpRingBuffer<SrsRtpAudioPacket*>(capacity);
}
SrsRtpAudioQueue::~SrsRtpAudioQueue()
{
srs_freep(queue_);
}
void SrsRtpAudioQueue::notify_drop_seq(uint16_t seq)
{
uint16_t next = seq + 1;
if (srs_rtp_seq_distance(queue_->end, seq) > 0) {
seq = queue_->end;
}
srs_trace("nack drop seq=%u, drop range [%u, %u, %u]", seq, queue_->begin, next, queue_->end);
queue_->advance_to(next);
}
void SrsRtpAudioQueue::notify_nack_list_full()
{
// TODO: FIXME: Maybe we should not drop all packets.
queue_->advance_to(queue_->end);
}
uint32_t SrsRtpAudioQueue::get_extended_highest_sequence()
{
return queue_->get_extended_highest_sequence();
}
srs_error_t SrsRtpAudioQueue::consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt)
{
srs_error_t err = srs_success;
uint16_t seq = pkt->rtp_header.get_sequence();
SrsRtpNackInfo* nack_info = NULL;
if (nack) {
nack_info = nack->find(seq);
}
if ((err = SrsRtpQueue::on_consume(nack, pkt)) != srs_success) {
return srs_error_wrap(err, "consume audio");
}
// OK, we got one new RTP packet, which is not in NACK.
if (!nack_info) {
uint16_t nack_first = 0, nack_last = 0;
if (!queue_->update(seq, nack_first, nack_last)) {
srs_warn("too old seq %u, range [%u, %u]", seq, queue_->begin, queue_->end);
}
if (nack && srs_rtp_seq_distance(nack_first, nack_last) > 0) {
srs_trace("update seq=%u, nack range [%u, %u]", seq, nack_first, nack_last);
insert_into_nack_list(nack, nack_first, nack_last);
}
}
// Save packet at the position seq.
SrsRtpAudioPacket* apkt = new SrsRtpAudioPacket();
apkt->pkt = pkt;
queue_->set(seq, apkt);
return err;
}
void SrsRtpAudioQueue::collect_frames(SrsRtpNackForReceiver* nack, vector<SrsRtpPacket2*>& frames)
{
// When done, next point to the next available packet.
uint16_t next = queue_->begin;
// If nack disabled, we ignore any empty packet.
if (!nack) {
for (; next != queue_->end; ++next) {
SrsRtpAudioPacket* pkt = queue_->at(next);
if (pkt) {
frames.push_back(pkt->detach());
}
}
} else {
for (; next != queue_->end; ++next) {
SrsRtpAudioPacket* pkt = queue_->at(next);
// TODO: FIXME: Should not wait for NACK packets.
// Not found or in NACK, stop collecting frame.
if (!pkt || nack->find(next) != NULL) {
srs_trace("wait for nack seq=%u", next);
break;
}
frames.push_back(pkt->detach());
}
}
// Reap packets from begin to next.
if (next != queue_->begin) {
srs_verbose("RTC collect audio [%u, %u, %u]", queue_->begin, next, queue_->end);
queue_->advance_to(next);
}
// For audio, if overflow, clear all packets.
// TODO: FIXME: Should notify nack?
if (queue_->overflow()) {
queue_->advance_to(queue_->end);
}
}
SrsRtpVideoPacket::SrsRtpVideoPacket()
{
video_is_first_packet = false;
video_is_last_packet = false;
video_is_idr = false;
pkt = NULL;
}
SrsRtpVideoPacket::~SrsRtpVideoPacket()
{
srs_freep(pkt);
}
SrsRtpPacket2* SrsRtpVideoPacket::detach()
{
SrsRtpPacket2* p = pkt;
pkt = NULL;
return p;
}
SrsRtpVideoQueue::SrsRtpVideoQueue(int capacity)
{
request_key_frame_ = false;
queue_ = new SrsRtpRingBuffer<SrsRtpVideoPacket*>(capacity);
}
SrsRtpVideoQueue::~SrsRtpVideoQueue()
{
srs_freep(queue_);
}
void SrsRtpVideoQueue::notify_drop_seq(uint16_t seq)
{
// If not found start frame, return the end, and we will clear queue.
uint16_t next = next_start_of_frame(seq);
srs_trace("nack drop seq=%u, drop range [%u, %u, %u]", seq, queue_->begin, next, queue_->end);
queue_->advance_to(next);
}
void SrsRtpVideoQueue::notify_nack_list_full()
{
// If not found start frame, return the end, and we will clear queue.
uint16_t next = next_keyframe();
srs_trace("nack overflow, drop range [%u, %u, %u]", queue_->begin, next, queue_->end);
queue_->advance_to(next);
}
uint32_t SrsRtpVideoQueue::get_extended_highest_sequence()
{
return queue_->get_extended_highest_sequence();
}
srs_error_t SrsRtpVideoQueue::consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt)
{
srs_error_t err = srs_success;
SrsRtpVideoPacket* vpkt = new SrsRtpVideoPacket();
vpkt->pkt = pkt;
uint8_t v = (uint8_t)pkt->nalu_type;
if (v == kFuA) {
SrsRtpFUAPayload2* payload = dynamic_cast<SrsRtpFUAPayload2*>(pkt->payload);
if (!payload) {
srs_freep(pkt); srs_freep(vpkt);
return srs_error_new(ERROR_RTC_RTP_MUXER, "FU-A payload");
}
vpkt->video_is_first_packet = payload->start;
vpkt->video_is_last_packet = payload->end;
vpkt->video_is_idr = (payload->nalu_type == SrsAvcNaluTypeIDR);
} else {
vpkt->video_is_first_packet = true;
vpkt->video_is_last_packet = true;
if (v == kStapA) {
vpkt->video_is_idr = true;
} else {
vpkt->video_is_idr = (pkt->nalu_type == SrsAvcNaluTypeIDR);
}
}
uint16_t seq = pkt->rtp_header.get_sequence();
SrsRtpNackInfo* nack_info = NULL;
if (nack) {
nack_info = nack->find(seq);
}
if ((err = SrsRtpQueue::on_consume(nack, pkt)) != srs_success) {
srs_freep(pkt); srs_freep(vpkt);
return srs_error_wrap(err, "consume video");
}
// OK, we got one new RTP packet, which is not in NACK.
if (!nack_info) {
uint16_t nack_first = 0, nack_last = 0;
if (!queue_->update(seq, nack_first, nack_last)) {
srs_warn("too old seq %u, range [%u, %u]", seq, queue_->begin, queue_->end);
}
if (nack && srs_rtp_seq_distance(nack_first, nack_last) > 0) {
srs_trace("update seq=%u, nack range [%u, %u]", seq, nack_first, nack_last);
insert_into_nack_list(nack, nack_first, nack_last);
}
}
// Save packet at the position seq.
queue_->set(seq, vpkt);
return err;
}
void SrsRtpVideoQueue::collect_frames(SrsRtpNackForReceiver* nack, std::vector<SrsRtpPacket2*>& frames)
{
while (true) {
SrsRtpPacket2* pkt = NULL;
collect_frame(nack, &pkt);
if (!pkt) {
break;
}
frames.push_back(pkt);
}
if (queue_->overflow()) {
on_overflow(nack);
}
}
bool SrsRtpVideoQueue::should_request_key_frame()
{
if (request_key_frame_) {
request_key_frame_ = false;
return true;
}
return request_key_frame_;
}
void SrsRtpVideoQueue::request_keyframe()
{
request_key_frame_ = true;
}
void SrsRtpVideoQueue::on_overflow(SrsRtpNackForReceiver* nack)
{
// If not found start frame, return the end, and we will clear queue.
uint16_t next = next_start_of_frame(queue_->begin);
srs_trace("on overflow, remove range [%u, %u, %u]", queue_->begin, next, queue_->end);
for (uint16_t s = queue_->begin; s != next; ++s) {
if (nack) {
nack->remove(s);
}
queue_->remove(s);
}
queue_->advance_to(next);
}
// TODO: FIXME: Should refer to the FU-A original video frame, to avoid finding for each packet.
void SrsRtpVideoQueue::collect_frame(SrsRtpNackForReceiver* nack, SrsRtpPacket2** ppkt)
{
bool found = false;
vector<SrsRtpVideoPacket*> frame;
// When done, next point to the next available packet.
uint16_t next = queue_->begin;
// If nack disabled, we ignore any empty packet.
if (!nack) {
for (; next != queue_->end; ++next) {
SrsRtpVideoPacket* vpkt = queue_->at(next);
if (!vpkt) {
continue;
}
if (frame.empty() && !vpkt->video_is_first_packet) {
continue;
}
frame.push_back(vpkt);
if (vpkt->pkt->rtp_header.get_marker() || vpkt->video_is_last_packet) {
found = true;
next++;
break;
}
}
} else {
for (; next != queue_->end; ++next) {
SrsRtpVideoPacket* vpkt = queue_->at(next);
// TODO: FIXME: Should not wait for NACK packets.
// Not found or in NACK, stop collecting frame.
if (!vpkt || nack->find(next) != NULL) {
srs_trace("wait for nack seq=%u", next);
return;
}
// Ignore when the first packet not the start.
if (frame.empty() && !vpkt->video_is_first_packet) {
return;
}
// OK, collect packet to frame.
frame.push_back(vpkt);
// Done, we got the last packet of frame.
// @remark Note that the STAP-A is marker false and it's the last packet.
if (vpkt->pkt->rtp_header.get_marker() || vpkt->video_is_last_packet) {
found = true;
next++;
break;
}
}
}
if (!found || frame.empty()) {
return;
}
if (next != queue_->begin) {
srs_verbose("RTC collect video [%u, %u, %u]", queue_->begin, next, queue_->end);
queue_->advance_to(next);
}
// Merge packets to one packet.
covert_frame(frame, ppkt);
return;
}
void SrsRtpVideoQueue::covert_frame(std::vector<SrsRtpVideoPacket*>& frame, SrsRtpPacket2** ppkt)
{
if (frame.size() == 1) {
*ppkt = frame[0]->detach();
return;
}
// If more than one packet in a frame, it must be FU-A.
SrsRtpPacket2* head = frame.at(0)->pkt;
SrsAvcNaluType nalu_type = head->nalu_type;
// Covert FU-A to one RAW RTP packet.
int nn_nalus = 0;
for (size_t i = 0; i < frame.size(); ++i) {
SrsRtpVideoPacket* vpkt = frame[i];
SrsRtpFUAPayload2* payload = dynamic_cast<SrsRtpFUAPayload2*>(vpkt->pkt->payload);
if (!payload) {
nn_nalus = 0; break;
}
nn_nalus += payload->size;
}
// Invalid packets, ignore.
if (nalu_type != (SrsAvcNaluType)kFuA || !nn_nalus) {
return;
}
// Merge to one RAW RTP packet.
// TODO: FIXME: Should covert to multiple NALU RTP packet to avoid copying.
SrsRtpPacket2* pkt = new SrsRtpPacket2();
pkt->rtp_header = head->rtp_header;
pkt->padding = head->padding;
SrsRtpFUAPayload2* head_payload = dynamic_cast<SrsRtpFUAPayload2*>(head->payload);
pkt->nalu_type = head_payload->nalu_type;
SrsRtpRawPayload* payload = pkt->reuse_raw();
payload->nn_payload = nn_nalus + 1;
payload->payload = new char[payload->nn_payload];
SrsBuffer buf(payload->payload, payload->nn_payload);
buf.write_1bytes(head_payload->nri | head_payload->nalu_type); // NALU header.
for (size_t i = 0; i < frame.size(); ++i) {
SrsRtpVideoPacket* vpkt = frame[i];
SrsRtpFUAPayload2* payload = dynamic_cast<SrsRtpFUAPayload2*>(vpkt->pkt->payload);
buf.write_bytes(payload->payload, payload->size);
}
*ppkt = pkt;
}
uint16_t SrsRtpVideoQueue::next_start_of_frame(uint16_t seq)
{
uint16_t s = seq;
if (srs_rtp_seq_distance(seq, queue_->begin) >= 0) {
s = queue_->begin + 1;
}
for (; s != queue_->end; ++s) {
SrsRtpVideoPacket* vpkt = queue_->at(s);
if (vpkt && vpkt->video_is_first_packet) {
return s;
}
}
return queue_->end;
}
uint16_t SrsRtpVideoQueue::next_keyframe()
{
uint16_t s = queue_->begin + 1;
for (; s != queue_->end; ++s) {
SrsRtpVideoPacket* vpkt = queue_->at(s);
if (vpkt && vpkt->video_is_idr && vpkt->video_is_first_packet) {
return s;
}
}
return queue_->end;
}

View file

@ -0,0 +1,318 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2013-2020 John
*
* 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.
*/
#ifndef SRS_APP_RTC_QUEUE_HPP
#define SRS_APP_RTC_QUEUE_HPP
#include <srs_core.hpp>
#include <string>
#include <vector>
#include <map>
class SrsRtpPacket2;
class SrsRtpQueue;
struct SrsNackOption
{
SrsNackOption()
{
// Default nack option.
max_count = 10;
max_alive_time = 2 * SRS_UTIME_SECONDS;
first_nack_interval = 10 * SRS_UTIME_MILLISECONDS;
nack_interval = 400 * SRS_UTIME_MILLISECONDS;
}
int max_count;
srs_utime_t max_alive_time;
int64_t first_nack_interval;
int64_t nack_interval;
};
struct SrsRtpNackInfo
{
SrsRtpNackInfo();
// Use to control the time of first nack req and the life of seq.
srs_utime_t generate_time_;
// Use to control nack interval.
srs_utime_t pre_req_nack_time_;
// Use to control nack times.
int req_nack_count_;
};
// The "distance" between two uint16 number, for example:
// distance(low=3, high=5) === (int16_t)(uint16_t)((uint16_t)3-(uint16_t)5) === -2
// distance(low=3, high=65534) === (int16_t)(uint16_t)((uint16_t)3-(uint16_t)65534) === 5
// distance(low=65532, high=65534) === (int16_t)(uint16_t)((uint16_t)65532-(uint16_t)65534) === -2
// For RTP sequence, it's only uint16 and may flip back, so 3 maybe 3+0xffff.
inline int16_t srs_rtp_seq_distance(const uint16_t& low, const uint16_t& high)
{
return (int16_t)(high - low);
}
class SrsRtpNackForReceiver
{
private:
struct SeqComp {
bool operator()(const uint16_t& low, const uint16_t& high) const {
return srs_rtp_seq_distance(low, high) > 0;
}
};
private:
// Nack queue, seq order, oldest to newest.
std::map<uint16_t, SrsRtpNackInfo, SeqComp> queue_;
// Max nack count.
size_t max_queue_size_;
SrsRtpQueue* rtp_queue_;
SrsNackOption opts_;
private:
srs_utime_t pre_check_time_;
private:
int rtt_;
public:
SrsRtpNackForReceiver(SrsRtpQueue* rtp_queue, size_t queue_size);
virtual ~SrsRtpNackForReceiver();
public:
void insert(uint16_t seq);
void remove(uint16_t seq);
SrsRtpNackInfo* find(uint16_t seq);
void check_queue_size();
public:
void get_nack_seqs(std::vector<uint16_t>& seqs);
public:
void update_rtt(int rtt);
};
// For UDP, the packets sequence may present as bellow:
// [seq1(done)|seq2|seq3 ... seq10|seq11(lost)|seq12|seq13]
// \___(head_sequence_) \ \___(highest_sequence_)
// \___(no received, in nack list)
// * seq1: The packet is done, we already got the entire frame and processed it.
// * seq2,seq3,...,seq10,seq12,seq13: We are processing theses packets, for example, some FU-A or NALUs,
// but not an entire video frame right now.
// * seq10: This packet is lost or not received, we put it in the nack list.
// We store the received packets in ring buffer.
template<typename T>
class SrsRtpRingBuffer
{
private:
// Capacity of the ring-buffer.
uint16_t capacity_;
// Ring bufer.
T* queue_;
// Increase one when uint16 flip back, for get_extended_highest_sequence.
uint64_t nn_seq_flip_backs;
// Whether initialized, because we use uint16 so we can't use -1.
bool initialized_;
public:
// The begin iterator for ring buffer.
// For example, when got 1 elems, the begin is 0.
uint16_t begin;
// The end iterator for ring buffer.
// For example, when got 1 elems, the end is 1.
uint16_t end;
public:
SrsRtpRingBuffer(int capacity) {
nn_seq_flip_backs = 0;
begin = end = 0;
capacity_ = (uint16_t)capacity;
initialized_ = false;
queue_ = new T[capacity_];
memset(queue_, 0, sizeof(T) * capacity);
}
virtual ~SrsRtpRingBuffer() {
srs_freepa(queue_);
}
public:
// Whether the ring buffer is empty.
bool empty() {
return begin == end;
}
// Get the count of elems in ring buffer.
int size() {
int size = srs_rtp_seq_distance(begin, end);
srs_assert(size >= 0);
return size;
}
// Move the low position of buffer to seq.
void advance_to(uint16_t seq) {
begin = seq;
}
// Free the packet at position.
void set(uint16_t at, T pkt) {
T p = queue_[at % capacity_];
if (p) {
srs_freep(p);
}
queue_[at % capacity_] = pkt;
}
void remove(uint16_t at) {
set(at, NULL);
}
// Whether queue overflow or heavy(too many packets and need clear).
bool overflow() {
return srs_rtp_seq_distance(begin, end) >= capacity_;
}
// The highest sequence number, calculate the flip back base.
uint32_t get_extended_highest_sequence() {
return nn_seq_flip_backs * 65536 + end - 1;
}
// Update the sequence, got the nack range by [first, last).
// @return If false, the seq is too old.
bool update(uint16_t seq, uint16_t& nack_first, uint16_t& nack_last) {
if (!initialized_) {
initialized_ = true;
begin = seq;
end = seq + 1;
return true;
}
// Normal sequence, seq follows high_.
if (srs_rtp_seq_distance(end, seq) >= 0) {
nack_first = end;
nack_last = seq;
// When distance(seq,high_)>0 and seq<high_, seq must flip back,
// for example, high_=65535, seq=1, distance(65535,1)>0 and 1<65535.
// TODO: FIXME: The first flip may be dropped.
if (seq < end) {
++nn_seq_flip_backs;
}
end = seq + 1;
return true;
}
// Out-of-order sequence, seq before low_.
if (srs_rtp_seq_distance(seq, begin) > 0) {
// When startup, we may receive packets in chaos order.
// Because we don't know the ISN(initiazlie sequence number), the first packet
// we received maybe no the first packet client sent.
// @remark We only log a warning, because it seems ok for publisher.
return false;
}
return true;
}
// Get the packet by seq.
T at(uint16_t seq) {
return queue_[seq % capacity_];
}
};
class SrsRtpQueue
{
private:
double jitter_;
// TODO: FIXME: Covert time to srs_utime_t.
int64_t last_trans_time_;
uint64_t pre_number_of_packet_received_;
uint64_t pre_number_of_packet_lossed_;
uint64_t num_of_packet_received_;
uint64_t number_of_packet_lossed_;
public:
SrsRtpQueue();
virtual ~SrsRtpQueue();
public:
virtual void notify_drop_seq(uint16_t seq) = 0;
virtual void notify_nack_list_full() = 0;
virtual uint32_t get_extended_highest_sequence() = 0;
uint8_t get_fraction_lost();
uint32_t get_cumulative_number_of_packets_lost();
uint32_t get_interarrival_jitter();
protected:
srs_error_t on_consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt);
void insert_into_nack_list(SrsRtpNackForReceiver* nack, uint16_t first, uint16_t last);
};
class SrsRtpAudioPacket
{
public:
SrsRtpPacket2* pkt;
public:
SrsRtpAudioPacket();
virtual ~SrsRtpAudioPacket();
public:
SrsRtpPacket2* detach();
};
class SrsRtpAudioQueue : public SrsRtpQueue
{
private:
SrsRtpRingBuffer<SrsRtpAudioPacket*>* queue_;
public:
SrsRtpAudioQueue(int capacity);
virtual ~SrsRtpAudioQueue();
public:
virtual void notify_drop_seq(uint16_t seq);
virtual void notify_nack_list_full();
virtual uint32_t get_extended_highest_sequence();
virtual srs_error_t consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt);
public:
virtual void collect_frames(SrsRtpNackForReceiver* nack, std::vector<SrsRtpPacket2*>& frames);
};
class SrsRtpVideoPacket
{
public:
// Helper information for video decoder only.
bool video_is_first_packet;
bool video_is_last_packet;
bool video_is_idr;
public:
SrsRtpPacket2* pkt;
public:
SrsRtpVideoPacket();
virtual ~SrsRtpVideoPacket();
public:
SrsRtpPacket2* detach();
};
class SrsRtpVideoQueue : public SrsRtpQueue
{
private:
bool request_key_frame_;
SrsRtpRingBuffer<SrsRtpVideoPacket*>* queue_;
public:
SrsRtpVideoQueue(int capacity);
virtual ~SrsRtpVideoQueue();
public:
virtual void notify_drop_seq(uint16_t seq);
virtual void notify_nack_list_full();
virtual uint32_t get_extended_highest_sequence();
virtual srs_error_t consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt);
virtual void collect_frames(SrsRtpNackForReceiver* nack, std::vector<SrsRtpPacket2*>& frame);
bool should_request_key_frame();
void request_keyframe();
private:
virtual void on_overflow(SrsRtpNackForReceiver* nack);
virtual void collect_frame(SrsRtpNackForReceiver* nack, SrsRtpPacket2** ppkt);
virtual void covert_frame(std::vector<SrsRtpVideoPacket*>& frame, SrsRtpPacket2** ppkt);
uint16_t next_start_of_frame(uint16_t seq);
uint16_t next_keyframe();
};
#endif

View file

@ -21,7 +21,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_app_sdp.hpp>
#include <srs_app_rtc_sdp.hpp>
using namespace std;
#include <stdlib.h>
@ -33,15 +33,16 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
// TODO: FIXME: Maybe we should use json.encode to escape it?
const std::string kCRLF = "\\r\\n";
#define FETCH(is,word) \
if (! (is >> word)) {\
if (!(is >> word)) {\
return srs_error_new(ERROR_RTC_SDP_DECODE, "fetch failed");\
}\
#define FETCH_WITH_DELIM(is,word,delim) \
if (! getline(is,word,delim)) {\
if (!getline(is,word,delim)) {\
return srs_error_new(ERROR_RTC_SDP_DECODE, "fetch with delim failed");\
}\
@ -111,6 +112,7 @@ SrsSessionInfo::~SrsSessionInfo()
srs_error_t SrsSessionInfo::parse_attribute(const std::string& attribute, const std::string& value)
{
srs_error_t err = srs_success;
if (attribute == "ice-ufrag") {
ice_ufrag_ = value;
} else if (attribute == "ice-pwd") {
@ -134,23 +136,25 @@ srs_error_t SrsSessionInfo::parse_attribute(const std::string& attribute, const
srs_error_t SrsSessionInfo::encode(std::ostringstream& os)
{
srs_error_t err = srs_success;
if (! ice_ufrag_.empty()) {
if (!ice_ufrag_.empty()) {
os << "a=ice-ufrag:" << ice_ufrag_ << kCRLF;
}
if (! ice_pwd_.empty()) {
if (!ice_pwd_.empty()) {
os << "a=ice-pwd:" << ice_pwd_ << kCRLF;
}
if (! ice_options_.empty()) {
// For ICE-lite, we never set the trickle.
if (!ice_options_.empty()) {
os << "a=ice-options:" << ice_options_ << kCRLF;
} else {
// @see: https://webrtcglossary.com/trickle-ice/
// Trickle ICE is an optimization of the ICE specification for NAT traversal.
os << "a=ice-options:trickle" << kCRLF;
}
if (! fingerprint_algo_.empty() && ! fingerprint_.empty()) {
if (!fingerprint_algo_.empty() && ! fingerprint_.empty()) {
os << "a=fingerprint:" << fingerprint_algo_ << " " << fingerprint_ << kCRLF;
}
if (! setup_.empty()) {
if (!setup_.empty()) {
os << "a=setup:" << setup_ << kCRLF;
}
@ -179,22 +183,23 @@ SrsSSRCInfo::~SrsSSRCInfo()
srs_error_t SrsSSRCInfo::encode(std::ostringstream& os)
{
srs_error_t err = srs_success;
if (ssrc_ == 0) {
return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid ssrc");
}
os << "a=ssrc:" << ssrc_ << " cname:" << cname_ << kCRLF;
if (! msid_.empty()) {
if (!msid_.empty()) {
os << "a=ssrc:" << ssrc_ << " msid:" << msid_;
if (! msid_tracker_.empty()) {
if (!msid_tracker_.empty()) {
os << " " << msid_tracker_;
}
os << kCRLF;
}
if (! mslabel_.empty()) {
if (!mslabel_.empty()) {
os << "a=ssrc:" << ssrc_ << " mslabel:" << mslabel_ << kCRLF;
}
if (! label_.empty()) {
if (!label_.empty()) {
os << "a=ssrc:" << ssrc_ << " label:" << label_ << kCRLF;
}
@ -215,7 +220,7 @@ srs_error_t SrsMediaPayloadType::encode(std::ostringstream& os)
srs_error_t err = srs_success;
os << "a=rtpmap:" << payload_type_ << " " << encoding_name_ << "/" << clock_rate_;
if (! encoding_param_.empty()) {
if (!encoding_param_.empty()) {
os << "/" << encoding_param_;
}
os << kCRLF;
@ -224,8 +229,11 @@ srs_error_t SrsMediaPayloadType::encode(std::ostringstream& os)
os << "a=rtcp-fb:" << payload_type_ << " " << *iter << kCRLF;
}
if (! format_specific_param_.empty()) {
os << "a=fmtp:" << payload_type_ << " " << format_specific_param_ << kCRLF;
if (!format_specific_param_.empty()) {
os << "a=fmtp:" << payload_type_ << " " << format_specific_param_
// TODO: FIXME: Remove the test code bellow.
// << ";x-google-max-bitrate=6000;x-google-min-bitrate=5100;x-google-start-bitrate=5000"
<< kCRLF;
}
return err;
@ -312,10 +320,10 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os)
}
os << "a=mid:" << mid_ << kCRLF;
if (! msid_.empty()) {
if (!msid_.empty()) {
os << "a=msid:" << msid_;
if (! msid_tracker_.empty()) {
if (!msid_tracker_.empty()) {
os << " " << msid_tracker_;
}
@ -359,7 +367,7 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os)
int foundation = 0;
int component_id = 1; /* RTP */
for (std::vector<SrsCandidate>::iterator iter = candidates_.begin(); iter != candidates_.end(); ++iter) {
for (std::vector<SrsCandidate>::iterator iter = candidates_.begin(); iter != candidates_.end(); ++iter) {
// @see: https://tools.ietf.org/html/draft-ietf-ice-rfc5245bis-00#section-4.2
uint32_t priority = (1<<24)*(126) + (1<<8)*(65535) + (1)*(256 - component_id);
@ -369,6 +377,8 @@ srs_error_t SrsMediaDesc::encode(std::ostringstream& os)
<< iter->ip_ << " " << iter->port_
<< " typ " << iter->type_
<< " generation 0" << kCRLF;
srs_verbose("local SDP candidate line=%s", os.str().c_str());
}
return err;
@ -419,7 +429,7 @@ srs_error_t SrsMediaDesc::parse_attribute(const std::string& content)
sendrecv_ = true;
} else if (attribute == "inactive") {
inactive_ = true;
} else {
} else {
return session_info_.parse_attribute(attribute, value);
}
@ -523,7 +533,7 @@ srs_error_t SrsMediaDesc::parse_attr_mid(const std::string& value)
std::istringstream is(value);
// mid_ means m-line id
FETCH(is, mid_);
srs_trace("mid=%s", mid_.c_str());
srs_verbose("mid=%s", mid_.c_str());
return err;
}
@ -649,11 +659,11 @@ srs_error_t SrsSdp::parse(const std::string& sdp_str)
std::istringstream is(sdp_str);
std::string line;
while (getline(is, line)) {
srs_trace("%s", line.c_str());
srs_verbose("%s", line.c_str());
if (line.size() < 2 || line[1] != '=') {
return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid sdp line=%s", line.c_str());
}
if (! line.empty() && line[line.size()-1] == '\r') {
if (!line.empty() && line[line.size()-1] == '\r') {
line.erase(line.size()-1, 1);
}
@ -676,7 +686,7 @@ srs_error_t SrsSdp::encode(std::ostringstream& os)
// ice-lite is a minimal version of the ICE specification, intended for servers running on a public IP address.
os << "a=ice-lite" << kCRLF;
if (! groups_.empty()) {
if (!groups_.empty()) {
os << "a=group:" << group_policy_;
for (std::vector<std::string>::iterator iter = groups_.begin(); iter != groups_.end(); ++iter) {
os << " " << *iter;
@ -751,7 +761,7 @@ void SrsSdp::add_candidate(const std::string& ip, const int& port, const std::st
candidate.type_ = type;
for (std::vector<SrsMediaDesc>::iterator iter = media_descs_.begin(); iter != media_descs_.end(); ++iter) {
iter->candidates_.push_back(candidate);
iter->candidates_.push_back(candidate);
}
}
@ -949,7 +959,7 @@ srs_error_t SrsSdp::parse_media_description(const std::string& content)
media_descs_.back().payload_types_.push_back(SrsMediaPayloadType(fmt));
}
if (! in_media_session_) {
if (!in_media_session_) {
in_media_session_ = true;
}

View file

@ -21,8 +21,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_APP_SDP_HPP
#define SRS_APP_SDP_HPP
#ifndef SRS_APP_RTC_SDP_HPP
#define SRS_APP_RTC_SDP_HPP
#include <srs_core.hpp>
#include <srs_kernel_utility.hpp>

View file

@ -0,0 +1,791 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2013-2020 John
*
* 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.
*/
#include <srs_app_rtc_server.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_log.hpp>
#include <srs_app_rtc.hpp>
#include <srs_app_statistic.hpp>
#include <srs_app_pithy_print.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_rtc_stun_stack.hpp>
#include <srs_http_stack.hpp>
#include <srs_app_server.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_rtc_dtls.hpp>
#include <srs_service_utility.hpp>
using namespace std;
static bool is_stun(const uint8_t* data, const int size)
{
return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1);
}
static bool is_dtls(const uint8_t* data, size_t len)
{
return (len >= 13 && (data[0] > 19 && data[0] < 64));
}
static bool is_rtp_or_rtcp(const uint8_t* data, size_t len)
{
return (len >= 12 && (data[0] & 0xC0) == 0x80);
}
static bool is_rtcp(const uint8_t* data, size_t len)
{
return (len >= 12) && (data[0] & 0x80) && (data[1] >= 200 && data[1] <= 209);
}
static std::vector<std::string> get_candidate_ips()
{
std::vector<std::string> candidate_ips;
string candidate = _srs_config->get_rtc_server_candidates();
if (candidate != "*" && candidate != "0.0.0.0") {
candidate_ips.push_back(candidate);
return candidate_ips;
}
// For * or 0.0.0.0, auto discovery expose ip addresses.
std::vector<SrsIPAddress*>& ips = srs_get_local_ips();
if (ips.empty()) {
return candidate_ips;
}
// We try to find the best match candidates, no loopback.
string family = _srs_config->get_rtc_server_ip_family();
for (int i = 0; i < (int)ips.size(); ++i) {
SrsIPAddress* ip = ips[i];
if (!ip->is_loopback) {
continue;
}
if (family == "ipv4" && !ip->is_ipv4) {
continue;
}
if (family == "ipv6" && ip->is_ipv4) {
continue;
}
candidate_ips.push_back(ip->ip);
srs_warn("Best matched ip=%s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str());
}
if (!candidate_ips.empty()) {
return candidate_ips;
}
// Then, we use the ipv4 address.
for (int i = 0; i < (int)ips.size(); ++i) {
SrsIPAddress* ip = ips[i];
if (!ip->is_ipv4) {
continue;
}
candidate_ips.push_back(ip->ip);
srs_warn("No best matched, use first ip=%s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str());
return candidate_ips;
}
// We use the first one.
if (candidate_ips.empty()) {
SrsIPAddress* ip = ips[0];
candidate_ips.push_back(ip->ip);
srs_warn("No best matched, use first ip=%s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str());
return candidate_ips;
}
return candidate_ips;
}
SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s)
{
lfd = NULL;
server = s;
waiting_msgs = false;
cond = srs_cond_new();
trd = new SrsDummyCoroutine();
cache_pos = 0;
max_sendmmsg = 0;
queue_length = 0;
extra_ratio = 0;
extra_queue = 0;
gso = false;
nn_senders = 0;
_srs_config->subscribe(this);
}
SrsUdpMuxSender::~SrsUdpMuxSender()
{
_srs_config->unsubscribe(this);
srs_freep(trd);
srs_cond_destroy(cond);
free_mhdrs(hotspot);
hotspot.clear();
free_mhdrs(cache);
cache.clear();
}
srs_error_t SrsUdpMuxSender::initialize(srs_netfd_t fd, int senders)
{
srs_error_t err = srs_success;
lfd = fd;
srs_freep(trd);
trd = new SrsSTCoroutine("udp", this);
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "start coroutine");
}
max_sendmmsg = _srs_config->get_rtc_server_sendmmsg();
gso = _srs_config->get_rtc_server_gso();
queue_length = srs_max(128, _srs_config->get_rtc_server_queue_length());
nn_senders = senders;
// For no GSO, we need larger queue.
if (!gso) {
queue_length *= 2;
}
srs_trace("RTC sender #%d init ok, max_sendmmsg=%d, gso=%d, queue_max=%dx%d, extra_ratio=%d/%d", srs_netfd_fileno(fd),
max_sendmmsg, gso, queue_length, nn_senders, extra_ratio, extra_queue);
return err;
}
void SrsUdpMuxSender::free_mhdrs(std::vector<srs_mmsghdr>& mhdrs)
{
int nn_mhdrs = (int)mhdrs.size();
for (int i = 0; i < nn_mhdrs; i++) {
// @see https://linux.die.net/man/2/sendmmsg
// @see https://linux.die.net/man/2/sendmsg
srs_mmsghdr* hdr = &mhdrs[i];
// Free control for GSO.
char* msg_control = (char*)hdr->msg_hdr.msg_control;
srs_freepa(msg_control);
// Free iovec.
for (int j = SRS_PERF_RTC_GSO_MAX - 1; j >= 0 ; j--) {
iovec* iov = hdr->msg_hdr.msg_iov + j;
char* data = (char*)iov->iov_base;
srs_freepa(data);
srs_freepa(iov);
}
}
mhdrs.clear();
}
srs_error_t SrsUdpMuxSender::fetch(srs_mmsghdr** pphdr)
{
// TODO: FIXME: Maybe need to shrink?
if (cache_pos >= (int)cache.size()) {
// @see https://linux.die.net/man/2/sendmmsg
// @see https://linux.die.net/man/2/sendmsg
srs_mmsghdr mhdr;
mhdr.msg_len = 0;
mhdr.msg_hdr.msg_flags = 0;
mhdr.msg_hdr.msg_control = NULL;
mhdr.msg_hdr.msg_iovlen = SRS_PERF_RTC_GSO_MAX;
mhdr.msg_hdr.msg_iov = new iovec[mhdr.msg_hdr.msg_iovlen];
memset((void*)mhdr.msg_hdr.msg_iov, 0, sizeof(iovec) * mhdr.msg_hdr.msg_iovlen);
for (int i = 0; i < SRS_PERF_RTC_GSO_IOVS; i++) {
iovec* p = mhdr.msg_hdr.msg_iov + i;
p->iov_base = new char[kRtpPacketSize];
}
cache.push_back(mhdr);
}
*pphdr = &cache[cache_pos++];
return srs_success;
}
bool SrsUdpMuxSender::overflow()
{
return cache_pos > queue_length + extra_queue;
}
void SrsUdpMuxSender::set_extra_ratio(int r)
{
// We use the larger extra ratio, because all vhosts shares the senders.
if (extra_ratio > r) {
return;
}
extra_ratio = r;
extra_queue = queue_length * r / 100;
srs_trace("RTC sender #%d extra queue, max_sendmmsg=%d, gso=%d, queue_max=%dx%d, extra_ratio=%d/%d, cache=%d/%d/%d", srs_netfd_fileno(lfd),
max_sendmmsg, gso, queue_length, nn_senders, extra_ratio, extra_queue, cache_pos, (int)cache.size(), (int)hotspot.size());
}
srs_error_t SrsUdpMuxSender::sendmmsg(srs_mmsghdr* hdr)
{
if (waiting_msgs) {
waiting_msgs = false;
srs_cond_signal(cond);
}
return srs_success;
}
srs_error_t SrsUdpMuxSender::cycle()
{
srs_error_t err = srs_success;
uint64_t nn_msgs = 0; uint64_t nn_msgs_last = 0; int nn_msgs_max = 0;
uint64_t nn_bytes = 0; int nn_bytes_max = 0;
uint64_t nn_gso_msgs = 0; uint64_t nn_gso_iovs = 0; int nn_gso_msgs_max = 0; int nn_gso_iovs_max = 0;
int nn_loop = 0; int nn_wait = 0;
srs_utime_t time_last = srs_get_system_time();
bool stat_enabled = _srs_config->get_rtc_server_perf_stat();
SrsStatistic* stat = SrsStatistic::instance();
SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_send(srs_netfd_fileno(lfd));
SrsAutoFree(SrsPithyPrint, pprint);
while (true) {
if ((err = trd->pull()) != srs_success) {
return err;
}
nn_loop++;
int pos = cache_pos;
int gso_iovs = 0;
if (pos <= 0) {
waiting_msgs = true;
nn_wait++;
srs_cond_wait(cond);
continue;
}
// We are working on hotspot now.
cache.swap(hotspot);
cache_pos = 0;
int gso_pos = 0;
int nn_writen = 0;
if (pos > 0) {
// Send out all messages.
// @see https://linux.die.net/man/2/sendmmsg
// @see https://linux.die.net/man/2/sendmsg
srs_mmsghdr* p = &hotspot[0]; srs_mmsghdr* end = p + pos;
for (p = &hotspot[0]; p < end; p += max_sendmmsg) {
int vlen = (int)(end - p);
vlen = srs_min(max_sendmmsg, vlen);
int r0 = srs_sendmmsg(lfd, p, (unsigned int)vlen, 0, SRS_UTIME_NO_TIMEOUT);
if (r0 != vlen) {
srs_warn("sendmmsg %d msgs, %d done", vlen, r0);
}
if (stat_enabled) {
stat->perf_on_sendmmsg_packets(vlen);
}
}
// Collect informations for GSO.
if (stat_enabled) {
// Stat the messages, iovs and bytes.
// @see https://linux.die.net/man/2/sendmmsg
// @see https://linux.die.net/man/2/sendmsg
for (int i = 0; i < pos; i++) {
srs_mmsghdr* mhdr = &hotspot[i];
nn_writen += (int)mhdr->msg_len;
int real_iovs = mhdr->msg_hdr.msg_iovlen;
gso_pos++; nn_gso_msgs++; nn_gso_iovs += real_iovs;
gso_iovs += real_iovs;
}
}
}
if (!stat_enabled) {
continue;
}
// Increase total messages.
nn_msgs += pos + gso_iovs;
nn_msgs_max = srs_max(pos, nn_msgs_max);
nn_bytes += nn_writen;
nn_bytes_max = srs_max(nn_bytes_max, nn_writen);
nn_gso_msgs_max = srs_max(gso_pos, nn_gso_msgs_max);
nn_gso_iovs_max = srs_max(gso_iovs, nn_gso_iovs_max);
pprint->elapse();
if (pprint->can_print()) {
// TODO: FIXME: Extract a PPS calculator.
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 /= 1000; pps_average /= 1000;
}
int nn_cache = 0;
int nn_hotspot_size = (int)hotspot.size();
for (int i = 0; i < nn_hotspot_size; i++) {
srs_mmsghdr* hdr = &hotspot[i];
nn_cache += hdr->msg_hdr.msg_iovlen;
}
srs_trace("-> RTC SEND #%d, sessions %d, udp %d/%d/%" PRId64 ", gso %d/%d/%" PRId64 ", iovs %d/%d/%" PRId64 ", pps %d/%d%s, cache %d/%d, bytes %d/%" PRId64,
srs_netfd_fileno(lfd), (int)server->nn_sessions(), pos, nn_msgs_max, nn_msgs, gso_pos, nn_gso_msgs_max, nn_gso_msgs, gso_iovs,
nn_gso_iovs_max, nn_gso_iovs, pps_average, pps_last, pps_unit.c_str(), (int)hotspot.size(), nn_cache, nn_bytes_max, nn_bytes);
nn_msgs_last = nn_msgs; time_last = srs_get_system_time();
nn_loop = nn_wait = nn_msgs_max = 0;
nn_gso_msgs_max = 0; nn_gso_iovs_max = 0;
nn_bytes_max = 0;
}
}
return err;
}
srs_error_t SrsUdpMuxSender::on_reload_rtc_server()
{
if (true) {
int v = _srs_config->get_rtc_server_sendmmsg();
if (max_sendmmsg != v) {
srs_trace("Reload max_sendmmsg %d=>%d", max_sendmmsg, v);
max_sendmmsg = v;
}
}
return srs_success;
}
SrsRtcServer::SrsRtcServer()
{
timer = new SrsHourGlass(this, 1 * SRS_UTIME_SECONDS);
}
SrsRtcServer::~SrsRtcServer()
{
srs_freep(timer);
if (true) {
vector<SrsUdpMuxListener*>::iterator it;
for (it = listeners.begin(); it != listeners.end(); ++it) {
SrsUdpMuxListener* listener = *it;
srs_freep(listener);
}
}
if (true) {
vector<SrsUdpMuxSender*>::iterator it;
for (it = senders.begin(); it != senders.end(); ++it) {
SrsUdpMuxSender* sender = *it;
srs_freep(sender);
}
}
}
srs_error_t SrsRtcServer::initialize()
{
srs_error_t err = srs_success;
if ((err = timer->tick(1 * SRS_UTIME_SECONDS)) != srs_success) {
return srs_error_wrap(err, "hourglass tick");
}
if ((err = timer->start()) != srs_success) {
return srs_error_wrap(err, "start timer");
}
srs_trace("RTC server init ok");
return err;
}
srs_error_t SrsRtcServer::listen_udp()
{
srs_error_t err = srs_success;
if (!_srs_config->get_rtc_server_enabled()) {
return err;
}
int port = _srs_config->get_rtc_server_listen();
if (port <= 0) {
return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port);
}
string ip = srs_any_address_for_listener();
srs_assert(listeners.empty());
int nn_listeners = _srs_config->get_rtc_server_reuseport();
for (int i = 0; i < nn_listeners; i++) {
SrsUdpMuxSender* sender = new SrsUdpMuxSender(this);
SrsUdpMuxListener* listener = new SrsUdpMuxListener(this, sender, ip, port);
if ((err = listener->listen()) != srs_success) {
srs_freep(listener);
return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port);
}
if ((err = sender->initialize(listener->stfd(), nn_listeners)) != srs_success) {
return srs_error_wrap(err, "init sender");
}
srs_trace("rtc listen at udp://%s:%d, fd=%d", ip.c_str(), port, listener->fd());
listeners.push_back(listener);
senders.push_back(sender);
}
return err;
}
srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt)
{
srs_error_t err = srs_success;
char* data = skt->data(); int size = skt->size();
SrsRtcSession* session = find_session_by_peer_id(skt->peer_id());
if (session) {
// Now, we got the RTC session to handle the packet, switch to its context
// to make all logs write to the "correct" pid+cid.
session->switch_to_context();
}
// For STUN, the peer address may change.
if (is_stun((uint8_t*)data, size)) {
SrsStunPacket ping;
if ((err = ping.decode(data, size)) != srs_success) {
return srs_error_wrap(err, "decode stun packet failed");
}
srs_verbose("recv stun packet from %s, use-candidate=%d, ice-controlled=%d, ice-controlling=%d",
skt->peer_id().c_str(), ping.get_use_candidate(), ping.get_ice_controlled(), ping.get_ice_controlling());
// TODO: FIXME: For ICE trickle, we may get STUN packets before SDP answer, so maybe should response it.
if (!session) {
session = find_session_by_username(ping.get_username());
if (session) {
session->switch_to_context();
}
}
if (session == NULL) {
return srs_error_new(ERROR_RTC_STUN, "can not find session, stun username=%s, peer_id=%s",
ping.get_username().c_str(), skt->peer_id().c_str());
}
return session->on_stun(skt, &ping);
}
// For DTLS, RTCP or RTP, which does not support peer address changing.
if (session == NULL) {
return srs_error_new(ERROR_RTC_STUN, "can not find session, peer_id=%s", skt->peer_id().c_str());
}
if (is_dtls((uint8_t*)data, size)) {
return session->on_dtls(data, size);
} else if (is_rtp_or_rtcp((uint8_t*)data, size)) {
if (is_rtcp((uint8_t*)data, size)) {
return session->on_rtcp(data, size);
}
return session->on_rtp(data, size);
}
return srs_error_new(ERROR_RTC_UDP, "unknown udp packet type");
}
srs_error_t SrsRtcServer::listen_api()
{
srs_error_t err = srs_success;
// TODO: FIXME: Fetch api from hybrid manager, not from SRS.
SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server();
if ((err = http_api_mux->handle("/rtc/v1/play/", new SrsGoApiRtcPlay(this))) != srs_success) {
return srs_error_wrap(err, "handle play");
}
if ((err = http_api_mux->handle("/rtc/v1/publish/", new SrsGoApiRtcPublish(this))) != srs_success) {
return srs_error_wrap(err, "handle publish");
}
#ifdef SRS_SIMULATOR
if ((err = http_api_mux->handle("/rtc/v1/nack/", new SrsGoApiRtcNACK(this))) != srs_success) {
return srs_error_wrap(err, "handle nack");
}
#endif
return err;
}
srs_error_t SrsRtcServer::create_session(
SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp, const std::string& mock_eip, bool publish,
SrsRtcSession** psession
) {
srs_error_t err = srs_success;
SrsSource* source = NULL;
// TODO: FIXME: Should refactor it, directly use http server as handler.
ISrsSourceHandler* handler = _srs_hybrid->srs()->instance();
if ((err = _srs_sources->fetch_or_create(req, handler, &source)) != srs_success) {
return srs_error_wrap(err, "create source");
}
// TODO: FIXME: Refine the API for stream status manage.
if (publish && !source->can_publish(false)) {
return srs_error_new(ERROR_RTC_SOURCE_BUSY, "stream %s busy", req->get_stream_url().c_str());
}
std::string local_pwd = gen_random_str(32);
std::string local_ufrag = "";
// TODO: FIXME: Rename for a better name, it's not an username.
std::string username = "";
while (true) {
local_ufrag = gen_random_str(8);
username = local_ufrag + ":" + remote_sdp.get_ice_ufrag();
if (!map_username_session.count(username)) {
break;
}
}
int cid = _srs_context->get_id();
SrsRtcSession* session = new SrsRtcSession(this);
if ((err = session->initialize(source, req, publish, username, cid)) != srs_success) {
srs_freep(session);
return srs_error_wrap(err, "init");
}
map_username_session.insert(make_pair(username, session));
*psession = session;
local_sdp.set_ice_ufrag(local_ufrag);
local_sdp.set_ice_pwd(local_pwd);
local_sdp.set_fingerprint_algo("sha-256");
local_sdp.set_fingerprint(SrsDtls::instance()->get_fingerprint());
// We allows to mock the eip of server.
if (!mock_eip.empty()) {
local_sdp.add_candidate(mock_eip, _srs_config->get_rtc_server_listen(), "host");
} else {
std::vector<string> candidate_ips = get_candidate_ips();
for (int i = 0; i < (int)candidate_ips.size(); ++i) {
local_sdp.add_candidate(candidate_ips[i], _srs_config->get_rtc_server_listen(), "host");
}
}
session->set_remote_sdp(remote_sdp);
session->set_local_sdp(local_sdp);
session->set_state(WAITING_STUN);
return err;
}
srs_error_t SrsRtcServer::create_session2(SrsSdp& local_sdp, SrsRtcSession** psession)
{
srs_error_t err = srs_success;
std::string local_pwd = gen_random_str(32);
// TODO: FIXME: Collision detect.
std::string local_ufrag = gen_random_str(8);
SrsRtcSession* session = new SrsRtcSession(this);
*psession = session;
local_sdp.set_ice_ufrag(local_ufrag);
local_sdp.set_ice_pwd(local_pwd);
local_sdp.set_fingerprint_algo("sha-256");
local_sdp.set_fingerprint(SrsDtls::instance()->get_fingerprint());
// We allows to mock the eip of server.
std::vector<string> candidate_ips = get_candidate_ips();
for (int i = 0; i < (int)candidate_ips.size(); ++i) {
local_sdp.add_candidate(candidate_ips[i], _srs_config->get_rtc_server_listen(), "host");
}
session->set_local_sdp(local_sdp);
session->set_state(WAITING_ANSWER);
return err;
}
srs_error_t SrsRtcServer::setup_session2(SrsRtcSession* session, SrsRequest* req, const SrsSdp& remote_sdp)
{
srs_error_t err = srs_success;
if (session->state() != WAITING_ANSWER) {
return err;
}
SrsSource* source = NULL;
// TODO: FIXME: Should refactor it, directly use http server as handler.
ISrsSourceHandler* handler = _srs_hybrid->srs()->instance();
if ((err = _srs_sources->fetch_or_create(req, handler, &source)) != srs_success) {
return srs_error_wrap(err, "create source");
}
// TODO: FIXME: Collision detect.
string username = session->get_local_sdp()->get_ice_ufrag() + ":" + remote_sdp.get_ice_ufrag();
int cid = _srs_context->get_id();
if ((err = session->initialize(source, req, false, username, cid)) != srs_success) {
return srs_error_wrap(err, "init");
}
map_username_session.insert(make_pair(username, session));
session->set_remote_sdp(remote_sdp);
session->set_state(WAITING_STUN);
return err;
}
bool SrsRtcServer::insert_into_id_sessions(const string& peer_id, SrsRtcSession* session)
{
return map_id_session.insert(make_pair(peer_id, session)).second;
}
void SrsRtcServer::check_and_clean_timeout_session()
{
map<string, SrsRtcSession*>::iterator iter = map_username_session.begin();
while (iter != map_username_session.end()) {
SrsRtcSession* session = iter->second;
if (session == NULL) {
map_username_session.erase(iter++);
continue;
}
if (session->is_stun_timeout()) {
// Now, we got the RTC session to cleanup, switch to its context
// to make all logs write to the "correct" pid+cid.
session->switch_to_context();
srs_trace("rtc session=%s, STUN timeout", session->id().c_str());
map_username_session.erase(iter++);
map_id_session.erase(session->peer_id());
delete session;
continue;
}
++iter;
}
}
int SrsRtcServer::nn_sessions()
{
return (int)map_username_session.size();
}
SrsRtcSession* SrsRtcServer::find_session_by_peer_id(const string& peer_id)
{
map<string, SrsRtcSession*>::iterator iter = map_id_session.find(peer_id);
if (iter == map_id_session.end()) {
return NULL;
}
return iter->second;
}
SrsRtcSession* SrsRtcServer::find_session_by_username(const std::string& username)
{
map<string, SrsRtcSession*>::iterator iter = map_username_session.find(username);
if (iter == map_username_session.end()) {
return NULL;
}
return iter->second;
}
srs_error_t SrsRtcServer::notify(int type, srs_utime_t interval, srs_utime_t tick)
{
check_and_clean_timeout_session();
return srs_success;
}
RtcServerAdapter::RtcServerAdapter()
{
rtc = new SrsRtcServer();
}
RtcServerAdapter::~RtcServerAdapter()
{
srs_freep(rtc);
}
srs_error_t RtcServerAdapter::initialize()
{
srs_error_t err = srs_success;
if ((err = rtc->initialize()) != srs_success) {
return srs_error_wrap(err, "rtc server initialize");
}
return err;
}
srs_error_t RtcServerAdapter::run()
{
srs_error_t err = srs_success;
if ((err = rtc->listen_udp()) != srs_success) {
return srs_error_wrap(err, "listen udp");
}
if ((err = rtc->listen_api()) != srs_success) {
return srs_error_wrap(err, "listen api");
}
return err;
}
void RtcServerAdapter::stop()
{
}

View file

@ -0,0 +1,143 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2013-2020 John
*
* 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.
*/
#ifndef SRS_APP_RTC_SERVER_HPP
#define SRS_APP_RTC_SERVER_HPP
#include <srs_core.hpp>
#include <srs_app_listener.hpp>
#include <srs_app_st.hpp>
#include <srs_app_reload.hpp>
#include <srs_app_hourglass.hpp>
#include <srs_app_hybrid.hpp>
#include <string>
class SrsRtcServer;
class SrsHourGlass;
class SrsRtcSession;
class SrsRequest;
class SrsSdp;
class SrsUdpMuxSender : virtual public ISrsUdpSender, virtual public ISrsCoroutineHandler, virtual public ISrsReloadHandler
{
private:
srs_netfd_t lfd;
SrsRtcServer* server;
SrsCoroutine* trd;
private:
srs_cond_t cond;
bool waiting_msgs;
bool gso;
int nn_senders;
private:
// Hotspot msgs, we are working on it.
// @remark We will wait util all messages are ready.
std::vector<srs_mmsghdr> hotspot;
// Cache msgs, for other coroutines to fill it.
std::vector<srs_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<srs_mmsghdr>& mhdrs);
public:
virtual srs_error_t fetch(srs_mmsghdr** pphdr);
virtual srs_error_t sendmmsg(srs_mmsghdr* hdr);
virtual bool overflow();
virtual void set_extra_ratio(int r);
public:
virtual srs_error_t cycle();
// interface ISrsReloadHandler
public:
virtual srs_error_t on_reload_rtc_server();
};
class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass
{
private:
SrsHourGlass* timer;
std::vector<SrsUdpMuxListener*> listeners;
std::vector<SrsUdpMuxSender*> senders;
private:
std::map<std::string, SrsRtcSession*> map_username_session; // key: username(local_ufrag + ":" + remote_ufrag)
std::map<std::string, SrsRtcSession*> map_id_session; // key: peerip(ip + ":" + port)
public:
SrsRtcServer();
virtual ~SrsRtcServer();
public:
virtual srs_error_t initialize();
public:
// TODO: FIXME: Support gracefully quit.
// TODO: FIXME: Support reload.
srs_error_t listen_udp();
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* skt);
srs_error_t listen_api();
public:
// Peer start offering, we answer it.
srs_error_t create_session(
SrsRequest* req, const SrsSdp& remote_sdp, SrsSdp& local_sdp, const std::string& mock_eip, bool publish,
SrsRtcSession** psession
);
// We start offering, create_session2 to generate offer, setup_session2 to handle answer.
srs_error_t create_session2(SrsSdp& local_sdp, SrsRtcSession** psession);
srs_error_t setup_session2(SrsRtcSession* session, SrsRequest* req, const SrsSdp& remote_sdp);
public:
bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* session);
void check_and_clean_timeout_session();
int nn_sessions();
SrsRtcSession* find_session_by_username(const std::string& ufrag);
private:
SrsRtcSession* find_session_by_peer_id(const std::string& peer_id);
// interface ISrsHourGlass
public:
virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick);
};
// The RTC server adapter.
class RtcServerAdapter : public ISrsHybridServer
{
private:
SrsRtcServer* rtc;
public:
RtcServerAdapter();
virtual ~RtcServerAdapter();
public:
virtual srs_error_t initialize();
virtual srs_error_t run();
virtual void stop();
};
#endif

View file

@ -81,13 +81,13 @@ SrsSimpleRtmpClient::~SrsSimpleRtmpClient()
srs_error_t SrsSimpleRtmpClient::connect_app()
{
std::vector<std::string> ips = srs_get_local_ips();
std::vector<SrsIPAddress*>& ips = srs_get_local_ips();
assert(_srs_config->get_stats_network() < (int)ips.size());
std::string local_ip = ips[_srs_config->get_stats_network()];
SrsIPAddress* local_ip = ips[_srs_config->get_stats_network()];
bool debug_srs_upnode = _srs_config->get_debug_srs_upnode(req->vhost);
return do_connect_app(local_ip, debug_srs_upnode);
return do_connect_app(local_ip->ip, debug_srs_upnode);
}
SrsClientInfo::SrsClientInfo()
@ -654,10 +654,13 @@ srs_error_t SrsRtmpConn::playing(SrsSource* source)
// Create a consumer of source.
SrsConsumer* consumer = NULL;
SrsAutoFree(SrsConsumer, consumer);
if ((err = source->create_consumer(this, consumer)) != srs_success) {
return srs_error_wrap(err, "rtmp: create consumer");
}
SrsAutoFree(SrsConsumer, consumer);
if ((err = source->consumer_dumps(consumer)) != srs_success) {
return srs_error_wrap(err, "rtmp: dumps consumer");
}
// Use receiving thread to receive packets from peer.
// @see: https://github.com/ossrs/srs/issues/217

View file

@ -30,7 +30,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <algorithm>
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
#include <sys/inotify.h>
#endif
using namespace std;
@ -349,7 +349,7 @@ SrsUdpCasterListener::~SrsUdpCasterListener()
srs_freep(caster);
}
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
SrsGb28181Listener::SrsGb28181Listener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsUdpStreamListener(svr, t, NULL)
{
@ -514,7 +514,7 @@ srs_error_t SrsInotifyWorker::start()
{
srs_error_t err = srs_success;
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
// Whether enable auto reload config.
bool auto_reload = _srs_config->inotify_auto_reload();
if (!auto_reload && _srs_in_docker && _srs_config->auto_reload_for_docker()) {
@ -594,7 +594,7 @@ srs_error_t SrsInotifyWorker::cycle()
{
srs_error_t err = srs_success;
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
string config_path = _srs_config->config();
string config_file = srs_path_basename(config_path);
string k8s_file = "..data";
@ -695,7 +695,7 @@ void SrsServer::destroy()
srs_freep(signal_manager);
srs_freep(conn_manager);
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
//free global gb28181 manager
srs_freep(_srs_gb28181);
#endif
@ -721,7 +721,7 @@ void SrsServer::dispose()
// @remark don't dispose all connections, for too slow.
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
srs_memory_report();
#endif
}
@ -763,7 +763,7 @@ void SrsServer::gracefully_dispose()
_srs_sources->dispose();
srs_trace("source disposed");
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
srs_memory_report();
#endif
@ -941,8 +941,8 @@ srs_error_t SrsServer::http_handle()
{
srs_error_t err = srs_success;
if ((err = http_api_mux->handle("/", new SrsHttpNotFoundHandler())) != srs_success) {
return srs_error_wrap(err, "handle not found");
if ((err = http_api_mux->handle("/", new SrsGoApiRoot())) != srs_success) {
return srs_error_wrap(err, "handle /");
}
if ((err = http_api_mux->handle("/api/", new SrsGoApiApi())) != srs_success) {
return srs_error_wrap(err, "handle api");
@ -992,7 +992,7 @@ srs_error_t SrsServer::http_handle()
if ((err = http_api_mux->handle("/api/v1/perf", new SrsGoApiPerf())) != srs_success) {
return srs_error_wrap(err, "handle perf");
}
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
if ((err = http_api_mux->handle("/api/v1/gb28181", new SrsGoApiGb28181())) != srs_success) {
return srs_error_wrap(err, "handle raw");
}
@ -1015,7 +1015,7 @@ srs_error_t SrsServer::http_handle()
return srs_error_wrap(err, "handle tests errors for error.srs.com");
}
#ifdef SRS_AUTO_GPERF
#ifdef SRS_GPERF
// The test api for get tcmalloc stats.
// @see Memory Introspection in https://gperftools.github.io/gperftools/tcmalloc.html
if ((err = http_api_mux->handle("/api/v1/tcmalloc", new SrsGoApiTcmalloc())) != srs_success) {
@ -1058,7 +1058,7 @@ srs_error_t SrsServer::cycle()
// Do server main cycle.
err = do_cycle();
#ifdef SRS_AUTO_GPERF_MC
#ifdef SRS_GPERF_MC
destroy();
// remark, for gmc, never invoke the exit().
@ -1104,7 +1104,7 @@ void SrsServer::on_signal(int signo)
return;
}
#ifndef SRS_AUTO_GPERF_MC
#ifndef SRS_GPERF_MC
if (signo == SRS_SIGNAL_REOPEN_LOG) {
_srs_log->reopen();
srs_warn("reopen log file, signo=%d", signo);
@ -1112,7 +1112,7 @@ void SrsServer::on_signal(int signo)
}
#endif
#ifdef SRS_AUTO_GPERF_MC
#ifdef SRS_GPERF_MC
if (signo == SRS_SIGNAL_REOPEN_LOG) {
signal_gmc_stop = true;
srs_warn("for gmc, the SIGUSR1 used as SIGINT, signo=%d", signo);
@ -1126,11 +1126,11 @@ void SrsServer::on_signal(int signo)
}
if (signo == SIGINT) {
#ifdef SRS_AUTO_GPERF_MC
#ifdef SRS_GPERF_MC
srs_trace("gmc is on, main cycle will terminate normally, signo=%d", signo);
signal_gmc_stop = true;
#else
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
srs_memory_report();
#endif
#endif
@ -1206,7 +1206,7 @@ srs_error_t SrsServer::do_cycle()
// if user interrupt the program, exit to check mem leak.
// but, if gperf, use reload to ensure main return normally,
// because directly exit will cause core-dump.
#ifdef SRS_AUTO_GPERF_MC
#ifdef SRS_GPERF_MC
if (signal_gmc_stop) {
srs_warn("gmc got singal to stop server.");
return err;
@ -1359,7 +1359,7 @@ srs_error_t SrsServer::listen_http_stream()
return err;
}
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
srs_error_t SrsServer::listen_gb28181_sip(SrsConfDirective* stream_caster)
{
srs_error_t err = srs_success;
@ -1410,7 +1410,7 @@ srs_error_t SrsServer::listen_stream_caster()
} else if (srs_stream_caster_is_flv(caster)) {
listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster);
} else if (srs_stream_caster_is_gb28181(caster)) {
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
//init global gb28181 manger
if (_srs_gb28181 == NULL){
_srs_gb28181 = new SrsGb28181Manger(stream_caster);

View file

@ -164,7 +164,7 @@ public:
virtual ~SrsUdpCasterListener();
};
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
// A UDP gb28181 listener, for sip and rtp stream mux server.
class SrsGb28181Listener : public SrsUdpStreamListener
@ -323,7 +323,7 @@ private:
virtual srs_error_t listen_http_api();
virtual srs_error_t listen_http_stream();
virtual srs_error_t listen_stream_caster();
#ifdef SRS_AUTO_GB28181
#ifdef SRS_GB28181
virtual srs_error_t listen_gb28181_sip(SrsConfDirective* c);
#endif
// Close the listeners for specified type,

View file

@ -31,7 +31,7 @@ using namespace std;
#include <srs_rtmp_stack.hpp>
#include <srs_protocol_amf0.hpp>
#include <srs_kernel_codec.hpp>
#include <srs_kernel_rtp.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_app_hls.hpp>
#include <srs_app_forward.hpp>
#include <srs_app_config.hpp>
@ -50,8 +50,9 @@ using namespace std;
#include <srs_app_ng_exec.hpp>
#include <srs_app_dash.hpp>
#include <srs_protocol_format.hpp>
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
#include <srs_app_rtc.hpp>
#include <srs_app_rtc_conn.hpp>
#endif
#define CONST_MAX_JITTER_MS 250
@ -456,6 +457,11 @@ SrsConsumer::~SrsConsumer()
#endif
}
void SrsConsumer::enable_pass_timestamp()
{
pass_timestamp = true;
}
void SrsConsumer::set_queue_size(srs_utime_t queue_size)
{
queue->set_queue_size(queue_size);
@ -843,58 +849,6 @@ SrsSharedPtrMessage* SrsMixQueue::pop()
return msg;
}
#ifdef SRS_AUTO_RTC
SrsRtpPacketQueue::SrsRtpPacketQueue()
{
}
SrsRtpPacketQueue::~SrsRtpPacketQueue()
{
clear();
}
void SrsRtpPacketQueue::clear()
{
map<uint16_t, SrsRtpSharedPacket*>::iterator iter = pkt_queue.begin();
while (iter != pkt_queue.end()) {
srs_freep(iter->second);
pkt_queue.erase(iter++);
}
}
void SrsRtpPacketQueue::push(std::vector<SrsRtpSharedPacket*>& pkts)
{
for (int i = 0; i < (int)pkts.size(); ++i) {
insert(pkts[i]->rtp_header.get_sequence(), pkts[i]);
}
}
void SrsRtpPacketQueue::insert(const uint16_t& sequence, SrsRtpSharedPacket* pkt)
{
pkt_queue.insert(make_pair(sequence, pkt->copy()));
// TODO: 3000 is magic number.
if (pkt_queue.size() >= 3000) {
srs_freep(pkt_queue.begin()->second);
pkt_queue.erase(pkt_queue.begin());
}
}
SrsRtpSharedPacket* SrsRtpPacketQueue::find(const uint16_t& sequence)
{
if (pkt_queue.empty()) {
return NULL;
}
SrsRtpSharedPacket* pkt = NULL;
map<uint16_t, SrsRtpSharedPacket*>::iterator iter = pkt_queue.find(sequence);
if (iter != pkt_queue.end()) {
pkt = iter->second->copy();
}
return pkt;
}
#endif
SrsOriginHub::SrsOriginHub()
{
source = NULL;
@ -905,10 +859,10 @@ SrsOriginHub::SrsOriginHub()
dash = new SrsDash();
dvr = new SrsDvr();
encoder = new SrsEncoder();
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
rtc = new SrsRtc();
#endif
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
hds = new SrsHds();
#endif
ng_exec = new SrsNgExec();
@ -936,7 +890,7 @@ SrsOriginHub::~SrsOriginHub()
srs_freep(dash);
srs_freep(dvr);
srs_freep(encoder);
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
srs_freep(hds);
#endif
}
@ -952,7 +906,7 @@ srs_error_t SrsOriginHub::initialize(SrsSource* s, SrsRequest* r)
return srs_error_wrap(err, "format initialize");
}
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
if ((err = rtc->initialize(this, req)) != srs_success) {
return srs_error_wrap(err, "rtc initialize");
}
@ -1030,6 +984,7 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
SrsSharedPtrMessage* msg = shared_audio;
// TODO: FIXME: Support parsing OPUS for RTC.
if ((err = format->on_audio(msg)) != srs_success) {
return srs_error_wrap(err, "format consume audio");
}
@ -1056,7 +1011,8 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
srs_flv_srates[c->sound_rate]);
}
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
// TODO: FIXME: Support parsing OPUS for RTC.
if ((err = rtc->on_audio(msg, format)) != srs_success) {
srs_warn("rtc: ignore audio error %s", srs_error_desc(err).c_str());
srs_error_reset(err);
@ -1095,7 +1051,7 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
dvr->on_unpublish();
}
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
if ((err = hds->on_audio(msg)) != srs_success) {
srs_warn("hds: ignore audio error %s", srs_error_desc(err).c_str());
srs_error_reset(err);
@ -1157,7 +1113,7 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se
return err;
}
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
// Parse RTMP message to RTP packets, in FU-A if too large.
if ((err = rtc->on_video(msg, format)) != srs_success) {
// TODO: We should support more strategies.
@ -1165,11 +1121,6 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se
srs_error_reset(err);
rtc->on_unpublish();
}
// TODO: FIXME: Refactor to move to rtp?
// Save the RTP packets for find_rtp_packet() to rtx or restore it.
// TODO: FIXME: Remove dead code.
//source->rtp_queue->push(msg->rtp_packets);
#endif
if ((err = hls->on_video(msg, format)) != srs_success) {
@ -1204,7 +1155,7 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se
dvr->on_unpublish();
}
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
if ((err = hds->on_video(msg)) != srs_success) {
srs_warn("hds: ignore video error %s", srs_error_desc(err).c_str());
srs_error_reset(err);
@ -1240,7 +1191,7 @@ srs_error_t SrsOriginHub::on_publish()
return srs_error_wrap(err, "encoder publish");
}
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
if ((err = rtc->on_publish()) != srs_success) {
return srs_error_wrap(err, "rtc publish");
}
@ -1259,7 +1210,7 @@ srs_error_t SrsOriginHub::on_publish()
}
// TODO: FIXME: use initialize to set req.
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
if ((err = hds->on_publish(req)) != srs_success) {
return srs_error_wrap(err, "hds publish");
}
@ -1283,14 +1234,14 @@ void SrsOriginHub::on_unpublish()
destroy_forwarders();
encoder->on_unpublish();
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
rtc->on_unpublish();
#endif
hls->on_unpublish();
dash->on_unpublish();
dvr->on_unpublish();
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
hds->on_unpublish();
#endif
@ -1479,7 +1430,7 @@ srs_error_t SrsOriginHub::on_reload_vhost_hds(string vhost)
// TODO: FIXME: maybe should ignore when publish already stopped?
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
hds->on_unpublish();
// Don't start HDS when source is not active.
@ -1947,9 +1898,6 @@ SrsSource::SrsSource()
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
mix_correct = false;
mix_queue = new SrsMixQueue();
#ifdef SRS_AUTO_RTC
rtp_queue = new SrsRtpPacketQueue();
#endif
_can_publish = true;
_pre_source_id = _source_id = -1;
@ -1966,6 +1914,10 @@ SrsSource::SrsSource()
_srs_config->subscribe(this);
atc = false;
#ifdef SRS_RTC
rtc_publisher_ = NULL;
#endif
}
SrsSource::~SrsSource()
@ -1979,9 +1931,6 @@ SrsSource::~SrsSource()
srs_freep(hub);
srs_freep(meta);
srs_freep(mix_queue);
#ifdef SRS_AUTO_RTC
srs_freep(rtp_queue);
#endif
srs_freep(play_edge);
srs_freep(publish_edge);
@ -2640,13 +2589,28 @@ void SrsSource::on_unpublish()
}
}
srs_error_t SrsSource::create_consumer(SrsConnection* conn, SrsConsumer*& consumer, bool ds, bool dm, bool dg)
srs_error_t SrsSource::create_consumer(SrsConnection* conn, SrsConsumer*& consumer)
{
srs_error_t err = srs_success;
consumer = new SrsConsumer(this, conn);
consumers.push_back(consumer);
// for edge, when play edge stream, check the state
if (_srs_config->get_vhost_is_edge(req->vhost)) {
// notice edge to start for the first client.
if ((err = play_edge->on_client_play()) != srs_success) {
return srs_error_wrap(err, "play edge");
}
}
return err;
}
srs_error_t SrsSource::consumer_dumps(SrsConsumer* consumer, bool ds, bool dm, bool dg)
{
srs_error_t err = srs_success;
srs_utime_t queue_size = _srs_config->get_queue_length(req->vhost);
consumer->set_queue_size(queue_size);
@ -2683,14 +2647,6 @@ srs_error_t SrsSource::create_consumer(SrsConnection* conn, SrsConsumer*& consum
srs_trace("create consumer, active=%d, ignore gop cache, jitter=%d", hub->active(), jitter_algorithm);
}
// for edge, when play edge stream, check the state
if (_srs_config->get_vhost_is_edge(req->vhost)) {
// notice edge to start for the first client.
if ((err = play_edge->on_client_play()) != srs_success) {
return srs_error_wrap(err, "play edge");
}
}
return err;
}
@ -2739,14 +2695,26 @@ string SrsSource::get_curr_origin()
return play_edge->get_curr_origin();
}
#ifdef SRS_AUTO_RTC
SrsRtpSharedPacket* SrsSource::find_rtp_packet(const uint16_t& seq)
{
return rtp_queue->find(seq);
}
#ifdef SRS_RTC
SrsMetaCache* SrsSource::cached_meta()
{
return meta;
}
SrsRtcPublisher* SrsSource::rtc_publisher()
{
return rtc_publisher_;
}
void SrsSource::set_rtc_publisher(SrsRtcPublisher* v)
{
rtc_publisher_ = v;
}
srs_error_t SrsSource::on_rtc_audio(SrsSharedPtrMessage* audio)
{
// TODO: FIXME: Merge with on_audio.
// TODO: FIXME: Print key information.
return on_audio_imp(audio);
}
#endif

View file

@ -59,10 +59,12 @@ class SrsDvr;
class SrsDash;
class SrsEncoder;
class SrsBuffer;
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
class SrsHds;
#endif
class SrsRtpSharedPacket;
#ifdef SRS_RTC
class SrsRtcPublisher;
#endif
// The time jitter algorithm:
// 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
@ -214,7 +216,7 @@ public:
virtual ~SrsConsumer();
public:
// Use pass timestamp mode.
void enable_pass_timestamp() { pass_timestamp = true; }
void enable_pass_timestamp();
// Set the size of queue.
virtual void set_queue_size(srs_utime_t queue_size);
// when source id changed, notice client to print.
@ -333,32 +335,6 @@ public:
virtual SrsSharedPtrMessage* pop();
};
#ifdef SRS_AUTO_RTC
// To find the RTP packet for RTX or restore.
// TODO: FIXME: Should queue RTP packets in connection level.
class SrsRtpPacketQueue
{
private:
struct SeqComp
{
bool operator()(const uint16_t& l, const uint16_t& r) const
{
return ((int16_t)(r - l)) > 0;
}
};
private:
std::map<uint16_t, SrsRtpSharedPacket*, SeqComp> pkt_queue;
public:
SrsRtpPacketQueue();
virtual ~SrsRtpPacketQueue();
public:
void clear();
void push(std::vector<SrsRtpSharedPacket*>& pkts);
void insert(const uint16_t& sequence, SrsRtpSharedPacket* pkt);
SrsRtpSharedPacket* find(const uint16_t& sequence);
};
#endif
// The hub for origin is a collection of utilities for origin only,
// For example, DVR, HLS, Forward and Transcode are only available for origin,
// they are meanless for edge server.
@ -371,7 +347,7 @@ private:
private:
// The format, codec information.
SrsRtmpFormat* format;
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
// rtc handler
SrsRtc* rtc;
#endif
@ -383,7 +359,7 @@ private:
SrsDvr* dvr;
// transcoding handler.
SrsEncoder* encoder;
#ifdef SRS_AUTO_HDS
#ifdef SRS_HDS
// adobe hds(http dynamic streaming).
SrsHds *hds;
#endif
@ -547,10 +523,6 @@ private:
bool mix_correct;
// The mix queue to implements the mix correct algorithm.
SrsMixQueue* mix_queue;
#ifdef SRS_AUTO_RTC
// rtp packet queue
SrsRtpPacketQueue* rtp_queue;
#endif
// For play, whether enabled atc.
// The atc(use absolute time and donot adjust time),
// directly use msg time and donot adjust if atc is true,
@ -577,6 +549,10 @@ private:
// The last die time, when all consumers quit and no publisher,
// We will remove the source when source die.
srs_utime_t die_at;
#ifdef SRS_RTC
private:
SrsRtcPublisher* rtc_publisher_;
#endif
public:
SrsSource();
virtual ~SrsSource();
@ -606,10 +582,12 @@ public:
virtual bool can_publish(bool is_edge);
virtual srs_error_t on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
public:
// TODO: FIXME: Use SrsSharedPtrMessage instead.
virtual srs_error_t on_audio(SrsCommonMessage* audio);
private:
virtual srs_error_t on_audio_imp(SrsSharedPtrMessage* audio);
public:
// TODO: FIXME: Use SrsSharedPtrMessage instead.
virtual srs_error_t on_video(SrsCommonMessage* video);
private:
virtual srs_error_t on_video_imp(SrsSharedPtrMessage* video);
@ -621,12 +599,14 @@ public:
virtual srs_error_t on_publish();
virtual void on_unpublish();
public:
// Create consumer and dumps packets in cache.
// Create consumer
// @param consumer, output the create consumer.
virtual srs_error_t create_consumer(SrsConnection* conn, SrsConsumer*& consumer);
// Dumps packets in cache to consumer.
// @param ds, whether dumps the sequence header.
// @param dm, whether dumps the metadata.
// @param dg, whether dumps the gop cache.
virtual srs_error_t create_consumer(SrsConnection* conn, SrsConsumer*& consumer, bool ds = true, bool dm = true, bool dg = true);
virtual srs_error_t consumer_dumps(SrsConsumer* consumer, bool ds = true, bool dm = true, bool dg = true);
virtual void on_consumer_destroy(SrsConsumer* consumer);
virtual void set_cache(bool enabled);
virtual SrsRtmpJitterAlgorithm jitter();
@ -639,12 +619,16 @@ public:
virtual void on_edge_proxy_unpublish();
public:
virtual std::string get_curr_origin();
#ifdef SRS_RTC
public:
#ifdef SRS_AUTO_RTC
// Find rtp packet by sequence
SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq);
// Get the cached meta, as such the sps/pps.
// For RTC, we need to package SPS/PPS(in cached meta) before each IDR.
SrsMetaCache* cached_meta();
// Get and set the publisher, passed to consumer to process requests such as PLI.
SrsRtcPublisher* rtc_publisher();
void set_rtc_publisher(SrsRtcPublisher* v);
// When got RTC audio message, which is encoded in opus.
// TODO: FIXME: Merge with on_audio.
srs_error_t on_rtc_audio(SrsSharedPtrMessage* audio);
#endif
};

View file

@ -35,7 +35,7 @@
#include <sys/time.h>
#include <math.h>
#include <map>
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
#include <sys/sysctl.h>
#endif
using namespace std;
@ -329,7 +329,7 @@ SrsProcSystemStat* srs_get_system_proc_stat()
bool get_proc_system_stat(SrsProcSystemStat& r)
{
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
FILE* f = fopen("/proc/stat", "r");
if (f == NULL) {
srs_warn("open system cpu stat failed, ignore");
@ -368,7 +368,7 @@ bool get_proc_system_stat(SrsProcSystemStat& r)
bool get_proc_self_stat(SrsProcSelfStat& r)
{
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
FILE* f = fopen("/proc/self/stat", "r");
if (f == NULL) {
srs_warn("open self cpu stat failed, ignore");
@ -491,7 +491,7 @@ SrsDiskStat* srs_get_disk_stat()
bool srs_get_disk_vmstat_stat(SrsDiskStat& r)
{
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
FILE* f = fopen("/proc/vmstat", "r");
if (f == NULL) {
srs_warn("open vmstat failed, ignore");
@ -523,7 +523,7 @@ bool srs_get_disk_diskstats_stat(SrsDiskStat& r)
r.ok = true;
r.sample_time = srsu2ms(srs_get_system_time());
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
// if disabled, ignore all devices.
SrsConfDirective* conf = _srs_config->get_stats_disk_device();
if (conf == NULL) {
@ -687,7 +687,7 @@ void srs_update_meminfo()
{
SrsMemInfo& r = _srs_system_meminfo;
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
FILE* f = fopen("/proc/meminfo", "r");
if (f == NULL) {
srs_warn("open meminfo failed, ignore");
@ -781,7 +781,7 @@ void srs_update_platform_info()
r.srs_startup_time = srsu2ms(srs_get_system_startup_time());
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
if (true) {
FILE* f = fopen("/proc/uptime", "r");
if (f == NULL) {
@ -893,7 +893,7 @@ int srs_get_network_devices_count()
void srs_update_network_devices()
{
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
if (true) {
FILE* f = fopen("/proc/net/dev", "r");
if (f == NULL) {
@ -978,7 +978,7 @@ void srs_update_rtmp_server(int nb_conn, SrsKbps* kbps)
int nb_tcp_mem = 0;
int nb_udp4 = 0;
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
if (true) {
FILE* f = fopen("/proc/net/sockstat", "r");
if (f == NULL) {
@ -1021,7 +1021,7 @@ void srs_update_rtmp_server(int nb_conn, SrsKbps* kbps)
int nb_tcp_estab = 0;
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
if (true) {
FILE* f = fopen("/proc/net/snmp", "r");
if (f == NULL) {

View file

@ -33,11 +33,6 @@
// The macros generated by configure script.
#include <srs_auto_headers.hpp>
// Alias for debug.
#ifdef SRS_AUTO_DEBUG
#define SRS_DEBUG
#endif
// To convert macro values to string.
// @see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
#define SRS_INTERNAL_STR(v) #v
@ -68,7 +63,7 @@
#endif
// For RTC/FFMPEG build.
#if defined(SRS_AUTO_RTC) && !defined(__STDC_CONSTANT_MACROS)
#if defined(SRS_RTC) && !defined(__STDC_CONSTANT_MACROS)
#define __STDC_CONSTANT_MACROS
#endif

View file

@ -23,7 +23,7 @@
#include <srs_core_mem_watch.hpp>
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
#include <map>
#include <stdio.h>

View file

@ -26,7 +26,7 @@
#include <srs_core.hpp>
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
#warning "MemoryWatch is deprecated."

View file

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

View file

@ -45,19 +45,10 @@ ISrsCodec::~ISrsCodec()
{
}
SrsBuffer::SrsBuffer()
{
p = bytes = NULL;
nb_bytes = 0;
// TODO: support both little and big endian.
srs_assert(srs_is_little_endian());
}
SrsBuffer::SrsBuffer(char* b, int nb_b)
SrsBuffer::SrsBuffer(char* b, int nn)
{
p = bytes = b;
nb_bytes = nb_b;
nb_bytes = nn;
// TODO: support both little and big endian.
srs_assert(srs_is_little_endian());
@ -67,11 +58,26 @@ SrsBuffer::~SrsBuffer()
{
}
char* SrsBuffer::data()
{
return bytes;
}
char* SrsBuffer::head()
{
return p;
}
int SrsBuffer::size()
{
return nb_bytes;
}
void SrsBuffer::set_size(int v)
{
nb_bytes = v;
}
int SrsBuffer::pos()
{
return (int)(p - bytes);

View file

@ -97,118 +97,75 @@ class SrsBuffer
private:
// current position at bytes.
char* p;
// the bytes data for stream to read or write.
// the bytes data for buffer to read or write.
char* bytes;
// the total number of bytes.
int nb_bytes;
public:
SrsBuffer();
// Initialize buffer with data b and size nb_b.
// Create buffer with data b and size nn.
// @remark User must free the data b.
SrsBuffer(char* b, int nb_b);
virtual ~SrsBuffer();
// get the status of stream
SrsBuffer(char* b, int nn);
~SrsBuffer();
public:
/**
* get data of stream, set by initialize.
* current bytes = data() + pos()
*/
inline char* data() { return bytes; }
inline char* head() { return p; }
/**
* the total stream size, set by initialize.
* left bytes = size() - pos().
*/
virtual int size();
/**
* tell the current pos.
*/
virtual int pos();
// Get the data and head of buffer.
// current-bytes = head() = data() + pos()
char* data();
char* head();
// Get the total size of buffer.
// left-bytes = size() - pos()
int size();
void set_size(int v);
// Get the current buffer position.
int pos();
// Left bytes in buffer, total size() minus the current pos().
virtual int left();
/**
* whether stream is empty.
* if empty, user should never read or write.
*/
virtual bool empty();
/**
* whether required size is ok.
* @return true if stream can read/write specified required_size bytes.
* @remark assert required_size positive.
*/
virtual bool require(int required_size);
// to change stream.
int left();
// Whether buffer is empty.
bool empty();
// Whether buffer is able to supply required size of bytes.
// @remark User should check buffer by require then do read/write.
// @remark Assert the required_size is not negative.
bool require(int required_size);
public:
/**
* to skip some size.
* @param size can be any value. positive to forward; nagetive to backward.
* @remark to skip(pos()) to reset stream.
* @remark assert initialized, the data() not NULL.
*/
virtual void skip(int size);
// Skip some size.
// @param size can be any value. positive to forward; nagetive to backward.
// @remark to skip(pos()) to reset buffer.
// @remark assert initialized, the data() not NULL.
void skip(int size);
public:
/**
* get 1bytes char from stream.
*/
virtual int8_t read_1bytes();
/**
* get 2bytes int from stream.
*/
virtual int16_t read_2bytes();
/**
* get 3bytes int from stream.
*/
virtual int32_t read_3bytes();
/**
* get 4bytes int from stream.
*/
virtual int32_t read_4bytes();
/**
* get 8bytes int from stream.
*/
virtual int64_t read_8bytes();
/**
* get string from stream, length specifies by param len.
*/
virtual std::string read_string(int len);
/**
* get bytes from stream, length specifies by param len.
*/
virtual void read_bytes(char* data, int size);
// Read 1bytes char from buffer.
int8_t read_1bytes();
// Read 2bytes int from buffer.
int16_t read_2bytes();
// Read 3bytes int from buffer.
int32_t read_3bytes();
// Read 4bytes int from buffer.
int32_t read_4bytes();
// Read 8bytes int from buffer.
int64_t read_8bytes();
// Read string from buffer, length specifies by param len.
std::string read_string(int len);
// Read bytes from buffer, length specifies by param len.
void read_bytes(char* data, int size);
public:
/**
* write 1bytes char to stream.
*/
virtual void write_1bytes(int8_t value);
/**
* write 2bytes int to stream.
*/
virtual void write_2bytes(int16_t value);
/**
* write 4bytes int to stream.
*/
virtual void write_4bytes(int32_t value);
/**
* write 3bytes int to stream.
*/
virtual void write_3bytes(int32_t value);
/**
* write 8bytes int to stream.
*/
virtual void write_8bytes(int64_t value);
/**
* write string to stream
*/
virtual void write_string(std::string value);
/**
* write bytes to stream
*/
virtual void write_bytes(char* data, int size);
// Write 1bytes char to buffer.
void write_1bytes(int8_t value);
// Write 2bytes int to buffer.
void write_2bytes(int16_t value);
// Write 4bytes int to buffer.
void write_4bytes(int32_t value);
// Write 3bytes int to buffer.
void write_3bytes(int32_t value);
// Write 8bytes int to buffer.
void write_8bytes(int64_t value);
// Write string to buffer
void write_string(std::string value);
// Write bytes to buffer
void write_bytes(char* data, int size);
};
/**
* the bit stream, base on SrsBuffer,
* for exmaple, the h.264 avc stream is bit stream.
* the bit buffer, base on SrsBuffer,
* for exmaple, the h.264 avc buffer is bit buffer.
*/
class SrsBitBuffer
{
@ -218,10 +175,10 @@ private:
SrsBuffer* stream;
public:
SrsBitBuffer(SrsBuffer* b);
virtual ~SrsBitBuffer();
~SrsBitBuffer();
public:
virtual bool empty();
virtual int8_t read_bit();
bool empty();
int8_t read_bit();
};
#endif

View file

@ -32,7 +32,7 @@ using namespace std;
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_rtp.hpp>
#include <srs_kernel_rtc_rtp.hpp>
string srs_video_codec_id2str(SrsVideoCodecId codec)
{
@ -603,7 +603,7 @@ srs_error_t SrsFormat::on_audio(int64_t timestamp, char* data, int size)
srs_error_t err = srs_success;
if (!data || size <= 0) {
srs_trace("no audio present, ignore it.");
srs_info("no audio present, ignore it.");
return err;
}

View file

@ -347,6 +347,11 @@
#define ERROR_RTC_RTCP_CHECK 5016
#define ERROR_RTC_SOURCE_CHECK 5017
#define ERROR_RTC_SDP_EXCHANGE 5018
#define ERROR_RTC_API_BODY 5019
#define ERROR_RTC_SOURCE_BUSY 5020
#define ERROR_RTC_DISABLED 5021
#define ERROR_RTC_NO_SESSION 5022
#define ERROR_RTC_INVALID_PARAMS 5023
///////////////////////////////////////////////////////
// GB28181 API error.

View file

@ -40,8 +40,8 @@ using namespace std;
#include <srs_kernel_utility.hpp>
#include <srs_core_mem_watch.hpp>
#include <srs_core_autofree.hpp>
#ifdef SRS_AUTO_RTC
#include <srs_kernel_rtp.hpp>
#ifdef SRS_RTC
#include <srs_kernel_rtc_rtp.hpp>
#endif
SrsMessageHeader::SrsMessageHeader()
@ -164,7 +164,7 @@ SrsCommonMessage::SrsCommonMessage()
SrsCommonMessage::~SrsCommonMessage()
{
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
srs_memory_unwatch(payload);
#endif
srs_freepa(payload);
@ -177,7 +177,7 @@ void SrsCommonMessage::create_payload(int size)
payload = new char[size];
srs_verbose("create payload for RTMP message. size=%d", size);
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
srs_memory_watch(payload, "RTMP.msg.payload", size);
#endif
}
@ -211,7 +211,7 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()
size = 0;
shared_count = 0;
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
samples = NULL;
nn_samples = 0;
has_idr = false;
@ -224,12 +224,12 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload()
SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload()
{
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
srs_memory_unwatch(payload);
#endif
srs_freepa(payload);
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
srs_freepa(samples);
for (int i = 0; i < nn_extra_payloads; i++) {
@ -376,7 +376,7 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy()
return copy;
}
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
void SrsSharedPtrMessage::set_extra_payloads(SrsSample* payloads, int nn_payloads)
{
srs_assert(nn_payloads);
@ -388,6 +388,36 @@ void SrsSharedPtrMessage::set_extra_payloads(SrsSample* payloads, int nn_payload
memcpy((void*)ptr->extra_payloads, payloads, nn_payloads * sizeof(SrsSample));
}
int SrsSharedPtrMessage::nn_extra_payloads()
{
return ptr->nn_extra_payloads;
}
SrsSample* SrsSharedPtrMessage::extra_payloads()
{
return ptr->extra_payloads;
}
void SrsSharedPtrMessage::set_max_extra_payload(int v)
{
ptr->nn_max_extra_payloads = v;
}
int SrsSharedPtrMessage::nn_max_extra_payloads()
{
return ptr->nn_max_extra_payloads;
}
bool SrsSharedPtrMessage::has_idr()
{
return ptr->has_idr;
}
void SrsSharedPtrMessage::set_has_idr(bool v)
{
ptr->has_idr = v;
}
void SrsSharedPtrMessage::set_samples(SrsSample* samples, int nn_samples)
{
srs_assert(nn_samples);
@ -398,6 +428,16 @@ void SrsSharedPtrMessage::set_samples(SrsSample* samples, int nn_samples)
ptr->samples = new SrsSample[nn_samples];
memcpy((void*)ptr->samples, samples, nn_samples * sizeof(SrsSample));
}
int SrsSharedPtrMessage::nn_samples()
{
return ptr->nn_samples;
}
SrsSample* SrsSharedPtrMessage::samples()
{
return ptr->samples;
}
#endif
SrsFlvTransmuxer::SrsFlvTransmuxer()

View file

@ -39,7 +39,6 @@ class ISrsWriter;
class ISrsReader;
class SrsFileReader;
class SrsPacket;
class SrsRtpSharedPacket;
class SrsSample;
#define SRS_FLV_TAG_HEADER_SIZE 11
@ -158,6 +157,7 @@ public:
// 1byte.
// One byte field to represent the message type. A range of type IDs
// (1-7) are reserved for protocol control messages.
// For example, RTMP_MSG_AudioMessage or RTMP_MSG_VideoMessage.
int8_t message_type;
// 4bytes.
// Four-byte field that identifies the stream of the message. These
@ -245,6 +245,7 @@ public:
// 1byte.
// One byte field to represent the message type. A range of type IDs
// (1-7) are reserved for protocol control messages.
// For example, RTMP_MSG_AudioMessage or RTMP_MSG_VideoMessage.
int8_t message_type;
// Get the perfered cid(chunk stream id) which sendout over.
// set at decoding, and canbe used for directly send message,
@ -302,7 +303,7 @@ private:
int size;
// The reference count
int shared_count;
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
public:
// For RTC video, we need to know the NALU structures,
// because the RTP STAP-A or FU-A based on NALU.
@ -361,22 +362,22 @@ public:
// @remark, assert object is created.
virtual SrsSharedPtrMessage* copy();
public:
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
// 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; }
int nn_extra_payloads();
SrsSample* 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; }
void set_max_extra_payload(int v);
int 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; }
bool has_idr();
void set_has_idr(bool 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; }
int nn_samples();
SrsSample* samples();
#endif
};

View file

@ -129,15 +129,15 @@ extern ISrsThreadContext* _srs_context;
#endif
// TODO: FIXME: Add more verbose and info logs.
#ifndef SRS_AUTO_VERBOSE
#ifndef SRS_VERBOSE
#undef srs_verbose
#define srs_verbose(msg, ...) (void)0
#endif
#ifndef SRS_AUTO_INFO
#ifndef SRS_INFO
#undef srs_info
#define srs_info(msg, ...) (void)0
#endif
#ifndef SRS_AUTO_TRACE
#ifndef SRS_TRACE
#undef srs_trace
#define srs_trace(msg, ...) (void)0
#endif

View file

@ -6276,7 +6276,6 @@ SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
writer = NULL;
nb_audios = nb_videos = 0;
samples = new SrsMp4SampleManager();
buffer = new SrsBuffer();
sequence_number = 0;
decode_basetime = 0;
styp_bytes = 0;
@ -6286,7 +6285,6 @@ SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
SrsMp4M2tsSegmentEncoder::~SrsMp4M2tsSegmentEncoder()
{
srs_freep(samples);
srs_freep(buffer);
}
srs_error_t SrsMp4M2tsSegmentEncoder::initialize(ISrsWriter* w, uint32_t sequence, srs_utime_t basetime, uint32_t tid)

View file

@ -2105,7 +2105,6 @@ class SrsMp4M2tsSegmentEncoder
{
private:
ISrsWriter* writer;
SrsBuffer* buffer;
uint32_t sequence_number;
srs_utime_t decode_basetime;
uint32_t track_id;

View file

@ -21,7 +21,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_kernel_rtp.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <fcntl.h>
#include <sstream>
@ -32,19 +32,10 @@ using namespace std;
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_utility.hpp>
// @see: https://tools.ietf.org/html/rfc6184#section-5.2
const uint8_t kStapA = 24;
// @see: https://tools.ietf.org/html/rfc6184#section-5.2
const uint8_t kFuA = 28;
// @see: https://tools.ietf.org/html/rfc6184#section-5.8
const uint8_t kStart = 0x80; // Fu-header start bit
const uint8_t kEnd = 0x40; // Fu-header end bit
SrsRtpHeader::SrsRtpHeader()
{
padding = false;
padding_length = 0;
extension = false;
cc = 0;
marker = false;
@ -70,22 +61,82 @@ SrsRtpHeader::~SrsRtpHeader()
{
}
srs_error_t SrsRtpHeader::decode(SrsBuffer* stream)
srs_error_t SrsRtpHeader::decode(SrsBuffer* buf)
{
srs_error_t err = srs_success;
// TODO: FIXME: Implements it.
if (!buf->require(kRtpHeaderFixedSize)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d+ bytes", kRtpHeaderFixedSize);
}
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
uint8_t first = buf->read_1bytes();
padding = (first & 0x20);
extension = (first & 0x10);
cc = (first & 0x0F);
uint8_t second = buf->read_1bytes();
marker = (second & 0x80);
payload_type = (second & 0x7F);
sequence = buf->read_2bytes();
timestamp = buf->read_4bytes();
ssrc = buf->read_4bytes();
int ext_bytes = nb_bytes() - kRtpHeaderFixedSize;
if (!buf->require(ext_bytes)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d+ bytes", ext_bytes);
}
for (uint8_t i = 0; i < cc; ++i) {
csrc[i] = buf->read_4bytes();
}
if (extension) {
uint16_t profile_id = buf->read_2bytes();
extension_length = buf->read_2bytes();
// TODO: FIXME: Read extensions.
// @see: https://tools.ietf.org/html/rfc3550#section-5.3.1
buf->skip(extension_length * 4);
// @see: https://tools.ietf.org/html/rfc5285#section-4.2
if (profile_id == 0xBEDE) {
// TODO: FIXME: Implements it.
}
}
if (padding && !buf->empty()) {
padding_length = *(reinterpret_cast<uint8_t*>(buf->data() + buf->size() - 1));
if (!buf->require(padding_length)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "padding requires %d bytes", padding_length);
}
}
return err;
}
srs_error_t SrsRtpHeader::encode(SrsBuffer* stream)
srs_error_t SrsRtpHeader::encode(SrsBuffer* buf)
{
srs_error_t err = srs_success;
// Encode the RTP fix header, 12bytes.
// @see https://tools.ietf.org/html/rfc1889#section-5.1
char* op = stream->head();
char* op = buf->head();
char* p = op;
// The version, padding, extension and cc, total 1 byte.
@ -138,20 +189,97 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* stream)
}
// Consume the data.
stream->skip(p - op);
buf->skip(p - op);
return err;
}
size_t SrsRtpHeader::header_size()
int SrsRtpHeader::nb_bytes()
{
return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0);
}
void SrsRtpHeader::set_marker(bool v)
{
marker = v;
}
bool SrsRtpHeader::get_marker() const
{
return marker;
}
void SrsRtpHeader::set_payload_type(uint8_t v)
{
payload_type = v;
}
uint8_t SrsRtpHeader::get_payload_type() const
{
return payload_type;
}
void SrsRtpHeader::set_sequence(uint16_t v)
{
sequence = v;
}
uint16_t SrsRtpHeader::get_sequence() const
{
return sequence;
}
void SrsRtpHeader::set_timestamp(uint32_t v)
{
timestamp = v;
}
uint32_t SrsRtpHeader::get_timestamp() const
{
return timestamp;
}
void SrsRtpHeader::set_ssrc(uint32_t v)
{
ssrc = v;
}
uint32_t SrsRtpHeader::get_ssrc() const
{
return ssrc;
}
void SrsRtpHeader::set_padding(bool v)
{
padding = v;
}
void SrsRtpHeader::set_padding_length(uint8_t v)
{
padding_length = v;
}
uint8_t SrsRtpHeader::get_padding_length() const
{
return padding_length;
}
ISrsRtpPacketDecodeHandler::ISrsRtpPacketDecodeHandler()
{
}
ISrsRtpPacketDecodeHandler::~ISrsRtpPacketDecodeHandler()
{
}
SrsRtpPacket2::SrsRtpPacket2()
{
payload = NULL;
padding = 0;
payload = NULL;
decode_handler = NULL;
nalu_type = SrsAvcNaluTypeReserved;
original_bytes = NULL;
cache_raw = new SrsRtpRawPayload();
cache_fua = new SrsRtpFUAPayload2();
@ -168,11 +296,14 @@ SrsRtpPacket2::~SrsRtpPacket2()
srs_freep(payload);
srs_freep(cache_raw);
srs_freep(cache_fua);
srs_freepa(original_bytes);
}
void SrsRtpPacket2::set_padding(int size)
{
rtp_header.set_padding(size > 0);
rtp_header.set_padding_length(size);
if (cache_payload) {
cache_payload += size - padding;
}
@ -182,6 +313,7 @@ void SrsRtpPacket2::set_padding(int size)
void SrsRtpPacket2::add_padding(int size)
{
rtp_header.set_padding(padding + size > 0);
rtp_header.set_padding_length(rtp_header.get_padding_length() + size);
if (cache_payload) {
cache_payload += size;
}
@ -213,10 +345,15 @@ SrsRtpFUAPayload2* SrsRtpPacket2::reuse_fua()
return cache_fua;
}
void SrsRtpPacket2::set_decode_handler(ISrsRtpPacketDecodeHandler* h)
{
decode_handler = h;
}
int SrsRtpPacket2::nb_bytes()
{
if (!cache_payload) {
cache_payload = rtp_header.header_size() + (payload? payload->nb_bytes():0) + padding;
cache_payload = rtp_header.nb_bytes() + (payload? payload->nb_bytes():0) + padding;
}
return cache_payload;
}
@ -230,7 +367,7 @@ srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf)
}
if (payload && (err = payload->encode(buf)) != srs_success) {
return srs_error_wrap(err, "encode payload");
return srs_error_wrap(err, "rtp payload");
}
if (padding > 0) {
@ -244,6 +381,43 @@ srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf)
return err;
}
srs_error_t SrsRtpPacket2::decode(SrsBuffer* buf)
{
srs_error_t err = srs_success;
if ((err = rtp_header.decode(buf)) != srs_success) {
return srs_error_wrap(err, "rtp header");
}
// We must skip the padding bytes before parsing payload.
padding = rtp_header.get_padding_length();
if (!buf->require(padding)) {
return srs_error_wrap(err, "requires padding %d bytes", padding);
}
buf->set_size(buf->size() - padding);
// Try to parse the NALU type for video decoder.
if (!buf->empty()) {
nalu_type = SrsAvcNaluType((uint8_t)(buf->head()[0] & kNalTypeMask));
}
// If user set the decode handler, call it to set the payload.
if (decode_handler) {
decode_handler->on_before_decode_payload(this, buf, &payload);
}
// By default, we always use the RAW payload.
if (!payload) {
payload = reuse_raw();
}
if ((err = payload->decode(buf)) != srs_success) {
return srs_error_wrap(err, "rtp payload");
}
return err;
}
SrsRtpRawPayload::SrsRtpRawPayload()
{
payload = NULL;
@ -274,6 +448,18 @@ srs_error_t SrsRtpRawPayload::encode(SrsBuffer* buf)
return srs_success;
}
srs_error_t SrsRtpRawPayload::decode(SrsBuffer* buf)
{
if (buf->empty()) {
return srs_success;
}
payload = buf->head();
nn_payload = buf->left();
return srs_success;
}
SrsRtpRawNALUs::SrsRtpRawNALUs()
{
cursor = 0;
@ -282,12 +468,10 @@ SrsRtpRawNALUs::SrsRtpRawNALUs()
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);
}
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
srs_freep(p);
}
}
@ -382,6 +566,22 @@ srs_error_t SrsRtpRawNALUs::encode(SrsBuffer* buf)
return srs_success;
}
srs_error_t SrsRtpRawNALUs::decode(SrsBuffer* buf)
{
if (buf->empty()) {
return srs_success;
}
SrsSample* sample = new SrsSample();
sample->bytes = buf->head();
sample->size = buf->left();
buf->skip(sample->size);
nalus.push_back(sample);
return srs_success;
}
SrsRtpSTAPPayload::SrsRtpSTAPPayload()
{
nri = (SrsAvcNaluType)0;
@ -396,6 +596,42 @@ SrsRtpSTAPPayload::~SrsRtpSTAPPayload()
}
}
SrsSample* SrsRtpSTAPPayload::get_sps()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
if (!p || !p->size) {
continue;
}
SrsAvcNaluType nalu_type = (SrsAvcNaluType)(p->bytes[0] & kNalTypeMask);
if (nalu_type == SrsAvcNaluTypeSPS) {
return p;
}
}
return NULL;
}
SrsSample* SrsRtpSTAPPayload::get_pps()
{
int nn_nalus = (int)nalus.size();
for (int i = 0; i < nn_nalus; i++) {
SrsSample* p = nalus[i];
if (!p || !p->size) {
continue;
}
SrsAvcNaluType nalu_type = (SrsAvcNaluType)(p->bytes[0] & kNalTypeMask);
if (nalu_type == SrsAvcNaluTypePPS) {
return p;
}
}
return NULL;
}
int SrsRtpSTAPPayload::nb_bytes()
{
int size = 1;
@ -437,6 +673,39 @@ srs_error_t SrsRtpSTAPPayload::encode(SrsBuffer* buf)
return srs_success;
}
srs_error_t SrsRtpSTAPPayload::decode(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 = buf->read_1bytes();
nri = SrsAvcNaluType(v & (~kNalTypeMask));
// NALUs.
while (!buf->empty()) {
if (!buf->require(2)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2);
}
int size = buf->read_2bytes();
if (!buf->require(size)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", size);
}
SrsSample* sample = new SrsSample();
sample->bytes = buf->head();
sample->size = size;
buf->skip(size);
nalus.push_back(sample);
}
return srs_success;
}
SrsRtpFUAPayload::SrsRtpFUAPayload()
{
start = end = false;
@ -501,6 +770,36 @@ srs_error_t SrsRtpFUAPayload::encode(SrsBuffer* buf)
return srs_success;
}
srs_error_t SrsRtpFUAPayload::decode(SrsBuffer* buf)
{
if (!buf->require(2)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2);
}
// FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8
uint8_t v = buf->read_1bytes();
nri = SrsAvcNaluType(v & (~kNalTypeMask));
// FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8
v = buf->read_1bytes();
start = v & kStart;
end = v & kEnd;
nalu_type = SrsAvcNaluType(v & kNalTypeMask);
if (!buf->require(1)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
}
SrsSample* sample = new SrsSample();
sample->bytes = buf->head();
sample->size = buf->left();
buf->skip(sample->size);
nalus.push_back(sample);
return srs_success;
}
SrsRtpFUAPayload2::SrsRtpFUAPayload2()
{
start = end = false;
@ -552,131 +851,29 @@ srs_error_t SrsRtpFUAPayload2::encode(SrsBuffer* buf)
return srs_success;
}
SrsRtpSharedPacket::SrsRtpSharedPacketPayload::SrsRtpSharedPacketPayload()
srs_error_t SrsRtpFUAPayload2::decode(SrsBuffer* buf)
{
payload = NULL;
size = 0;
shared_count = 0;
}
SrsRtpSharedPacket::SrsRtpSharedPacketPayload::~SrsRtpSharedPacketPayload()
{
srs_freepa(payload);
}
SrsRtpSharedPacket::SrsRtpSharedPacket()
{
payload_ptr = NULL;
payload = NULL;
size = 0;
}
SrsRtpSharedPacket::~SrsRtpSharedPacket()
{
if (payload_ptr) {
if (payload_ptr->shared_count == 0) {
srs_freep(payload_ptr);
} else {
--payload_ptr->shared_count;
}
}
}
srs_error_t SrsRtpSharedPacket::create(int64_t timestamp, uint16_t sequence, uint32_t ssrc, uint16_t payload_type, char* p, int s)
{
srs_error_t err = srs_success;
if (s < 0) {
return srs_error_new(ERROR_RTP_PACKET_CREATE, "create packet size=%d", s);
if (!buf->require(2)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2);
}
srs_assert(!payload_ptr);
// FU indicator, @see https://tools.ietf.org/html/rfc6184#section-5.8
uint8_t v = buf->read_1bytes();
nri = SrsAvcNaluType(v & (~kNalTypeMask));
rtp_header.set_timestamp(timestamp);
rtp_header.set_sequence(sequence);
rtp_header.set_ssrc(ssrc);
rtp_header.set_payload_type(payload_type);
// FU header, @see https://tools.ietf.org/html/rfc6184#section-5.8
v = buf->read_1bytes();
start = v & kStart;
end = v & kEnd;
nalu_type = SrsAvcNaluType(v & kNalTypeMask);
// TODO: rtp header padding.
size_t buffer_size = rtp_header.header_size() + s;
char* buffer = new char[buffer_size];
SrsBuffer stream(buffer, buffer_size);
if ((err = rtp_header.encode(&stream)) != srs_success) {
srs_freepa(buffer);
return srs_error_wrap(err, "rtp header encode");
if (!buf->require(1)) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
}
stream.write_bytes(p, s);
payload_ptr = new SrsRtpSharedPacketPayload();
payload_ptr->payload = buffer;
payload_ptr->size = buffer_size;
payload = buf->head();
size = buf->left();
buf->skip(size);
this->payload = payload_ptr->payload;
this->size = payload_ptr->size;
return err;
}
SrsRtpSharedPacket* SrsRtpSharedPacket::copy()
{
SrsRtpSharedPacket* copy = new SrsRtpSharedPacket();
copy->payload_ptr = payload_ptr;
payload_ptr->shared_count++;
copy->rtp_header = rtp_header;
copy->payload = payload;
copy->size = size;
return copy;
}
srs_error_t SrsRtpSharedPacket::modify_rtp_header_marker(bool marker)
{
srs_error_t err = srs_success;
if (payload_ptr == NULL || payload_ptr->payload == NULL || payload_ptr->size < kRtpHeaderFixedSize) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "rtp payload incorrect");
}
rtp_header.set_marker(marker);
if (marker) {
payload_ptr->payload[1] |= kRtpMarker;
} else {
payload_ptr->payload[1] &= (~kRtpMarker);
}
return err;
}
srs_error_t SrsRtpSharedPacket::modify_rtp_header_ssrc(uint32_t ssrc)
{
srs_error_t err = srs_success;
if (payload_ptr == NULL || payload_ptr->payload == NULL || payload_ptr->size < kRtpHeaderFixedSize) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "rtp payload incorrect");
}
rtp_header.set_ssrc(ssrc);
SrsBuffer stream(payload_ptr->payload + 8, 4);
stream.write_4bytes(ssrc);
return err;
}
srs_error_t SrsRtpSharedPacket::modify_rtp_header_payload_type(uint8_t payload_type)
{
srs_error_t err = srs_success;
if (payload_ptr == NULL || payload_ptr->payload == NULL || payload_ptr->size < kRtpHeaderFixedSize) {
return srs_error_new(ERROR_RTC_RTP_MUXER, "rtp payload incorrect");
}
rtp_header.set_payload_type(payload_type);
payload_ptr->payload[1] = (payload_ptr->payload[1] & 0x80) | payload_type;
return err;
return srs_success;
}

View file

@ -21,8 +21,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_KERNEL_RTP_HPP
#define SRS_KERNEL_RTP_HPP
#ifndef SRS_KERNEL_RTC_RTP_HPP
#define SRS_KERNEL_RTC_RTP_HPP
#include <srs_core.hpp>
@ -31,12 +31,25 @@
#include <string>
class SrsRtpPacket2;
const int kRtpHeaderFixedSize = 12;
const uint8_t kRtpMarker = 0x80;
// 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;
// @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
class SrsBuffer;
class SrsRtpRawPayload;
class SrsRtpFUAPayload2;
@ -45,12 +58,13 @@ class SrsRtpHeader
{
private:
bool padding;
uint8_t padding_length;
bool extension;
uint8_t cc;
bool marker;
uint8_t payload_type;
uint16_t sequence;
int32_t timestamp;
uint32_t timestamp;
uint32_t ssrc;
uint32_t csrc[15];
uint16_t extension_length;
@ -60,34 +74,58 @@ public:
virtual ~SrsRtpHeader();
void reset();
public:
srs_error_t decode(SrsBuffer* stream);
srs_error_t encode(SrsBuffer* stream);
virtual srs_error_t decode(SrsBuffer* buf);
virtual srs_error_t encode(SrsBuffer* buf);
virtual int nb_bytes();
public:
size_t header_size();
void set_marker(bool v);
bool get_marker() const;
void set_payload_type(uint8_t v);
uint8_t get_payload_type() const;
void set_sequence(uint16_t v);
uint16_t get_sequence() const;
void set_timestamp(uint32_t v);
uint32_t get_timestamp() const;
void set_ssrc(uint32_t v);
uint32_t get_ssrc() const;
void set_padding(bool v);
void set_padding_length(uint8_t v);
uint8_t get_padding_length() const;
};
class ISrsRtpPacketDecodeHandler
{
public:
inline void set_marker(bool v) { marker = v; }
bool get_marker() const { return marker; }
inline void set_payload_type(uint8_t v) { payload_type = v; }
uint8_t get_payload_type() const { return payload_type; }
inline void set_sequence(uint16_t v) { sequence = v; }
uint16_t get_sequence() const { return sequence; }
inline void set_timestamp(int64_t v) { timestamp = (uint32_t)v; }
int64_t get_timestamp() const { return timestamp; }
inline void set_ssrc(uint32_t v) { ssrc = v; }
uint32_t get_ssrc() const { return ssrc; }
inline void set_padding(bool v) { padding = v; }
ISrsRtpPacketDecodeHandler();
virtual ~ISrsRtpPacketDecodeHandler();
public:
// We don't know the actual payload, so we depends on external handler.
virtual void on_before_decode_payload(SrsRtpPacket2* pkt, SrsBuffer* buf, ISrsCodec** ppayload) = 0;
};
class SrsRtpPacket2
{
// RTP packet fields.
public:
// TODO: FIXME: Rename to header.
SrsRtpHeader rtp_header;
ISrsEncoder* payload;
ISrsCodec* payload;
// TODO: FIXME: Merge into rtp_header.
int padding;
// Decoder helper.
public:
// The first byte as nalu type, for video decoder only.
SrsAvcNaluType nalu_type;
// The original bytes for decoder only, we will free it.
char* original_bytes;
// Fast cache for performance.
private:
// Cache frequently used payload for performance.
SrsRtpRawPayload* cache_raw;
SrsRtpFUAPayload2* cache_fua;
int cache_payload;
// The helper handler for decoder, use RAW payload if NULL.
ISrsRtpPacketDecodeHandler* decode_handler;
public:
SrsRtpPacket2();
virtual ~SrsRtpPacket2();
@ -102,14 +140,17 @@ public:
SrsRtpRawPayload* reuse_raw();
// Reuse the cached fua message as payload.
SrsRtpFUAPayload2* reuse_fua();
// Set the decode handler.
void set_decode_handler(ISrsRtpPacketDecodeHandler* h);
// interface ISrsEncoder
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
virtual srs_error_t decode(SrsBuffer* buf);
};
// Single payload data.
class SrsRtpRawPayload : public ISrsEncoder
class SrsRtpRawPayload : public ISrsCodec
{
public:
// The RAW payload, directly point to the shared memory.
@ -123,10 +164,11 @@ public:
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
virtual srs_error_t decode(SrsBuffer* buf);
};
// Multiple NALUs, automatically insert 001 between NALUs.
class SrsRtpRawNALUs : public ISrsEncoder
class SrsRtpRawNALUs : public ISrsCodec
{
private:
// We will manage the samples, but the sample itself point to the shared memory.
@ -146,10 +188,11 @@ public:
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
virtual srs_error_t decode(SrsBuffer* buf);
};
// STAP-A, for multiple NALUs.
class SrsRtpSTAPPayload : public ISrsEncoder
class SrsRtpSTAPPayload : public ISrsCodec
{
public:
// The NRI in NALU type.
@ -160,15 +203,19 @@ public:
public:
SrsRtpSTAPPayload();
virtual ~SrsRtpSTAPPayload();
public:
SrsSample* get_sps();
SrsSample* get_pps();
// interface ISrsEncoder
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
virtual srs_error_t decode(SrsBuffer* buf);
};
// FU-A, for one NALU with multiple fragments.
// With more than one payload.
class SrsRtpFUAPayload : public ISrsEncoder
class SrsRtpFUAPayload : public ISrsCodec
{
public:
// The NRI in NALU type.
@ -187,11 +234,12 @@ public:
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
virtual srs_error_t decode(SrsBuffer* buf);
};
// FU-A, for one NALU with multiple fragments.
// With only one payload.
class SrsRtpFUAPayload2 : public ISrsEncoder
class SrsRtpFUAPayload2 : public ISrsCodec
{
public:
// The NRI in NALU type.
@ -210,39 +258,7 @@ public:
public:
virtual int nb_bytes();
virtual srs_error_t encode(SrsBuffer* buf);
};
class SrsRtpSharedPacket
{
private:
class SrsRtpSharedPacketPayload
{
public:
// Rtp packet buffer, include rtp header and payload.
char* payload;
int size;
int shared_count;
public:
SrsRtpSharedPacketPayload();
virtual ~SrsRtpSharedPacketPayload();
};
private:
SrsRtpSharedPacketPayload* payload_ptr;
public:
SrsRtpHeader rtp_header;
char* payload;
int size;
public:
SrsRtpSharedPacket();
virtual ~SrsRtpSharedPacket();
public:
srs_error_t create(int64_t timestamp, uint16_t sequence, uint32_t ssrc, uint16_t payload_type, char* payload, int size);
SrsRtpSharedPacket* copy();
// Interface to modify rtp header
public:
srs_error_t modify_rtp_header_marker(bool marker);
srs_error_t modify_rtp_header_ssrc(uint32_t ssrc);
srs_error_t modify_rtp_header_payload_type(uint8_t payload_type);
virtual srs_error_t decode(SrsBuffer* buf);
};
#endif

View file

@ -124,7 +124,7 @@ srs_utime_t srs_get_system_startup_time()
}
// For utest to mock it.
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
_srs_gettimeofday_t _srs_gettimeofday = ::gettimeofday;
#endif

View file

@ -166,7 +166,7 @@ extern int srs_chunk_header_c3(int perfer_cid, uint32_t timestamp, char* cache,
// For utest to mock it.
#include <sys/time.h>
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
#define _srs_gettimeofday gettimeofday
#else
typedef int (*_srs_gettimeofday_t) (struct timeval* tv, struct timezone* tz);

View file

@ -63,8 +63,8 @@ int main(int argc, char** argv)
srs_assert(srs_is_little_endian());
// directly failed when compile limited.
#if defined(SRS_AUTO_GPERF_MP) || defined(SRS_AUTO_GPERF_MP) \
|| defined(SRS_AUTO_GPERF_MC) || defined(SRS_AUTO_GPERF_MP)
#if defined(SRS_GPERF_MP) || defined(SRS_GPERF_MP) \
|| defined(SRS_GPERF_MC) || defined(SRS_GPERF_MP)
srs_error("donot support gmc/gmp/gcp/gprof");
exit(-1);
#endif

View file

@ -30,14 +30,14 @@
#include <sstream>
using namespace std;
#ifdef SRS_AUTO_GPERF_MP
#ifdef SRS_GPERF_MP
#include <gperftools/heap-profiler.h>
#endif
#ifdef SRS_AUTO_GPERF_CP
#ifdef SRS_GPERF_CP
#include <gperftools/profiler.h>
#endif
#ifdef SRS_AUTO_GPERF
#ifdef SRS_GPERF
#include <gperftools/malloc_extension.h>
#endif
@ -54,11 +54,12 @@ using namespace std;
#include <srs_core_autofree.hpp>
#include <srs_kernel_file.hpp>
#include <srs_app_hybrid.hpp>
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtc_server.hpp>
#endif
#ifdef SRS_AUTO_SRT
#ifdef SRS_SRT
#include <srt_server.hpp>
#endif
@ -86,17 +87,20 @@ srs_error_t do_main(int argc, char** argv)
// TODO: support both little and big endian.
srs_assert(srs_is_little_endian());
// For RTC to generating random ICE username.
::srandom((unsigned long)(srs_update_system_time() | (::getpid()<<13)));
// for gperf gmp or gcp,
// should never enable it when not enabled for performance issue.
#ifdef SRS_AUTO_GPERF_MP
#ifdef SRS_GPERF_MP
HeapProfilerStart("gperf.srs.gmp");
#endif
#ifdef SRS_AUTO_GPERF_CP
#ifdef SRS_GPERF_CP
ProfilerStart("gperf.srs.gcp");
#endif
// directly compile error when these two macro defines.
#if defined(SRS_AUTO_GPERF_MC) && defined(SRS_AUTO_GPERF_MP)
#if defined(SRS_GPERF_MC) && defined(SRS_GPERF_MP)
#error ("option --with-gmc confict with --with-gmp, "
"@see: http://google-perftools.googlecode.com/svn/trunk/doc/heap_checker.html\n"
"Note that since the heap-checker uses the heap-profiling framework internally, "
@ -104,7 +108,7 @@ srs_error_t do_main(int argc, char** argv)
#endif
// never use gmp to check memory leak.
#ifdef SRS_AUTO_GPERF_MP
#ifdef SRS_GPERF_MP
#warning "gmp is not used for memory leak, please use gmc instead."
#endif
@ -132,12 +136,12 @@ srs_error_t do_main(int argc, char** argv)
// config already applied to log.
srs_trace("%s, %s", RTMP_SIG_SRS_SERVER, RTMP_SIG_SRS_LICENSE);
srs_trace("authors: %s", RTMP_SIG_SRS_AUTHORS);
srs_trace("contributors: %s", SRS_AUTO_CONSTRIBUTORS);
srs_trace("contributors: %s", SRS_CONSTRIBUTORS);
srs_trace("cwd=%s, work_dir=%s, build: %s, configure: %s, uname: %s, osx: %d",
_srs_config->cwd().c_str(), cwd.c_str(), SRS_AUTO_BUILD_DATE, SRS_AUTO_USER_CONFIGURE, SRS_AUTO_UNAME, SRS_AUTO_OSX_BOOL);
srs_trace("configure detail: " SRS_AUTO_CONFIGURE);
#ifdef SRS_AUTO_EMBEDED_TOOL_CHAIN
srs_trace("crossbuild tool chain: " SRS_AUTO_EMBEDED_TOOL_CHAIN);
_srs_config->cwd().c_str(), cwd.c_str(), SRS_BUILD_DATE, SRS_USER_CONFIGURE, SRS_UNAME, SRS_OSX_BOOL);
srs_trace("configure detail: " SRS_CONFIGURE);
#ifdef SRS_EMBEDED_TOOL_CHAIN
srs_trace("crossbuild tool chain: " SRS_EMBEDED_TOOL_CHAIN);
#endif
// for memory check or detect.
@ -157,7 +161,7 @@ srs_error_t do_main(int argc, char** argv)
ss << "glic mem-check env MALLOC_CHECK_ " << mcov << "=>" << mcnv << ", LIBC_FATAL_STDERR_ " << lfsov << "=>" << lfsnv << ".";
#endif
#ifdef SRS_AUTO_GPERF_MC
#ifdef SRS_GPERF_MC
string hcov = srs_getenv("HEAPCHECK");
if (hcov.empty()) {
string cpath = _srs_config->config();
@ -167,7 +171,7 @@ srs_error_t do_main(int argc, char** argv)
}
#endif
#ifdef SRS_AUTO_GPERF_MD
#ifdef SRS_GPERF_MD
char* TCMALLOC_PAGE_FENCE = getenv("TCMALLOC_PAGE_FENCE");
if (!TCMALLOC_PAGE_FENCE || strcmp(TCMALLOC_PAGE_FENCE, "1")) {
srs_warn("gmd enabled without env TCMALLOC_PAGE_FENCE=1");
@ -190,7 +194,7 @@ srs_error_t do_main(int argc, char** argv)
// features
show_macro_features();
#ifdef SRS_AUTO_GPERF
#ifdef SRS_GPERF
// For tcmalloc, use slower release rate.
if (true) {
double trr = _srs_config->tcmalloc_release_rate();
@ -233,8 +237,8 @@ void show_macro_features()
ss << ", rch:" << srs_bool2switch(true);
ss << ", dash:" << "on";
ss << ", hls:" << srs_bool2switch(true);
ss << ", hds:" << srs_bool2switch(SRS_AUTO_HDS_BOOL);
ss << ", srt:" << srs_bool2switch(SRS_AUTO_SRT_BOOL);
ss << ", hds:" << srs_bool2switch(SRS_HDS_BOOL);
ss << ", srt:" << srs_bool2switch(SRS_SRT_BOOL);
// hc(http callback)
ss << ", hc:" << srs_bool2switch(true);
// ha(http api)
@ -272,7 +276,7 @@ void show_macro_features()
#if defined(__aarch64__)
ss << " aarch64";
#endif
#if defined(SRS_AUTO_CROSSBUILD)
#if defined(SRS_CROSSBUILD)
ss << "(crossbuild)";
#endif
@ -345,7 +349,7 @@ void show_macro_features()
srs_trace("system default latency(ms): mw(0-%d) + mr(0-%d) + play-queue(0-%d)",
srsu2msi(SRS_PERF_MW_SLEEP), possible_mr_latency, srsu2msi(SRS_PERF_PLAY_QUEUE));
#ifdef SRS_AUTO_MEM_WATCH
#ifdef SRS_MEM_WATCH
#warning "srs memory watcher will hurts performance. user should kill by SIGTERM or init.d script."
srs_warn("srs memory watcher will hurts performance. user should kill by SIGTERM or init.d script.");
#endif
@ -461,11 +465,11 @@ srs_error_t run_hybrid_server()
// Create servers and register them.
_srs_hybrid->register_server(new SrsServerAdapter());
#ifdef SRS_AUTO_SRT
#ifdef SRS_SRT
_srs_hybrid->register_server(new SrtServerAdapter());
#endif
#ifdef SRS_AUTO_RTC
#ifdef SRS_RTC
_srs_hybrid->register_server(new RtcServerAdapter());
#endif

View file

@ -21,7 +21,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_stun_stack.hpp>
#include <srs_rtc_stun_stack.hpp>
using namespace std;
@ -98,6 +98,96 @@ SrsStunPacket::~SrsStunPacket()
{
}
bool SrsStunPacket::is_binding_request() const
{
return message_type == BindingRequest;
}
bool SrsStunPacket::is_binding_response() const
{
return message_type == BindingResponse;
}
uint16_t SrsStunPacket::get_message_type() const
{
return message_type;
}
std::string SrsStunPacket::get_username() const
{
return username;
}
std::string SrsStunPacket::get_local_ufrag() const
{
return local_ufrag;
}
std::string SrsStunPacket::get_remote_ufrag() const
{
return remote_ufrag;
}
std::string SrsStunPacket::get_transcation_id() const
{
return transcation_id;
}
uint32_t SrsStunPacket::get_mapped_address() const
{
return mapped_address;
}
uint16_t SrsStunPacket::get_mapped_port() const
{
return mapped_port;
}
bool SrsStunPacket::get_ice_controlled() const
{
return ice_controlled;
}
bool SrsStunPacket::get_ice_controlling() const
{
return ice_controlling;
}
bool SrsStunPacket::get_use_candidate() const
{
return use_candidate;
}
void SrsStunPacket::set_message_type(const uint16_t& m)
{
message_type = m;
}
void SrsStunPacket::set_local_ufrag(const std::string& u)
{
local_ufrag = u;
}
void SrsStunPacket::set_remote_ufrag(const std::string& u)
{
remote_ufrag = u;
}
void SrsStunPacket::set_transcation_id(const std::string& t)
{
transcation_id = t;
}
void SrsStunPacket::set_mapped_address(const uint32_t& addr)
{
mapped_address = addr;
}
void SrsStunPacket::set_mapped_port(const uint32_t& port)
{
mapped_port = port;
}
srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf)
{
srs_error_t err = srs_success;

View file

@ -21,8 +21,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_PROTOCOL_STUN_HPP
#define SRS_PROTOCOL_STUN_HPP
#ifndef SRS_PROTOCOL_RTC_STUN_HPP
#define SRS_PROTOCOL_RTC_STUN_HPP
#include <srs_core.hpp>
@ -92,28 +92,25 @@ private:
public:
SrsStunPacket();
virtual ~SrsStunPacket();
bool is_binding_request() const { return message_type == BindingRequest; }
bool is_binding_response() const { return message_type == BindingResponse; }
uint16_t get_message_type() const { return message_type; }
std::string get_username() const { return username; }
std::string get_local_ufrag() const { return local_ufrag; }
std::string get_remote_ufrag() const { return remote_ufrag; }
std::string get_transcation_id() const { return transcation_id; }
uint32_t get_mapped_address() const { return mapped_address; }
uint16_t get_mapped_port() const { return mapped_port; }
bool get_ice_controlled() const { return ice_controlled; }
bool get_ice_controlling() const { return ice_controlling; }
bool get_use_candidate() const { return use_candidate; }
void set_message_type(const uint16_t& m) { message_type = m; }
void set_local_ufrag(const std::string& u) { local_ufrag = u; }
void set_remote_ufrag(const std::string& u) { remote_ufrag = u; }
void set_transcation_id(const std::string& t) { transcation_id = t; }
void set_mapped_address(const uint32_t& addr) { mapped_address = addr; }
void set_mapped_port(const uint32_t& port) { mapped_port = port; }
public:
bool is_binding_request() const;
bool is_binding_response() const;
uint16_t get_message_type() const;
std::string get_username() const;
std::string get_local_ufrag() const;
std::string get_remote_ufrag() const;
std::string get_transcation_id() const;
uint32_t get_mapped_address() const;
uint16_t get_mapped_port() const;
bool get_ice_controlled() const;
bool get_ice_controlling() const;
bool get_use_candidate() const;
void set_message_type(const uint16_t& m);
void set_local_ufrag(const std::string& u);
void set_remote_ufrag(const std::string& u);
void set_transcation_id(const std::string& t);
void set_mapped_address(const uint32_t& addr);
void set_mapped_port(const uint32_t& port);
srs_error_t decode(const char* buf, const int nb_buf);
srs_error_t encode(const std::string& pwd, SrsBuffer* stream);
private:

View file

@ -635,9 +635,9 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
std::vector<std::string> vec_device_status = srs_string_split(body_map["Response@DeviceList@Item@Status"], ",");
//map key:devicd_id value:status
for(int i=0 ; i<vec_device_id.size(); i++){
for(int i=0 ; i< (int)vec_device_id.size(); i++){
std::string status = "";
if (vec_device_id.size() > i) {
if ((int)vec_device_id.size() > i) {
status = vec_device_status.at(i);
}
@ -653,7 +653,7 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
if (cmdtype == "Keepalive"){
//TODO: ????
std::vector<std::string> vec_device_id = srs_string_split(body_map["Notify@Info@DeviceID"], ",");
for(int i=0; i<vec_device_id.size(); i++){
for(int i=0; i< (int)vec_device_id.size(); i++){
//req->device_list_map[vec_device_id.at(i)] = "OFF";
}
}else{

View file

@ -115,7 +115,7 @@ srs_error_t srs_fd_reuseport(int fd)
#if defined(SO_REUSEPORT)
int v = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(int)) == -1) {
#ifdef SRS_AUTO_CROSSBUILD
#ifdef SRS_CROSSBUILD
srs_warn("SO_REUSEPORT disabled for crossbuild");
return srs_success;
#else
@ -412,53 +412,9 @@ int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime
return st_sendmsg((st_netfd_t)stfd, msg, flags, (st_utime_t)timeout);
}
int srs_sendmmsg(srs_netfd_t stfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, srs_utime_t timeout)
int srs_sendmmsg(srs_netfd_t stfd, struct srs_mmsghdr *msgvec, unsigned int vlen, int flags, srs_utime_t timeout)
{
#if !defined(SRS_AUTO_HAS_SENDMMSG) || !defined(SRS_AUTO_SENDMMSG)
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
for (int i = 0; i < (int)vlen; ++i) {
struct mmsghdr* p = msgvec + i;
int n = srs_sendmsg(stfd, &p->msg_hdr, flags, timeout);
if (n < 0) {
// An error is returned only if no datagrams could be sent.
if (i == 0) {
return n;
}
return i + 1;
}
p->msg_len = n;
}
// Returns the number of messages sent from msgvec; if this is less than vlen, the caller can retry with a
// further sendmmsg() call to send the remaining messages.
return vlen;
#else
if (vlen == 1) {
#if 1
int r0 = srs_sendmsg(stfd, &msgvec->msg_hdr, flags, timeout);
if (r0 < 0) {
return r0;
}
msgvec->msg_len = r0;
#else
msgvec->msg_len = 0;
int tolen = (int)msgvec->msg_hdr.msg_namelen;
const struct sockaddr* to = (const struct sockaddr*)msgvec->msg_hdr.msg_name;
for (int i = 0; i < (int)msgvec->msg_hdr.msg_iovlen; i++) {
iovec* iov = msgvec->msg_hdr.msg_iov + i;
int r0 = srs_sendto(stfd, (void*)iov->iov_base, (int)iov->iov_len, to, tolen, timeout);
if (r0 < 0) {
return r0;
}
msgvec->msg_len += r0;
}
#endif
return 1;
}
return st_sendmmsg((st_netfd_t)stfd, msgvec, vlen, flags, (st_utime_t)timeout);
#endif
return st_sendmmsg((st_netfd_t)stfd, (struct st_mmsghdr*)msgvec, vlen, flags, (st_utime_t)timeout);
}
srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout)

View file

@ -92,15 +92,13 @@ extern int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockadd
extern int srs_recvmsg(srs_netfd_t stfd, struct msghdr *msg, int flags, srs_utime_t timeout);
extern int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime_t timeout);
#if !defined(SRS_AUTO_HAS_SENDMMSG)
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
#include <sys/socket.h>
struct mmsghdr {
struct msghdr msg_hdr; /* Message header */
unsigned int msg_len; /* Number of bytes transmitted */
};
#endif
extern int srs_sendmmsg(srs_netfd_t stfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, srs_utime_t timeout);
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
#include <sys/socket.h>
struct srs_mmsghdr {
struct msghdr msg_hdr; /* Message header */
unsigned int msg_len; /* Number of bytes transmitted */
};
extern int srs_sendmmsg(srs_netfd_t stfd, struct srs_mmsghdr *msgvec, unsigned int vlen, int flags, srs_utime_t timeout);
extern srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout);
@ -110,7 +108,7 @@ extern bool srs_is_never_timeout(srs_utime_t tm);
// The mutex locker.
#define SrsLocker(instance) \
impl__SrsLocker _srs_auto_free_##instance(&instance)
impl__SrsLocker _SRS_free_##instance(&instance)
class impl__SrsLocker
{

View file

@ -144,9 +144,9 @@ bool srs_net_device_is_internet(const sockaddr* addr)
return true;
}
vector<string> _srs_system_ips;
vector<SrsIPAddress*> _srs_system_ips;
void discover_network_iface(ifaddrs* cur, vector<string>& ips, stringstream& ss0, stringstream& ss1, bool ipv6)
void discover_network_iface(ifaddrs* cur, vector<SrsIPAddress*>& ips, stringstream& ss0, stringstream& ss1, bool ipv6, bool loopback)
{
char saddr[64];
char* h = (char*)saddr;
@ -160,10 +160,17 @@ void discover_network_iface(ifaddrs* cur, vector<string>& ips, stringstream& ss0
std::string ip(saddr, strlen(saddr));
ss0 << ", iface[" << (int)ips.size() << "] " << cur->ifa_name << " " << (ipv6? "ipv6":"ipv4")
<< " 0x" << std::hex << cur->ifa_flags << std::dec << " " << ip;
ips.push_back(ip);
SrsIPAddress* ip_address = new SrsIPAddress();
ip_address->ip = ip;
ip_address->is_ipv4 = !ipv6;
ip_address->is_loopback = loopback;
ip_address->ifname = cur->ifa_name;
ip_address->is_internet = srs_net_device_is_internet(cur->ifa_addr);
ips.push_back(ip_address);
// set the device internet status.
if (!srs_net_device_is_internet(cur->ifa_addr)) {
if (!ip_address->is_internet) {
ss1 << ", intranet ";
_srs_device_ifs[cur->ifa_name] = false;
} else {
@ -175,10 +182,16 @@ void discover_network_iface(ifaddrs* cur, vector<string>& ips, stringstream& ss0
void retrieve_local_ips()
{
vector<string>& ips = _srs_system_ips;
vector<SrsIPAddress*>& ips = _srs_system_ips;
// Release previous IPs.
for (int i = 0; i < (int)ips.size(); i++) {
SrsIPAddress* ip = ips[i];
srs_freep(ip);
}
ips.clear();
// Get the addresses.
ifaddrs* ifap;
if (getifaddrs(&ifap) == -1) {
srs_warn("retrieve local ips, getifaddrs failed.");
@ -207,8 +220,9 @@ void retrieve_local_ips()
bool ready = (cur->ifa_flags & IFF_UP) && (cur->ifa_flags & IFF_RUNNING);
// Ignore IFF_PROMISC(Interface is in promiscuous mode), which may be set by Wireshark.
bool ignored = (!cur->ifa_addr) || (cur->ifa_flags & IFF_LOOPBACK) || (cur->ifa_flags & IFF_POINTOPOINT);
bool loopback = (cur->ifa_flags & IFF_LOOPBACK);
if (ipv4 && ready && !ignored) {
discover_network_iface(cur, ips, ss0, ss1, false);
discover_network_iface(cur, ips, ss0, ss1, false, loopback);
}
}
@ -227,8 +241,9 @@ void retrieve_local_ips()
bool ipv6 = (cur->ifa_addr->sa_family == AF_INET6);
bool ready = (cur->ifa_flags & IFF_UP) && (cur->ifa_flags & IFF_RUNNING);
bool ignored = (!cur->ifa_addr) || (cur->ifa_flags & IFF_POINTOPOINT) || (cur->ifa_flags & IFF_PROMISC) || (cur->ifa_flags & IFF_LOOPBACK);
bool loopback = (cur->ifa_flags & IFF_LOOPBACK);
if (ipv6 && ready && !ignored) {
discover_network_iface(cur, ips, ss0, ss1, true);
discover_network_iface(cur, ips, ss0, ss1, true, loopback);
}
}
@ -248,8 +263,9 @@ void retrieve_local_ips()
bool ipv4 = (cur->ifa_addr->sa_family == AF_INET);
bool ready = (cur->ifa_flags & IFF_UP) && (cur->ifa_flags & IFF_RUNNING);
bool ignored = (!cur->ifa_addr) || (cur->ifa_flags & IFF_POINTOPOINT) || (cur->ifa_flags & IFF_PROMISC);
bool loopback = (cur->ifa_flags & IFF_LOOPBACK);
if (ipv4 && ready && !ignored) {
discover_network_iface(cur, ips, ss0, ss1, false);
discover_network_iface(cur, ips, ss0, ss1, false, loopback);
}
}
}
@ -260,7 +276,7 @@ void retrieve_local_ips()
freeifaddrs(ifap);
}
vector<string>& srs_get_local_ips()
vector<SrsIPAddress*>& srs_get_local_ips()
{
if (_srs_system_ips.empty()) {
retrieve_local_ips();
@ -277,72 +293,39 @@ string srs_get_public_internet_address()
return _public_internet_address;
}
std::vector<std::string>& ips = srs_get_local_ips();
std::vector<SrsIPAddress*>& ips = srs_get_local_ips();
// find the best match public address.
for (int i = 0; i < (int)ips.size(); i++) {
std::string ip = ips[i];
// TODO: FIXME: Support ipv6.
if (ip.find(".") == string::npos) {
SrsIPAddress* ip = ips[i];
if (!ip->is_internet) {
continue;
}
in_addr_t addr = inet_addr(ip.c_str());
uint32_t addr_h = ntohl(addr);
// lo, 127.0.0.0-127.0.0.1
if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) {
srs_trace("ignore private address: %s", ip.c_str());
continue;
}
// Class A 10.0.0.0-10.255.255.255
if (addr_h >= 0x0a000000 && addr_h <= 0x0affffff) {
srs_trace("ignore private address: %s", ip.c_str());
continue;
}
// Class B 172.16.0.0-172.31.255.255
if (addr_h >= 0xac100000 && addr_h <= 0xac1fffff) {
srs_trace("ignore private address: %s", ip.c_str());
continue;
}
// Class C 192.168.0.0-192.168.255.255
if (addr_h >= 0xc0a80000 && addr_h <= 0xc0a8ffff) {
srs_trace("ignore private address: %s", ip.c_str());
continue;
}
srs_warn("use public address as ip: %s", ip.c_str());
_public_internet_address = ip;
return ip;
srs_warn("use public address as ip: %s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str());
_public_internet_address = ip->ip;
return ip->ip;
}
// no public address, use private address.
for (int i = 0; i < (int)ips.size(); i++) {
std::string ip = ips[i];
// TODO: FIXME: Support ipv6.
if (ip.find(".") == string::npos) {
SrsIPAddress* ip = ips[i];
if (ip->is_loopback) {
continue;
}
in_addr_t addr = inet_addr(ip.c_str());
uint32_t addr_h = ntohl(addr);
// lo, 127.0.0.0-127.0.0.1
if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) {
srs_trace("ignore private address: %s", ip.c_str());
continue;
}
srs_warn("use private address as ip: %s", ip.c_str());
_public_internet_address = ip;
return ip;
srs_warn("use private address as ip: %s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str());
_public_internet_address = ip->ip;
return ip->ip;
}
// Finally, use first whatever kind of address.
if (!ips.empty() && _public_internet_address.empty()) {
string ip = ips.at(0);
srs_warn("use first address as ip: %s", ip.c_str());
SrsIPAddress* ip = ips[0];
_public_internet_address = ip;
return ip;
srs_warn("use first address as ip: %s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str());
_public_internet_address = ip->ip;
return ip->ip;
}
return "";

View file

@ -51,7 +51,20 @@ extern bool srs_string_is_rtmp(std::string url);
extern bool srs_is_digit_number(std::string str);
// Get local ip, fill to @param ips
extern std::vector<std::string>& srs_get_local_ips();
struct SrsIPAddress
{
// The network interface name, such as eth0, en0, eth1.
std::string ifname;
// The IP v4 or v6 address.
std::string ip;
// Whether the ip is IPv4 address.
bool is_ipv4;
// Whether the ip is internet public IP address.
bool is_internet;
// Whether the ip is loopback, such as 127.0.0.1
bool is_loopback;
};
extern std::vector<SrsIPAddress*>& srs_get_local_ips();
// Get local public ip, empty string if no public internet address found.
extern std::string srs_get_public_internet_address();

View file

@ -1323,7 +1323,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesString)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::str();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -1354,7 +1354,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesString)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::str();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
@ -1452,7 +1452,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesBoolean)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::boolean();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -1467,7 +1467,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesBoolean)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::boolean();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
@ -1549,7 +1549,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesNumber)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::number();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -1564,7 +1564,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesNumber)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::number();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
@ -1673,14 +1673,14 @@ VOID TEST(ProtocolAMF0Test, InterfacesNull)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::null();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::null();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
@ -1739,14 +1739,14 @@ VOID TEST(ProtocolAMF0Test, InterfacesUndefined)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::undefined();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* o = SrsAmf0Any::undefined();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
@ -1811,14 +1811,14 @@ VOID TEST(ProtocolAMF0Test, InterfacesObject)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Object* o = SrsAmf0Any::object();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Object* o = SrsAmf0Any::object();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -2014,14 +2014,14 @@ VOID TEST(ProtocolAMF0Test, InterfacesObjectEOF)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0ObjectEOF* o = new SrsAmf0ObjectEOF();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0ObjectEOF* o = new SrsAmf0ObjectEOF();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -2106,14 +2106,14 @@ VOID TEST(ProtocolAMF0Test, InterfacesEcmaArray)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0EcmaArray* o = SrsAmf0Any::ecma_array();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0EcmaArray* o = SrsAmf0Any::ecma_array();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -2233,14 +2233,14 @@ VOID TEST(ProtocolAMF0Test, InterfacesStrictArray)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0StrictArray* o = SrsAmf0Any::strict_array();
HELPER_EXPECT_FAILED(o->read(&b));
srs_freep(o);
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0StrictArray* o = SrsAmf0Any::strict_array();
HELPER_EXPECT_FAILED(o->write(&b));
srs_freep(o);
@ -2346,7 +2346,7 @@ VOID TEST(ProtocolAMF0Test, InterfacesError)
srs_error_t err;
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
HELPER_EXPECT_FAILED(SrsAmf0Any::discovery(&b, NULL));
}
@ -2490,7 +2490,7 @@ VOID TEST(ProtocolAMF0Test, Amf0Object2)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsAmf0Any* eof = SrsAmf0Any::object_eof();
HELPER_EXPECT_FAILED(srs_amf0_write_object_eof(&b, (SrsAmf0ObjectEOF*)eof));
srs_freep(eof);

View file

@ -41,25 +41,25 @@ VOID TEST(CoreAutoFreeTest, Free)
VOID TEST(CoreMacroseTest, Check)
{
#ifndef SRS_AUTO_BUILD_TS
#ifndef SRS_BUILD_TS
EXPECT_TRUE(false);
#endif
#ifndef SRS_AUTO_BUILD_DATE
#ifndef SRS_BUILD_DATE
EXPECT_TRUE(false);
#endif
#ifndef SRS_AUTO_UNAME
#ifndef SRS_UNAME
EXPECT_TRUE(false);
#endif
#ifndef SRS_AUTO_USER_CONFIGURE
#ifndef SRS_USER_CONFIGURE
EXPECT_TRUE(false);
#endif
#ifndef SRS_AUTO_CONFIGURE
#ifndef SRS_CONFIGURE
EXPECT_TRUE(false);
#endif
#ifndef SRS_AUTO_PREFIX
#ifndef SRS_PREFIX
EXPECT_TRUE(false);
#endif
#ifndef SRS_AUTO_CONSTRIBUTORS
#ifndef SRS_CONSTRIBUTORS
EXPECT_TRUE(false);
#endif
}

View file

@ -2596,7 +2596,7 @@ VOID TEST(KernelUtility, AnnexbUtils)
if (true) {
EXPECT_TRUE(!srs_avc_startswith_annexb(NULL, NULL));
SrsBuffer buf;
SrsBuffer buf(NULL, 0);
EXPECT_TRUE(!srs_avc_startswith_annexb(&buf, NULL));
}
@ -2654,7 +2654,7 @@ VOID TEST(KernelUtility, AdtsUtils)
if (true) {
EXPECT_TRUE(!srs_aac_startswith_adts(NULL));
SrsBuffer buf;
SrsBuffer buf(NULL, 0);
EXPECT_TRUE(!srs_aac_startswith_adts(&buf));
}
@ -3843,7 +3843,7 @@ VOID TEST(KernelFileWriterTest, WriteSpecialCase)
off_t seeked = 0;
HELPER_EXPECT_SUCCESS(f.lseek(0, SEEK_CUR, &seeked));
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
EXPECT_EQ(10, seeked);
#else
EXPECT_EQ(0, seeked);
@ -4212,7 +4212,7 @@ VOID TEST(KernelUtilityTest, CoverBitsBufferAll)
}
}
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
extern _srs_gettimeofday_t _srs_gettimeofday;
int mock_gettimeofday(struct timeval* /*tp*/, struct timezone* /*tzp*/) {
return -1;
@ -4506,7 +4506,7 @@ VOID TEST(KernelTSTest, CoverContextUtility)
SrsTsMessage m(&c, &p);
m.PES_packet_length = 8;
SrsBuffer b;
SrsBuffer b(NULL, 0);
int nb_bytes = 0;
HELPER_EXPECT_SUCCESS(m.dump(&b, &nb_bytes));
@ -4625,7 +4625,7 @@ VOID TEST(KernelTSTest, CoverContextEncode)
MockTsHandler h;
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
HELPER_EXPECT_SUCCESS(ctx.decode(&b, &h));
EXPECT_TRUE(NULL == h.msg);
}

View file

@ -220,7 +220,7 @@ VOID TEST(KernelMp4Test, DiscoveryBox)
SrsMp4Box* pbox;
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
HELPER_ASSERT_FAILED(SrsMp4Box::discovery(&b, &pbox));
}
@ -419,7 +419,7 @@ VOID TEST(KernelMp4Test, UUIDBoxDecode)
}
if (true) {
SrsBuffer b;
SrsBuffer b(NULL, 0);
SrsMp4Box box;
HELPER_ASSERT_FAILED(box.decode(&b));
}

View file

@ -92,7 +92,7 @@ VOID TEST(ProtocolRTMPTest, PacketEncode)
MockPacket pkt;
pkt.size = 1024;
SrsBuffer b;
SrsBuffer b(NULL, 0);
HELPER_EXPECT_FAILED(pkt.decode(&b));
}

View file

@ -124,7 +124,7 @@ VOID TEST(TCPServerTest, PingPong)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -146,7 +146,7 @@ VOID TEST(TCPServerTest, PingPong)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -170,7 +170,7 @@ VOID TEST(TCPServerTest, PingPong)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -205,7 +205,7 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -227,7 +227,7 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -249,7 +249,7 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -382,7 +382,7 @@ VOID TEST(TCPServerTest, StringIsHex)
char* str = (char*)"!1234567890";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
EXPECT_EQ(0, errno);
#endif
EXPECT_EQ(str, parsed);
@ -400,7 +400,7 @@ VOID TEST(TCPServerTest, StringIsHex)
char* str = (char*)"";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
#ifndef SRS_AUTO_OSX
#ifndef SRS_OSX
EXPECT_EQ(0, errno);
#endif
EXPECT_EQ(str, parsed);
@ -429,7 +429,7 @@ VOID TEST(TCPServerTest, WritevIOVC)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
@ -459,7 +459,7 @@ VOID TEST(TCPServerTest, WritevIOVC)
SrsStSocket skt;
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
#ifdef SRS_AUTO_OSX
#ifdef SRS_OSX
ASSERT_TRUE(h.fd != NULL);
#endif
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));