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:
commit
c768a8ccd9
86 changed files with 5945 additions and 2276 deletions
|
@ -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
|
||||
|
|
12
trunk/3rdparty/readme.txt
vendored
12
trunk/3rdparty/readme.txt
vendored
|
@ -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
|
||||
|
|
4
trunk/3rdparty/st-srs/Makefile
vendored
4
trunk/3rdparty/st-srs/Makefile
vendored
|
@ -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)
|
||||
|
|
29
trunk/3rdparty/st-srs/io.c
vendored
29
trunk/3rdparty/st-srs/io.c
vendored
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
|
10
trunk/3rdparty/st-srs/public.h
vendored
10
trunk/3rdparty/st-srs/public.h
vendored
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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..
|
||||
--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,24 +613,10 @@ 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"
|
||||
if [[ $SRS_OSX == YES && $SRS_SENDMMSG == YES ]]; then
|
||||
echo "Disable sendmmsg for OSX"
|
||||
SRS_SENDMMSG=NO
|
||||
fi
|
||||
fi
|
||||
}
|
||||
apply_user_detail_options
|
||||
|
||||
|
@ -593,33 +625,35 @@ 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_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
|
||||
|
|
|
@ -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
9
trunk/configure
vendored
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 © 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;
|
||||
});
|
||||
};
|
||||
|
|
169
trunk/research/players/rtc_publisher.html
Normal file
169
trunk/research/players/rtc_publisher.html
Normal 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 © 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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>-->
|
||||
|
|
|
@ -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>-->
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_FFMPEG_STUB
|
||||
#ifdef SRS_FFMPEG_STUB
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <srs_app_hds.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_HDS
|
||||
#ifdef SRS_HDS
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_HDS
|
||||
#ifdef SRS_HDS
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
// 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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
class SrsFormat;
|
||||
class SrsSample;
|
||||
class SrsSharedPtrMessage;
|
||||
class SrsRtpSharedPacket;
|
||||
class SrsRequest;
|
||||
class SrsOriginHub;
|
||||
class SrsAudioRecode;
|
||||
|
|
|
@ -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;
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
675
trunk/src/app/srs_app_rtc_queue.cpp
Normal file
675
trunk/src/app/srs_app_rtc_queue.cpp
Normal 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;
|
||||
}
|
||||
|
318
trunk/src/app/srs_app_rtc_queue.hpp
Normal file
318
trunk/src/app/srs_app_rtc_queue.hpp
Normal 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
|
|
@ -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,6 +33,7 @@ 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) \
|
||||
|
@ -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,22 +136,24 @@ 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()) {
|
||||
os << "a=ice-ufrag:" << ice_ufrag_ << kCRLF;
|
||||
}
|
||||
|
||||
if (!ice_pwd_.empty()) {
|
||||
os << "a=ice-pwd:" << ice_pwd_ << kCRLF;
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
os << "a=fingerprint:" << fingerprint_algo_ << " " << fingerprint_ << kCRLF;
|
||||
}
|
||||
|
||||
if (!setup_.empty()) {
|
||||
os << "a=setup:" << setup_ << kCRLF;
|
||||
}
|
||||
|
@ -179,6 +183,7 @@ 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");
|
||||
}
|
||||
|
@ -225,7 +230,10 @@ srs_error_t SrsMediaPayloadType::encode(std::ostringstream& os)
|
|||
}
|
||||
|
||||
if (!format_specific_param_.empty()) {
|
||||
os << "a=fmtp:" << payload_type_ << " " << format_specific_param_ << kCRLF;
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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,7 +659,7 @@ 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());
|
||||
}
|
|
@ -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>
|
791
trunk/src/app/srs_app_rtc_server.cpp
Normal file
791
trunk/src/app/srs_app_rtc_server.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
|
143
trunk/src/app/srs_app_rtc_server.hpp
Normal file
143
trunk/src/app/srs_app_rtc_server.hpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <srs_core_mem_watch.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_MEM_WATCH
|
||||
#ifdef SRS_MEM_WATCH
|
||||
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_MEM_WATCH
|
||||
#ifdef SRS_MEM_WATCH
|
||||
|
||||
#warning "MemoryWatch is deprecated."
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2105,7 +2105,6 @@ class SrsMp4M2tsSegmentEncoder
|
|||
{
|
||||
private:
|
||||
ISrsWriter* writer;
|
||||
SrsBuffer* buffer;
|
||||
uint32_t sequence_number;
|
||||
srs_utime_t decode_basetime;
|
||||
uint32_t track_id;
|
||||
|
|
|
@ -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;
|
||||
|
||||
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,14 +468,12 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SrsRtpRawNALUs::push_back(SrsSample* sample)
|
||||
{
|
||||
|
@ -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;
|
||||
if (!buf->require(2)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2);
|
||||
}
|
||||
|
||||
SrsRtpSharedPacket::SrsRtpSharedPacketPayload::~SrsRtpSharedPacketPayload()
|
||||
{
|
||||
srs_freepa(payload);
|
||||
// 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);
|
||||
}
|
||||
|
||||
SrsRtpSharedPacket::SrsRtpSharedPacket()
|
||||
{
|
||||
payload_ptr = NULL;
|
||||
payload = buf->head();
|
||||
size = buf->left();
|
||||
buf->skip(size);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
srs_assert(!payload_ptr);
|
||||
|
||||
rtp_header.set_timestamp(timestamp);
|
||||
rtp_header.set_sequence(sequence);
|
||||
rtp_header.set_ssrc(ssrc);
|
||||
rtp_header.set_payload_type(payload_type);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
stream.write_bytes(p, s);
|
||||
payload_ptr = new SrsRtpSharedPacketPayload();
|
||||
payload_ptr->payload = buffer;
|
||||
payload_ptr->size = buffer_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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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:
|
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 srs_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);
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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 "";
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue