diff --git a/README.md b/README.md
index a3c1058101..f867be0587 100755
--- a/README.md
+++ b/README.md
@@ -177,6 +177,8 @@ The ports used by SRS:
## V5 changes
+* v5.0, 2021-04-07, Threads: Support multiple hybrid threads, [#2188](https://github.com/ossrs/srs/issues/2188). 5.0.3
+* v5.0, 2021-03-31, Threads: Support multiple threads with locks, [#2188](https://github.com/ossrs/srs/issues/2188). 5.0.2
* v5.0, 2021-03-17, Live: Refine edge to follow client and HTTP/302. 5.0.1
* v5.0, 2021-03-15, Init SRS/5. 5.0.0
@@ -1119,7 +1121,6 @@ The data for publishing RTMP was benchmarked by [SB][srs-bench]:
The data for playing HTTP FLV was benchmarked by [SB][srs-bench]:
-
| Update | SRS | Clients | Type | CPU | Memory | Commit |
| ------------- | --------- | ------------- | ------------- | --------- | -------- | ------------ |
| 2014-05-25 | 2.0.171 | 6.0k(6000) | players | 84% | 297MB | [code][p20] |
@@ -1133,25 +1134,33 @@ The data for playing HTTP FLV was benchmarked by [SB][srs-bench]:
The RTC benchmark data, by [srs-bench](https://github.com/ossrs/srs-bench/tree/feature/rtc#usage):
-
-| Update | SRS | Clients | Type | CPU | Memory | Threads |
-| ------------- | --------- | ------------- | ------------- | --------- | -------- | ------- |
-| 2021-03-31 | 4.0.87 | 550 | publishers | ~86% | 1.3GB | 1 |
-| 2021-03-31 | 4.0.87 | 800 | players | ~94% | 444MB | 1 |
-
-> Note: CentOS7, 500Kbps, 4CPU, 2.5 GHz Intel Xeon Platinum 8163/8269CY.
+| Update | Server | Clients | Type | CPU | Memory | Threads | Commit |
+| ------------- | ------------ | ----- | ---------- | -------- | -------- | ----- | --------- |
+| 2021-04-07 | SRS/5.0.3 | 10000 | publishers | ~90% x 32 | 28GB | 33 | [#2188](https://github.com/ossrs/srs/issues/2188#issuecomment-816309097) |
+| 2021-04-20 | Janus/0.11.1 | 4000 | publishers | ~90% x 32 | 790MB | 51 | [#2629](https://github.com/meetecho/janus-gateway/pull/2629#issuecomment-822914989) |
+| 2021-04-07 | SRS/5.0.3 | 3400 | publishers | ~95% x 8 | 6.3GB | 12 | [#2188](https://github.com/ossrs/srs/issues/2188#issuecomment-816309097) |
+| 2021-04-20 | Janus/0.11.1 | 1500 | publishers | ~95% x 8 | 276MB | 26 | [#2629](https://github.com/meetecho/janus-gateway/pull/2629#issuecomment-822914989) |
+| 2021-04-07 | SRS/5.0.3 | 2000 | publishers | ~95% x 4 | 4.1GB | 8 | [#2188](https://github.com/ossrs/srs/issues/2188#issuecomment-816309097) |
+| 2021-03-31 | SRS/5.0.2 | 1400 | publishers | ~90% x 4 | 3.1GB | 6 | [#2188](https://github.com/ossrs/srs/issues/2188#issuecomment-812499542) |
+| 2021-03-31 | SRS/5.0.2 | 1400 | players | ~93% x 4 | 1.0GB | 6 | [#2188](https://github.com/ossrs/srs/issues/2188#issuecomment-812499542) |
+| 2021-04-20 | Janus/0.11.1 | 750 | publishers | ~90% x 4 | 142MB | 23 | [#2629](https://github.com/meetecho/janus-gateway/pull/2629#issuecomment-822914989) |
+| 2021-04-20 | Janus/0.11.1 | 750 | players | ~92% x 4 | 283MB | 23 | [#2629](https://github.com/meetecho/janus-gateway/pull/2629#issuecomment-822914989) |
+| 2021-03-31 | SRS/4.0.87 | 550 | publishers | ~86% x 1 | 1.3GB | 1 | |
+| 2021-03-31 | SRS/4.0.87 | 800 | players | ~94% x 1 | 444MB | 1 | |
+
+> Note: The benchmark tool for Janus is [srs-bench](https://github.com/ossrs/srs-bench/tree/feature/rtc#janus), and startup script by [janus-docker](https://github.com/winlinvip/janus-docker#usage).
**Latency benchmark**
The latency between encoder and player with realtime config([CN][v4_CN_LowLatency], [EN][v4_EN_LowLatency]):
-|
-| Update | SRS | VP6 | H.264 | VP6+MP3 | H.264+MP3 |
-| ------------- | --------- | --------- | --------- | --------- | -------- |
-| 2014-12-16 | 2.0.72 | 0.1s | 0.4s |[0.8s][p15]|[0.6s][p16]|
-| 2014-12-12 | 2.0.70 |[0.1s][p13]|[0.4s][p14]| 1.0s | 0.9s |
-| 2014-12-03 | 1.0.10 | 0.4s | 0.4s | 0.9s | 1.2s |
+| Update | SRS | Protocol | VP6 | H.264 | VP6+MP3 | H.264+MP3 |
+| ------------- | --------- | --------- | --------- | --------- | --------- | -------- |
+| 2014-12-16 | 2.0.72 | RTMP | 0.1s | 0.4s |[0.8s][p15]|[0.6s][p16]|
+| 2014-12-12 | 2.0.70 | RTMP |[0.1s][p13]|[0.4s][p14]| 1.0s | 0.9s |
+| 2014-12-03 | 1.0.10 | RTMP | 0.4s | 0.4s | 0.9s | 1.2s |
+| 2021-04-02 | 4.0.87 | WebRTC | x | 80ms | x | x |
> 2018-08-05, [c45f72e](https://github.com/ossrs/srs/commit/c45f72ef7bac9c7cf85b9125fc9e3aafd53f396f), Refine HTTP-FLV latency, support realtime mode. 2.0.252
@@ -1159,35 +1168,6 @@ We used FMLE as encoder for benchmark. The latency of server was 0.1s+,
and the bottleneck was the encoder. For more information, read
[bug #257][bug #257-c0].
-
-**HLS overhead**
-
-About the overhead of HLS overhead, we compared FFMPEG and SRS.
-
-| Bitrate | Duration | FLV(KB) | HLS(KB) | Overhead |
-| ------- | -------- | ------- | -------- | --------- |
-| 275kbps | 600s | 11144 | 12756 | 14.46% |
-| 260kbps | 1860s | 59344 | 68004 | 14.59% |
-| 697kbps | 60s | 5116 | 5476 | 7.03% |
-| 565kbps | 453s | 31316 | 33544 | 7.11% |
-| 565kbps | 1813s | 125224 | 134140 | 7.12% |
-| 861kbps | 497s | 52316 | 54924 | 4.98% |
-| 857kbps | 1862s | 195008 | 204768 | 5.00% |
-| 1301kbps | 505s | 80320 | 83676 | 4.17% |
-| 1312kbps | 1915s | 306920 | 319680 | 4.15% |
-| 2707kbps | 600s | 198356 | 204560 | 3.12% |
-| 2814kbps | 1800s | 618456 | 637660 | 3.10% |
-| 2828kbps | 60s | 20716 | 21356 | 3.08% |
-| 2599kbps | 307s | 97580 | 100672 | 3.16% |
-| 2640kbps | 1283s | 413880 | 426912 | 3.14% |
-| 5254kbps | 71s | 45832 | 47056 | 2.67% |
-| 5147kbps | 370s | 195040 | 200280 | 2.68% |
-| 5158kbps | 1327s | 835664 | 858092 | 2.68% |
-
-The HLS overhead is calc by: (HLS - FLV) / FLV * 100%.
-
-The overhead should be larger than this benchmark(48kbps audio is best overhead), for we fix the [#512][bug #512].
-
## Architecture
SRS always use the simplest architecture to solve complex domain problems.
diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh
index 5aae95c9a7..5ccffcbb21 100755
--- a/trunk/auto/depends.sh
+++ b/trunk/auto/depends.sh
@@ -488,7 +488,11 @@ fi
# Affected users should upgrade to OpenSSL 1.1.0e. Users unable to immediately
# upgrade can alternatively recompile OpenSSL with -DOPENSSL_NO_HEARTBEATS.
if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL != YES ]]; then
- OPENSSL_OPTIONS="-no-shared -no-threads -DOPENSSL_NO_HEARTBEATS"
+ # Should never disable threads by -no-threads, because we're now multiple threading.
+ # @see https://www.openssl.org/blog/blog/2017/02/21/threads/
+ # @see https://github.com/openssl/openssl/issues/2165
+ # @see https://curl.se/libcurl/c/opensslthreadlock.html
+ OPENSSL_OPTIONS="-no-shared -DOPENSSL_NO_HEARTBEATS"
OPENSSL_CONFIG="./config"
# https://stackoverflow.com/questions/15539062/cross-compiling-of-openssl-for-linux-arm-v5te-linux-gnueabi-toolchain
if [[ $SRS_CROSS_BUILD == YES ]]; then
@@ -527,7 +531,7 @@ if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL != YES ]]; then
fi
#
# https://wiki.openssl.org/index.php/Compilation_and_Installation#Configure_Options
- # Already defined: -no-shared -no-threads -no-asm
+ # Already defined: -no-shared -no-asm
# Should enable: -no-dtls -no-dtls1 -no-ssl3
# Might able to disable: -no-ssl2 -no-comp -no-idea -no-hw -no-engine -no-dso -no-err -no-nextprotoneg -no-psk -no-srp -no-ec2m -no-weak-ssl-ciphers
# Note that we do not disable more features, because no file could be removed.
diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf
index 99a2265f45..ec2f88bc78 100644
--- a/trunk/conf/full.conf
+++ b/trunk/conf/full.conf
@@ -3,10 +3,6 @@
#############################################################################################
# RTMP sections
#############################################################################################
-# the rtmp listen ports, split by space, each listen entry is <[ip:]port>
-# for example, 192.168.1.100:1935 10.10.10.100:1935
-# where the ip is optional, default to 0.0.0.0, that is 1935 equals to 0.0.0.0:1935
-listen 1935;
# the pid file
# to ensure only one process can use a pid file
# and provides the current running process id, for script,
@@ -41,10 +37,11 @@ srs_log_level trace;
# when srs_log_tank is file, specifies the log file.
# default: ./objs/srs.log
srs_log_file ./objs/srs.log;
-# the max connections.
-# if exceed the max connections, server will drop the new connection.
-# default: 1000
-max_connections 1000;
+# The interval in ms, to flush async log. Generally, we flush from
+# coroutine-queue to thread-queue, then from thread-queue to disk.
+# So the delay of logs might be 2*srs_log_flush_interval.
+# Default: 1300
+srs_log_flush_interval 1300;
# whether start as daemon
# @remark: do not support reload.
# default: on
@@ -111,6 +108,66 @@ auto_reload_for_docker on;
# default: 0.8
tcmalloc_release_rate 0.8;
+# For thread pool.
+threads {
+ # The thread pool manager cycle interval, in seconds.
+ # Default: 5
+ interval 5;
+ # The number of hybrid threads to use, MUST >=1.
+ # Note that there MUST be same number of stream sections.
+ # Max to 64 threads.
+ # Default: 1
+ hybrids 1;
+ # Whether automatically generate stream config by hybrid.
+ # If off, user must create a number of streams, which is equal to the hybrids.
+ # Default: off
+ generate_streams off;
+ # CPU set for affinity, for example:
+ # 0 means CPU0
+ # 0-3 means CPU0, CPU1, CPU2
+ # 1-63 means all CPUs except CPU0
+ # Default: 0-63
+ cpu_affinity {
+ # For master thread manager.
+ master 0-63;
+ # For hybrid server or services.
+ hybrid 0-63;
+ # For log writing thread.
+ log 0-63;
+ }
+}
+
+# For system circuit breaker.
+circuit_breaker {
+ # Whether enable the circuit breaker.
+ # Default: on
+ enabled on;
+ # The CPU percent(0, 100) ever 1s, as system high water-level, which enable the circuit-break
+ # mechanism, for example, NACK will be disabled if high water-level.
+ # Default: 90
+ high_threshold 90;
+ # Reset the high water-level, if number of pulse under high_threshold.
+ # @remark 0 to disable the high water-level.
+ # Default: 2
+ high_pulse 2;
+ # The CPU percent(0, 100) ever 1s, as system critical water-level, which enable the circuit-break
+ # mechanism, for example, TWCC will be disabled if high water-level.
+ # @note All circuit-break mechanism of high-water-level scope are enabled in critical.
+ # Default: 95
+ critical_threshold 95;
+ # Reset the critical water-level, if number of pulse under critical_threshold.
+ # @remark 0 to disable the critical water-level.
+ # Default: 1
+ critical_pulse 1;
+ # If dying, also drop packets for players.
+ # Default: 99
+ dying_threshold 99;
+ # If CPU exceed the dying_pulse times, enter dying.
+ # @remark 0 to disable the dying water-level.
+ # Default: 5
+ dying_pulse 5;
+}
+
#############################################################################################
# heartbeat/stats sections
#############################################################################################
@@ -218,49 +275,219 @@ http_api {
cert ./conf/server.crt;
}
}
-# embedded http server in srs.
-# the http streaming config, for HLS/HDS/DASH/HTTPProgressive
-# global config for http streaming, user must config the http section for each vhost.
-# the embed http server used to substitute nginx in ./objs/nginx,
-# for example, srs running in arm, can provides RTMP and HTTP service, only with srs installed.
-# user can access the http server pages, generally:
-# curl http://192.168.1.170:80/srs.html
-# which will show srs version and welcome to srs.
-# @remark, the http embedded stream need to config the vhost, for instance, the __defaultVhost__
-# need to open the feature http of vhost.
-http_server {
- # whether http streaming service is enabled.
- # default: off
- enabled on;
- # the http streaming listen entry is <[ip:]port>
- # for example, 192.168.1.100:8080
- # where the ip is optional, default to 0.0.0.0, that is 8080 equals to 0.0.0.0:8080
- # @remark, if use lower port, for instance 80, user must start srs by root.
- # default: 8080
- listen 8080;
- # the default dir for http root.
- # default: ./objs/nginx/html
- dir ./objs/nginx/html;
- # whether enable crossdomain request.
- # for both http static and stream server and apply on all vhosts.
- # default: on
- crossdomain on;
- # For https_server or HTTPS Streaming.
- https {
- # Whether enable HTTPS Streaming.
+
+#############################################################################################
+# RTMP/HTTP/RTC Stream sections
+#############################################################################################
+stream {
+ # the rtmp listen ports, split by space, each listen entry is <[ip:]port>
+ # for example, 192.168.1.100:1935 10.10.10.100:1935
+ # where the ip is optional, default to 0.0.0.0, that is 1935 equals to 0.0.0.0:1935
+ listen 1935;
+ # the max connections.
+ # if exceed the max connections, server will drop the new connection.
+ # default: 1000
+ max_connections 1000;
+
+ # embedded http server in srs.
+ # the http streaming config, for HLS/HDS/DASH/HTTPProgressive
+ # global config for http streaming, user must config the http section for each vhost.
+ # the embed http server used to substitute nginx in ./objs/nginx,
+ # for example, srs running in arm, can provides RTMP and HTTP service, only with srs installed.
+ # user can access the http server pages, generally:
+ # curl http://192.168.1.170:80/srs.html
+ # which will show srs version and welcome to srs.
+ # @remark, the http embedded stream need to config the vhost, for instance, the __defaultVhost__
+ # need to open the feature http of vhost.
+ http_server {
+ # whether http streaming service is enabled.
+ # default: off
+ enabled on;
+ # the http streaming listen entry is <[ip:]port>
+ # for example, 192.168.1.100:8080
+ # where the ip is optional, default to 0.0.0.0, that is 8080 equals to 0.0.0.0:8080
+ # @remark, if use lower port, for instance 80, user must start srs by root.
+ # default: 8080
+ listen 8080;
+ # the default dir for http root.
+ # default: ./objs/nginx/html
+ dir ./objs/nginx/html;
+ # whether enable crossdomain request.
+ # for both http static and stream server and apply on all vhosts.
+ # default: on
+ crossdomain on;
+ # For https_server or HTTPS Streaming.
+ https {
+ # Whether enable HTTPS Streaming.
+ # default: off
+ enabled on;
+ # The listen endpoint for HTTPS Streaming.
+ # default: 8088
+ listen 8088;
+ # The SSL private key file, generated by:
+ # openssl genrsa -out server.key 2048
+ # default: ./conf/server.key
+ key ./conf/server.key;
+ # The SSL public cert file, generated by:
+ # openssl req -new -x509 -key server.key -out server.crt -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=Me/OU=Me/CN=ossrs.net"
+ # default: ./conf/server.crt
+ cert ./conf/server.crt;
+ }
+ }
+
+ rtc_server {
+ # Whether enable WebRTC server.
# default: off
enabled on;
- # The listen endpoint for HTTPS Streaming.
- # default: 8088
- listen 8088;
- # The SSL private key file, generated by:
- # openssl genrsa -out server.key 2048
- # default: ./conf/server.key
- key ./conf/server.key;
- # The SSL public cert file, generated by:
- # openssl req -new -x509 -key server.key -out server.crt -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=Me/OU=Me/CN=ossrs.net"
- # default: ./conf/server.crt
- cert ./conf/server.crt;
+ # The udp listen port, we will reuse it for connections.
+ # default: 8000
+ listen 8000;
+ # The exposed candidate IPs, response in SDP candidate line. It can be:
+ # * Retrieve server IP automatically, from all network interfaces.
+ # eth0 Retrieve server IP by specified network interface name. # TODO: Implements it.
+ # $CANDIDATE Read the IP from ENV variable, use * if not set.
+ # x.x.x.x A specified IP address or DNS name, which can be access by client such as Chrome.
+ # You can specific more than one interface name:
+ # eth0 eth1 Use network interface eth0 and eth1. # TODO: Implements it.
+ # Also by IP or DNS names:
+ # 192.168.1.3 10.1.2.3 rtc.me # TODO: Implements it.
+ # And by multiple ENV variables:
+ # $CANDIDATE $EIP # TODO: Implements it.
+ # @remark For Firefox, the candidate MUST be IP, MUST NOT be DNS name.
+ # @see https://github.com/ossrs/srs/wiki/v4_CN_RTCWiki#config-candidate
+ # default: *
+ candidate *;
+ # The IP family filter for auto discover 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
+ ecdsa on;
+ # Whether encrypt RTP packet by SRTP.
+ # @remark Should always turn it on, or Chrome will fail.
+ # default: on
+ encrypt on;
+ # We listen multiple times at the same port, by REUSEPORT, to increase the UDP queue.
+ # Note that you can set to 1 and increase the system UDP buffer size by net.core.rmem_max
+ # and net.core.rmem_default or just increase this to get larger UDP recv and send buffer.
+ # default: 1
+ reuseport 1;
+ # Whether merge multiple NALUs into one.
+ # @see https://github.com/ossrs/srs/issues/307#issuecomment-612806318
+ # default: off
+ merge_nalus off;
+ # Whether enable the perf stat at http://localhost:1985/api/v1/perf
+ # TODO: FIXME: We should enable it when refined.
+ # default: off
+ perf_stat off;
+ # For RTP packet and its payload cache.
+ rtp_cache {
+ # Whether enable the RTP packet cache.
+ # default: on
+ enabled on;
+ # The cache size for rtp packet in MB, each object is about 300B..
+ # default: 64
+ pkt_size 64.0;
+ # The cache size for rtp payload in MB, each object is about 40B.
+ # default: 16
+ payload_size 16.0;
+ }
+ # For RTP shared message and the large buffer cache.
+ rtp_msg_cache {
+ #Whether enable the RTP message(a large buffer) cache.
+ # default: on
+ enabled on;
+ # The cache size for message object in MB, each object is about 40B.
+ # default: 16
+ msg_size 16.0;
+ # The cache size for message large buffer in MB, each object is about 1500B.
+ # default: 512
+ buffer_size 512.0;
+ }
+ # 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.
+ # default: off
+ enabled off;
+ # The black-hole address for session.
+ addr 127.0.0.1:10000;
+ }
+ }
+}
+
+vhost rtc.vhost.srs.com {
+ rtc {
+ # Whether enable WebRTC server.
+ # default: off
+ enabled on;
+ # Whether support NACK.
+ # default: on
+ nack on;
+ # Whether directly use the packet, avoid copy.
+ # default: on
+ nack_no_copy on;
+ # Whether support TWCC.
+ # default: on
+ twcc on;
+ # The timeout in seconds for session timeout.
+ # Client will send ping(STUN binding request) to server, we use it as heartbeat.
+ # default: 30
+ stun_timeout 30;
+ # The strict check when process stun.
+ # default: off
+ stun_strict_check on;
+ # The role of dtls when peer is actpass: passive or active
+ # default: passive
+ dtls_role passive;
+ # The version of dtls, support dtls1.0, dtls1.2, and auto
+ # default: auto
+ dtls_version auto;
+ # Drop the packet with the pt(payload type), 0 never drop.
+ # default: 0
+ drop_for_pt 0;
+ ###############################################################
+ # For transmuxing RTMP to RTC, the strategy for bframe.
+ # keep Keep bframe, which may make browser with playing problems.
+ # discard Discard bframe, maybe cause browser with little problems.
+ # default: discard
+ bframe discard;
+ # For transmuxing RTMP to RTC, the strategy for aac audio.
+ # transcode Transcode aac to opus.
+ # discard Discard aac audio packet.
+ # default: transcode
+ aac transcode;
+ ###############################################################
+ # For transmuxing RTC to RTMP.
+ # Whether trans-mux RTC to RTMP streaming.
+ # Default: off
+ rtc_to_rtmp off;
+ # The PLI interval in seconds, for RTC to RTMP.
+ # Note the available range is [0.5, 30]
+ # Default: 6.0
+ pli_for_rtmp 6.0;
+ }
+ ###############################################################
+ # For transmuxing RTMP to RTC, it will impact the default values if RTC is on.
+ # Whether enable min delay mode for vhost.
+ # default: on, for RTC.
+ min_latency on;
+ play {
+ # set the MW(merged-write) latency in ms.
+ # @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config.
+ # default: 0 (For WebRTC)
+ mw_latency 0;
+ # Set the MW(merged-write) min messages.
+ # default: 0 (For Real-Time, that is min_latency on)
+ # default: 1 (For WebRTC, that is min_latency off)
+ mw_msgs 0;
}
}
@@ -440,164 +667,6 @@ srt_server {
default_app live;
}
-#############################################################################################
-# WebRTC server section
-#############################################################################################
-rtc_server {
- # Whether enable WebRTC server.
- # default: off
- enabled on;
- # The udp listen port, we will reuse it for connections.
- # default: 8000
- listen 8000;
- # The exposed candidate IPs, response in SDP candidate line. It can be:
- # * Retrieve server IP automatically, from all network interfaces.
- # eth0 Retrieve server IP by specified network interface name. # TODO: Implements it.
- # $CANDIDATE Read the IP from ENV variable, use * if not set.
- # x.x.x.x A specified IP address or DNS name, which can be access by client such as Chrome.
- # You can specific more than one interface name:
- # eth0 eth1 Use network interface eth0 and eth1. # TODO: Implements it.
- # Also by IP or DNS names:
- # 192.168.1.3 10.1.2.3 rtc.me # TODO: Implements it.
- # And by multiple ENV variables:
- # $CANDIDATE $EIP # TODO: Implements it.
- # @remark For Firefox, the candidate MUST be IP, MUST NOT be DNS name.
- # @see https://github.com/ossrs/srs/wiki/v4_CN_RTCWiki#config-candidate
- # default: *
- candidate *;
- # The IP family filter for auto discover 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
- ecdsa on;
- # Whether encrypt RTP packet by SRTP.
- # @remark Should always turn it on, or Chrome will fail.
- # default: on
- encrypt on;
- # We listen multiple times at the same port, by REUSEPORT, to increase the UDP queue.
- # Note that you can set to 1 and increase the system UDP buffer size by net.core.rmem_max
- # and net.core.rmem_default or just increase this to get larger UDP recv and send buffer.
- # default: 1
- reuseport 1;
- # Whether merge multiple NALUs into one.
- # @see https://github.com/ossrs/srs/issues/307#issuecomment-612806318
- # default: off
- merge_nalus off;
- # Whether enable the perf stat at http://localhost:1985/api/v1/perf
- # TODO: FIXME: We should enable it when refined.
- # default: off
- perf_stat off;
- # For RTP packet and its payload cache.
- rtp_cache {
- # Whether enable the RTP packet cache.
- # default: on
- enabled on;
- # The cache size for rtp packet in MB, each object is about 300B..
- # default: 64
- pkt_size 64.0;
- # The cache size for rtp payload in MB, each object is about 40B.
- # default: 16
- payload_size 16.0;
- }
- # For RTP shared message and the large buffer cache.
- rtp_msg_cache {
- #Whether enable the RTP message(a large buffer) cache.
- # default: on
- enabled on;
- # The cache size for message object in MB, each object is about 40B.
- # default: 16
- msg_size 16.0;
- # The cache size for message large buffer in MB, each object is about 1500B.
- # default: 512
- buffer_size 512.0;
- }
- # 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.
- # default: off
- enabled off;
- # The black-hole address for session.
- addr 127.0.0.1:10000;
- }
-}
-
-vhost rtc.vhost.srs.com {
- rtc {
- # Whether enable WebRTC server.
- # default: off
- enabled on;
- # Whether support NACK.
- # default: on
- nack on;
- # Whether directly use the packet, avoid copy.
- # default: on
- nack_no_copy on;
- # Whether support TWCC.
- # default: on
- twcc on;
- # The timeout in seconds for session timeout.
- # Client will send ping(STUN binding request) to server, we use it as heartbeat.
- # default: 30
- stun_timeout 30;
- # The strict check when process stun.
- # default: off
- stun_strict_check on;
- # The role of dtls when peer is actpass: passive or active
- # default: passive
- dtls_role passive;
- # The version of dtls, support dtls1.0, dtls1.2, and auto
- # default: auto
- dtls_version auto;
- # Drop the packet with the pt(payload type), 0 never drop.
- # default: 0
- drop_for_pt 0;
- ###############################################################
- # For transmuxing RTMP to RTC, the strategy for bframe.
- # keep Keep bframe, which may make browser with playing problems.
- # discard Discard bframe, maybe cause browser with little problems.
- # default: discard
- bframe discard;
- # For transmuxing RTMP to RTC, the strategy for aac audio.
- # transcode Transcode aac to opus.
- # discard Discard aac audio packet.
- # default: transcode
- aac transcode;
- ###############################################################
- # For transmuxing RTC to RTMP.
- # Whether trans-mux RTC to RTMP streaming.
- # Default: off
- rtc_to_rtmp off;
- # The PLI interval in seconds, for RTC to RTMP.
- # Note the available range is [0.5, 30]
- # Default: 6.0
- pli_for_rtmp 6.0;
- }
- ###############################################################
- # For transmuxing RTMP to RTC, it will impact the default values if RTC is on.
- # Whether enable min delay mode for vhost.
- # default: on, for RTC.
- min_latency on;
- play {
- # set the MW(merged-write) latency in ms.
- # @remark For WebRTC, we enable pass-timestamp mode, so we ignore this config.
- # default: 0 (For WebRTC)
- mw_latency 0;
- # Set the MW(merged-write) min messages.
- # default: 0 (For Real-Time, that is min_latency on)
- # default: 1 (For WebRTC, that is min_latency off)
- mw_msgs 0;
- }
-}
-
#############################################################################################
# RTMP/HTTP VHOST sections
#############################################################################################
diff --git a/trunk/conf/threads.conf b/trunk/conf/threads.conf
new file mode 100644
index 0000000000..630c6a9ee1
--- /dev/null
+++ b/trunk/conf/threads.conf
@@ -0,0 +1,37 @@
+
+daemon off;
+srs_log_tank console;
+
+http_api {
+ enabled on;
+ listen 1985;
+}
+
+threads {
+ hybrids 2;
+ generate_streams on;
+}
+
+stream {
+ listen 1935;
+ max_connections 1000;
+ http_server {
+ enabled on;
+ listen 8080;
+ }
+ rtc_server {
+ enabled on;
+ listen 8000;
+ }
+}
+
+vhost __defaultVhost__ {
+ rtc {
+ enabled on;
+ }
+ http_remux {
+ enabled on;
+ mount [vhost]/[app]/[stream].flv;
+ }
+}
+
diff --git a/trunk/configure b/trunk/configure
index 8ae0b701b3..86c1ae204a 100755
--- a/trunk/configure
+++ b/trunk/configure
@@ -274,7 +274,7 @@ MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_sourc
"srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call"
"srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec"
"srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr"
- "srs_app_coworkers" "srs_app_hybrid")
+ "srs_app_coworkers" "srs_app_hybrid" "srs_app_threads")
if [[ $SRS_RTC == YES ]]; then
MODULE_FILES+=("srs_app_rtc_conn" "srs_app_rtc_dtls" "srs_app_rtc_sdp"
"srs_app_rtc_queue" "srs_app_rtc_server" "srs_app_rtc_source" "srs_app_rtc_api")
diff --git a/trunk/research/thread-model/.gitignore b/trunk/research/thread-model/.gitignore
index 1abd1fc862..5737fff3e8 100644
--- a/trunk/research/thread-model/.gitignore
+++ b/trunk/research/thread-model/.gitignore
@@ -1,3 +1,4 @@
thread-local
udp-connect-client
udp-connect-server
+extern-main
diff --git a/trunk/research/thread-model/extern-extra.cpp b/trunk/research/thread-model/extern-extra.cpp
new file mode 100644
index 0000000000..f203776488
--- /dev/null
+++ b/trunk/research/thread-model/extern-extra.cpp
@@ -0,0 +1,13 @@
+
+#include
+
+int __thread ga = 100;
+int __thread gb = 200;
+
+void* pfn2(void* arg)
+{
+ printf("Thread2: ga=%d, gb=%d\n", ga, gb);
+ return NULL;
+}
+
+
diff --git a/trunk/research/thread-model/extern-main.cpp b/trunk/research/thread-model/extern-main.cpp
new file mode 100644
index 0000000000..33c4f446f9
--- /dev/null
+++ b/trunk/research/thread-model/extern-main.cpp
@@ -0,0 +1,36 @@
+/*
+g++ -std=c++11 -g -O0 extern-main.cpp extern-extra.cpp -o extern-main
+*/
+#include
+// @see https://linux.die.net/man/3/pthread_create
+#include
+
+/*
+Main: ga=100, gb=1867710016
+Thread1: ga=100, gb=1867710016
+Thread2: ga=100, gb=200
+*/
+extern __thread int ga;
+extern int gb;
+
+void* pfn(void* arg)
+{
+ printf("Thread1: ga=%d, gb=%d\n", ga, gb);
+ return NULL;
+}
+
+extern void* pfn2(void* arg);
+
+int main(int argc, char** argv)
+{
+ printf("Main: ga=%d, gb=%d\n", ga, gb);
+
+ pthread_t trd = NULL;
+ pthread_create(&trd, NULL, pfn, NULL);
+ pthread_join(trd, NULL);
+
+ pthread_t trd2 = NULL;
+ pthread_create(&trd2, NULL, pfn2, NULL);
+ pthread_join(trd2, NULL);
+ return 0;
+}
diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp
index 33edb4ff2a..4038d4c5ce 100644
--- a/trunk/src/app/srs_app_config.cpp
+++ b/trunk/src/app/srs_app_config.cpp
@@ -56,6 +56,7 @@ using namespace std;
#include
#include
#include
+#include
using namespace srs_internal;
@@ -541,6 +542,151 @@ srs_error_t srs_config_transform_vhost(SrsConfDirective* root)
return err;
}
+// To wrap directive temporally.
+class SrsTempConfig : public SrsConfig
+{
+public:
+ SrsTempConfig(SrsConfDirective* r) {
+ root = r;
+ }
+ virtual ~SrsTempConfig() {
+ root = NULL;
+ }
+};
+
+srs_error_t srs_config_transform_vhost2(SrsConfDirective* root)
+{
+ srs_error_t err = srs_success;
+
+ // Transform streams for hybrids.
+ if (true) {
+ SrsConfDirective* stream = new SrsConfDirective();
+ SrsAutoFree(SrsConfDirective, stream);
+
+ // The number of stream directives.
+ int nn_streams = 0;
+ std::string old_style_stream_name;
+
+ // Collect directives which should be moved to stream.
+ for (int i = 0; i < (int)root->directives.size(); i++) {
+ SrsConfDirective* dir = root->directives.at(i);
+
+ // SRS5.0, move listen/max_connections/http_server/rtc_server to stream.
+ // SRS1/2/3/4:
+ // listen; max_connections;
+ // http_server {} rtc_server{}
+ // SRS5+:
+ // stream {
+ // listen; max_connections;
+ // http_server {} rtc_server{}
+ // }
+ if (dir->name == "listen" || dir->name == "max_connections"
+ || dir->name == "http_server" || dir->name == "rtc_server") {
+ old_style_stream_name = dir->name;
+ stream->directives.push_back(dir);
+ }
+
+ if (dir->name == "stream") {
+ nn_streams++;
+ }
+ }
+
+ // Fail if config the stream and old style stream.
+ if (!stream->directives.empty() && nn_streams) {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "config %d stream conflicts with %s",
+ nn_streams, old_style_stream_name.c_str());
+ }
+
+ // Ignore if no directives for stream.
+ if (!stream->directives.empty()) {
+ // Remove the stream directives from root.
+ for (int i = 0; i < (int)stream->directives.size(); i++) {
+ SrsConfDirective* dir = stream->directives.at(i);
+ root->remove(dir);
+ }
+
+ // Push the stream to root.
+ stream->name = "stream";
+ root->directives.push_back(stream);
+ stream = NULL;
+ }
+ }
+
+ // Auto generate streams, if there is only one stream template.
+ SrsTempConfig config(root);
+ if (config.get_threads_generate_stream()) {
+ int nn_streams = 0;
+ SrsConfDirective* tmpl = NULL;
+ for (int i = 0; i < (int)root->directives.size(); i++) {
+ SrsConfDirective* dir = root->directives.at(i);
+ if (dir->name == "stream") {
+ tmpl = dir;
+ nn_streams++;
+ }
+ }
+
+ int nn_hybrids = config.get_threads_hybrids();
+ if (tmpl && nn_streams == 1 && nn_hybrids > 1) {
+ if ((err = srs_config_generate_stream(root, tmpl, nn_hybrids - nn_streams)) != srs_success) {
+ return srs_error_wrap(err, "generate stream");
+ }
+ }
+ }
+
+ return err;
+}
+
+srs_error_t srs_config_generate_stream(SrsConfDirective* root, SrsConfDirective* tmpl, int nn)
+{
+ srs_error_t err = srs_success;
+
+ SrsConfDirective* p = NULL;
+
+ // stream.listen for RTMP.
+ int rtmp_port = 0;
+ if ((p = tmpl->get("listen")) != NULL) {
+ rtmp_port = ::atoi(p->arg0().c_str());
+ }
+
+ // stream.http_server.listen for HTTP.
+ int http_port = 0;
+ if ((p = tmpl->get("http_server")) != NULL) {
+ if ((p = p->get("listen")) != NULL) {
+ http_port = ::atoi(p->arg0().c_str());
+ }
+ }
+
+ // stream.rtc_server.listen for RTC.
+ int rtc_port = 0;
+ if ((p = tmpl->get("rtc_server")) != NULL) {
+ if ((p = p->get("listen")) != NULL) {
+ rtc_port = ::atoi(p->arg0().c_str());
+ }
+ }
+
+ for (int i = 0; i < nn; i++) {
+ SrsConfDirective* stream = tmpl->copy();
+ root->directives.push_back(stream);
+
+ // stream.listen for RTMP.
+ if (rtmp_port) {
+ stream->get_or_create("listen")->set_arg0(srs_int2str(rtmp_port + i + 1));
+ }
+
+ // stream.http_server.listen for HTTP.
+ if (http_port) {
+ stream->get_or_create("http_server")->get_or_create("listen")->set_arg0(srs_int2str(http_port + i + 1));
+ }
+
+ // stream.rtc_server.listen for RTC.
+ if (http_port) {
+ stream->get_or_create("rtc_server")->get_or_create("listen")->set_arg0(srs_int2str(rtc_port + i + 1));
+ }
+ }
+
+ return err;
+}
+
// LCOV_EXCL_START
srs_error_t srs_config_dumps_engine(SrsConfDirective* dir, SrsJsonObject* engine)
{
@@ -720,10 +866,10 @@ string SrsConfDirective::arg3()
return "";
}
-SrsConfDirective* SrsConfDirective::at(int index)
+SrsConfDirective* SrsConfDirective::at(int stream_index)
{
- srs_assert(index < (int)directives.size());
- return directives.at(index);
+ srs_assert(stream_index < (int)directives.size());
+ return directives.at(stream_index);
}
SrsConfDirective* SrsConfDirective::get(string _name)
@@ -1163,8 +1309,6 @@ srs_error_t SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector
SrsConfig::SrsConfig()
{
- dolphin = false;
-
show_help = false;
show_version = false;
test_conf = false;
@@ -1173,20 +1317,20 @@ SrsConfig::SrsConfig()
root = new SrsConfDirective();
root->conf_line = 0;
root->name = "root";
+
+ lock_ = new SrsThreadMutex();
}
SrsConfig::~SrsConfig()
{
+ srs_freep(lock_);
srs_freep(root);
}
-bool SrsConfig::is_dolphin()
-{
- return dolphin;
-}
-
void SrsConfig::subscribe(ISrsReloadHandler* handler)
{
+ SrsThreadLocker(lock_);
+
std::vector::iterator it;
it = std::find(subscribes.begin(), subscribes.end(), handler);
@@ -1199,6 +1343,8 @@ void SrsConfig::subscribe(ISrsReloadHandler* handler)
void SrsConfig::unsubscribe(ISrsReloadHandler* handler)
{
+ SrsThreadLocker(lock_);
+
std::vector::iterator it;
it = std::find(subscribes.begin(), subscribes.end(), handler);
@@ -1225,6 +1371,9 @@ srs_error_t SrsConfig::reload()
if ((err = srs_config_transform_vhost(conf.root)) != srs_success) {
return srs_error_wrap(err, "transform config");
}
+ if ((err = srs_config_transform_vhost2(conf.root)) != srs_success) {
+ return srs_error_wrap(err, "transform config");
+ }
if ((err = conf.check_config()) != srs_success) {
return srs_error_wrap(err, "check config");
@@ -1519,27 +1668,6 @@ srs_error_t SrsConfig::reload_conf(SrsConfig* conf)
}
}
- // merge config: srs_log_tank
- if (!srs_directive_equals(root->get("srs_log_tank"), old_root->get("srs_log_tank"))) {
- if ((err = do_reload_srs_log_tank()) != srs_success) {
- return srs_error_wrap(err, "log tank");;
- }
- }
-
- // merge config: srs_log_level
- if (!srs_directive_equals(root->get("srs_log_level"), old_root->get("srs_log_level"))) {
- if ((err = do_reload_srs_log_level()) != srs_success) {
- return srs_error_wrap(err, "log level");;
- }
- }
-
- // merge config: srs_log_file
- if (!srs_directive_equals(root->get("srs_log_file"), old_root->get("srs_log_file"))) {
- if ((err = do_reload_srs_log_file()) != srs_success) {
- return srs_error_wrap(err, "log file");;
- }
- }
-
// merge config: max_connections
if (!srs_directive_equals(root->get("max_connections"), old_root->get("max_connections"))) {
if ((err = do_reload_max_connections()) != srs_success) {
@@ -1547,13 +1675,6 @@ srs_error_t SrsConfig::reload_conf(SrsConfig* conf)
}
}
- // merge config: utc_time
- if (!srs_directive_equals(root->get("utc_time"), old_root->get("utc_time"))) {
- if ((err = do_reload_utc_time()) != srs_success) {
- return srs_error_wrap(err, "utc time");;
- }
- }
-
// merge config: pithy_print_ms
if (!srs_directive_equals(root->get("pithy_print_ms"), old_root->get("pithy_print_ms"))) {
if ((err = do_reload_pithy_print_ms()) != srs_success) {
@@ -1667,102 +1788,14 @@ srs_error_t SrsConfig::reload_http_api(SrsConfDirective* old_root)
srs_error_t SrsConfig::reload_http_stream(SrsConfDirective* old_root)
{
srs_error_t err = srs_success;
-
- // merge config.
- std::vector::iterator it;
-
- // state graph
- // old_http_stream new_http_stream
- // DISABLED => ENABLED
- // ENABLED => DISABLED
- // ENABLED => ENABLED (modified)
-
- SrsConfDirective* new_http_stream = root->get("http_server");
- SrsConfDirective* old_http_stream = old_root->get("http_server");
-
- // DISABLED => ENABLED
- if (!get_http_stream_enabled(old_http_stream) && get_http_stream_enabled(new_http_stream)) {
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_http_stream_enabled()) != srs_success) {
- return srs_error_wrap(err, "http stream off=>on");
- }
- }
- srs_trace("reload http stream off=>on success.");
- return err;
- }
-
- // ENABLED => DISABLED
- if (get_http_stream_enabled(old_http_stream) && !get_http_stream_enabled(new_http_stream)) {
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_http_stream_disabled()) != srs_success) {
- return srs_error_wrap(err, "http stream on=>off");
- }
- }
- srs_trace("reload http stream on=>off success.");
- return err;
- }
-
- // ENABLED => ENABLED (modified)
- if (get_http_stream_enabled(old_http_stream) && get_http_stream_enabled(new_http_stream)
- && !srs_directive_equals(old_http_stream, new_http_stream)
- ) {
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_http_stream_updated()) != srs_success) {
- return srs_error_wrap(err, "http stream enabled");
- }
- }
- srs_trace("reload http stream enabled success.");
-
- if (!srs_directive_equals(old_http_stream->get("crossdomain"), new_http_stream->get("crossdomain"))) {
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_http_stream_crossdomain()) != srs_success) {
- return srs_error_wrap(err, "http stream crossdomain");
- }
- }
- }
- srs_trace("reload http stream crossdomain success.");
- return err;
- }
-
- srs_trace("reload http stream success, nothing changed.");
+ // TODO: FIXME: We never support reload HTTP stream.
return err;
}
srs_error_t SrsConfig::reload_rtc_server(SrsConfDirective* old_root)
{
srs_error_t err = srs_success;
-
- // merge config.
- std::vector::iterator it;
-
- // state graph
- // old_rtc_server new_rtc_server
- // ENABLED => ENABLED (modified)
-
- SrsConfDirective* new_rtc_server = root->get("rtc_server");
- SrsConfDirective* old_rtc_server = old_root->get("rtc_server");
-
- // TODO: FIXME: Support disable or enable reloading.
-
- // ENABLED => ENABLED (modified)
- if (get_rtc_server_enabled(old_rtc_server) && get_rtc_server_enabled(new_rtc_server)
- && !srs_directive_equals(old_rtc_server, new_rtc_server)
- ) {
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_rtc_server()) != srs_success) {
- return srs_error_wrap(err, "rtc server enabled");
- }
- }
- srs_trace("reload rtc server success.");
- return err;
- }
-
- srs_trace("reload rtc server success, nothing changed.");
+ // TODO: FIXME: Do not support reloading RTC Server.
return err;
}
@@ -1988,12 +2021,14 @@ srs_error_t SrsConfig::parse_options(int argc, char** argv)
// the parse_file never check the config,
// we check it when user requires check config file.
if (err == srs_success && (err = srs_config_transform_vhost(root)) == srs_success) {
- if (err == srs_success && (err = check_config()) == srs_success) {
- srs_trace("config file is ok");
- exit(0);
+ if (err == srs_success && (err = srs_config_transform_vhost2(root)) == srs_success) {
+ if (err == srs_success && (err = check_config()) == srs_success) {
+ srs_trace("config file is ok");
+ exit(0);
+ }
}
}
-
+
srs_error("invalid config, %s", srs_error_desc(err).c_str());
int ret = srs_error_code(err);
srs_freep(err);
@@ -2004,6 +2039,9 @@ srs_error_t SrsConfig::parse_options(int argc, char** argv)
if ((err = srs_config_transform_vhost(root)) != srs_success) {
return srs_error_wrap(err, "transform");
}
+ if ((err = srs_config_transform_vhost2(root)) != srs_success) {
+ return srs_error_wrap(err, "transform");
+ }
////////////////////////////////////////////////////////////////////////
// check log name and level
@@ -2102,9 +2140,7 @@ srs_error_t SrsConfig::global_to_json(SrsJsonObject* obj)
continue;
}
- if (dir->name == "listen") {
- obj->set(dir->name, dir->dumps_args());
- } else if (dir->name == "pid") {
+ if (dir->name == "pid") {
obj->set(dir->name, dir->dumps_arg0_to_str());
} else if (dir->name == "chunk_size") {
obj->set(dir->name, dir->dumps_arg0_to_integer());
@@ -2116,8 +2152,6 @@ srs_error_t SrsConfig::global_to_json(SrsJsonObject* obj)
obj->set(dir->name, dir->dumps_arg0_to_str());
} else if (dir->name == "srs_log_file") {
obj->set(dir->name, dir->dumps_arg0_to_str());
- } else if (dir->name == "max_connections") {
- obj->set(dir->name, dir->dumps_arg0_to_integer());
} else if (dir->name == "daemon") {
obj->set(dir->name, dir->dumps_arg0_to_boolean());
} else if (dir->name == "utc_time") {
@@ -2181,19 +2215,6 @@ srs_error_t SrsConfig::global_to_json(SrsJsonObject* obj)
}
}
obj->set(dir->name, sobj);
- } else if (dir->name == "http_server") {
- SrsJsonObject* sobj = SrsJsonAny::object();
- for (int j = 0; j < (int)dir->directives.size(); j++) {
- SrsConfDirective* sdir = dir->directives.at(j);
- if (sdir->name == "enabled") {
- sobj->set(sdir->name, sdir->dumps_arg0_to_boolean());
- } else if (sdir->name == "listen") {
- sobj->set(sdir->name, sdir->dumps_arg0_to_str());
- } else if (sdir->name == "dir") {
- sobj->set(sdir->name, sdir->dumps_arg0_to_str());
- }
- }
- obj->set(dir->name, sobj);
} else if (dir->name == "stream_caster") {
SrsJsonObject* sobj = SrsJsonAny::object();
for (int j = 0; j < (int)dir->directives.size(); j++) {
@@ -2973,78 +2994,6 @@ srs_error_t SrsConfig::raw_set_ff_log_dir(string ff_log_dir, bool& applied)
return err;
}
-srs_error_t SrsConfig::raw_set_srs_log_tank(string srs_log_tank, bool& applied)
-{
- srs_error_t err = srs_success;
-
- applied = false;
-
- SrsConfDirective* conf = root->get_or_create("srs_log_tank");
-
- if (conf->arg0() == srs_log_tank) {
- return err;
- }
-
- conf->args.clear();
- conf->args.push_back(srs_log_tank);
-
- if ((err = do_reload_srs_log_tank()) != srs_success) {
- return srs_error_wrap(err, "reload log tank");
- }
-
- applied = true;
-
- return err;
-}
-
-srs_error_t SrsConfig::raw_set_srs_log_level(string srs_log_level, bool& applied)
-{
- srs_error_t err = srs_success;
-
- applied = false;
-
- SrsConfDirective* conf = root->get_or_create("srs_log_level");
-
- if (conf->arg0() == srs_log_level) {
- return err;
- }
-
- conf->args.clear();
- conf->args.push_back(srs_log_level);
-
- if ((err = do_reload_srs_log_level()) != srs_success) {
- return srs_error_wrap(err, "reload log level");
- }
-
- applied = true;
-
- return err;
-}
-
-srs_error_t SrsConfig::raw_set_srs_log_file(string srs_log_file, bool& applied)
-{
- srs_error_t err = srs_success;
-
- applied = false;
-
- SrsConfDirective* conf = root->get_or_create("srs_log_file");
-
- if (conf->arg0() == srs_log_file) {
- return err;
- }
-
- conf->args.clear();
- conf->args.push_back(srs_log_file);
-
- if ((err = do_reload_srs_log_file()) != srs_success) {
- return srs_error_wrap(err, "reload log file");
- }
-
- applied = true;
-
- return err;
-}
-
srs_error_t SrsConfig::raw_set_max_connections(string max_connections, bool& applied)
{
srs_error_t err = srs_success;
@@ -3069,30 +3018,6 @@ srs_error_t SrsConfig::raw_set_max_connections(string max_connections, bool& app
return err;
}
-srs_error_t SrsConfig::raw_set_utc_time(string utc_time, bool& applied)
-{
- srs_error_t err = srs_success;
-
- applied = false;
-
- SrsConfDirective* conf = root->get_or_create("utc_time");
-
- if (conf->arg0() == utc_time) {
- return err;
- }
-
- conf->args.clear();
- conf->args.push_back(utc_time);
-
- if ((err = do_reload_utc_time()) != srs_success) {
- return srs_error_wrap(err, "reload");
- }
-
- applied = true;
-
- return err;
-}
-
srs_error_t SrsConfig::raw_set_pithy_print_ms(string pithy_print_ms, bool& applied)
{
srs_error_t err = srs_success;
@@ -3292,54 +3217,6 @@ srs_error_t SrsConfig::do_reload_pid()
return err;
}
-srs_error_t SrsConfig::do_reload_srs_log_tank()
-{
- srs_error_t err = srs_success;
-
- vector::iterator it;
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_log_tank()) != srs_success) {
- return srs_error_wrap(err, "notify subscribes reload srs_log_tank failed");
- }
- }
- srs_trace("reload srs_log_tank success.");
-
- return err;
-}
-
-srs_error_t SrsConfig::do_reload_srs_log_level()
-{
- srs_error_t err = srs_success;
-
- vector::iterator it;
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_log_level()) != srs_success) {
- return srs_error_wrap(err, "notify subscribes reload srs_log_level failed");
- }
- }
- srs_trace("reload srs_log_level success.");
-
- return err;
-}
-
-srs_error_t SrsConfig::do_reload_srs_log_file()
-{
- srs_error_t err = srs_success;
-
- vector::iterator it;
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_log_file()) != srs_success) {
- return srs_error_wrap(err, "notify subscribes reload srs_log_file failed");
- }
- }
- srs_trace("reload srs_log_file success.");
-
- return err;
-}
-
srs_error_t SrsConfig::do_reload_max_connections()
{
srs_error_t err = srs_success;
@@ -3356,22 +3233,6 @@ srs_error_t SrsConfig::do_reload_max_connections()
return err;
}
-srs_error_t SrsConfig::do_reload_utc_time()
-{
- srs_error_t err = srs_success;
-
- vector::iterator it;
- for (it = subscribes.begin(); it != subscribes.end(); ++it) {
- ISrsReloadHandler* subscribe = *it;
- if ((err = subscribe->on_reload_utc_time()) != srs_success) {
- return srs_error_wrap(err, "utc_time");
- }
- }
- srs_trace("reload utc_time success.");
-
- return err;
-}
-
srs_error_t SrsConfig::do_reload_pithy_print_ms()
{
srs_error_t err = srs_success;
@@ -3468,28 +3329,6 @@ srs_error_t SrsConfig::parse_argv(int& i, char** argv)
show_help = false;
test_conf = true;
break;
- case 'p':
- dolphin = true;
- if (*p) {
- dolphin_rtmp_port = p;
- continue;
- }
- if (argv[++i]) {
- dolphin_rtmp_port = argv[i];
- continue;
- }
- return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "-p requires params");
- case 'x':
- dolphin = true;
- if (*p) {
- dolphin_http_port = p;
- continue;
- }
- if (argv[++i]) {
- dolphin_http_port = argv[i];
- continue;
- }
- return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "-x requires params");
case 'v':
case 'V':
show_help = false;
@@ -3576,6 +3415,10 @@ srs_error_t SrsConfig::check_config()
if ((err = check_number_connections()) != srs_success) {
return srs_error_wrap(err, "check connections");
}
+
+ if ((err = check_hybrids()) != srs_success) {
+ return srs_error_wrap(err, "check hybrids");
+ }
return err;
}
@@ -3599,19 +3442,44 @@ srs_error_t SrsConfig::check_normal_config()
for (int i = 0; i < (int)root->directives.size(); i++) {
SrsConfDirective* conf = root->at(i);
std::string n = conf->name;
- if (n != "listen" && n != "pid" && n != "chunk_size" && n != "ff_log_dir"
+ if (n != "pid" && n != "chunk_size" && n != "ff_log_dir"
&& n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file"
- && n != "max_connections" && n != "daemon" && n != "heartbeat"
+ && n != "daemon" && n != "heartbeat" && n != "stream"
&& n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms"
- && n != "http_server" && n != "stream_caster" && n != "rtc_server" && n != "srt_server"
+ && n != "stream_caster" && n != "srt_server"
&& n != "utc_time" && n != "work_dir" && n != "asprocess"
&& n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit"
&& n != "grace_start_wait" && n != "empty_ip_ok" && n != "disable_daemon_for_docker"
&& n != "inotify_auto_reload" && n != "auto_reload_for_docker" && n != "tcmalloc_release_rate"
- ) {
+ && n != "srs_log_flush_interval" && n != "threads" && n != "circuit_breaker") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal directive %s", n.c_str());
}
+
+ for (int j = 0; conf && n == "stream" && j < (int)conf->directives.size(); j++) {
+ SrsConfDirective* obj = conf->at(j);
+ string m = obj->name;
+ if (m != "listen" && m != "max_connections" && m != "http_server" && m != "rtc_server") {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal stream directive %s", m.c_str());
+ }
+
+ for (int k = 0; obj && m == "http_server" && k < (int)obj->directives.size(); k++) {
+ string l = obj->at(k)->name;
+ if (l != "enabled" && l != "listen" && l != "dir" && l != "crossdomain" && l != "https") {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal http_stream.%s", l.c_str());
+ }
+ }
+
+ for (int k = 0; obj && m == "rtc_server" && k < (int)obj->directives.size(); k++) {
+ string l = obj->at(k)->name;
+ if (l != "enabled" && l != "listen" && l != "dir" && l != "candidate" && l != "ecdsa"
+ && l != "encrypt" && l != "reuseport" && l != "merge_nalus" && l != "perf_stat" && l != "black_hole"
+ && l != "ip_family" && l != "rtp_cache" && l != "rtp_msg_cache") {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", l.c_str());
+ }
+ }
+ }
}
+
if (true) {
SrsConfDirective* conf = root->get("http_api");
for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
@@ -3631,15 +3499,6 @@ srs_error_t SrsConfig::check_normal_config()
}
}
}
- if (true) {
- SrsConfDirective* conf = root->get("http_server");
- for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
- string n = conf->at(i)->name;
- if (n != "enabled" && n != "listen" && n != "dir" && n != "crossdomain" && n != "https") {
- return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal http_stream.%s", n.c_str());
- }
- }
- }
if (true) {
SrsConfDirective* conf = root->get("srt_server");
for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
@@ -3672,17 +3531,6 @@ srs_error_t SrsConfig::check_normal_config()
}
}
}
- if (true) {
- SrsConfDirective* conf = root->get("rtc_server");
- for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
- string n = conf->at(i)->name;
- if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa"
- && n != "encrypt" && n != "reuseport" && n != "merge_nalus" && n != "perf_stat" && n != "black_hole"
- && n != "ip_family" && n != "rtp_cache" && n != "rtp_msg_cache") {
- return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str());
- }
- }
- }
////////////////////////////////////////////////////////////////////////
// check listen for rtmp.
@@ -4075,6 +3923,63 @@ srs_error_t SrsConfig::check_number_connections()
}
// LCOV_EXCL_STOP
+srs_error_t SrsConfig::check_hybrids()
+{
+ srs_error_t err = srs_success;
+
+ // There MUST be at least one stream/hybrid.
+ int hybrids = get_threads_hybrids();
+ if (hybrids < 1) {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "hybrids MUST >=1, actual %d", hybrids);
+ }
+
+ // The number of hybrids MUST be equal to the streams.
+ vector streams;
+ for (int i = 0; i < (int)root->directives.size(); i++) {
+ SrsConfDirective* conf = root->at(i);
+ if (conf->name == "stream") {
+ streams.push_back(conf);
+ }
+ }
+
+ if (hybrids > (int)streams.size()) {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "hybrids=%d requires %d streams, actual=%d",
+ hybrids, (int)streams.size(), (int)streams.size());
+ }
+
+ // For each stream, the UDP listen MUST not be the same.
+ vector udp_ports;
+ for (int i = 0; i < (int)streams.size(); i++) {
+ int port = get_rtc_server_listen(i);
+ if (std::find(udp_ports.begin(), udp_ports.end(), port) != udp_ports.end()) {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "RTC port=%d duplicated", port);
+ }
+ udp_ports.push_back(port);
+ }
+
+ // TODO: FIXME: For edge, the RTMP/HTTP port is OK to be the same, but it's too complex.
+ // For each stream, the TCP listen MUST not be the same.
+ vector tcp_ports;
+ for (int i = 0; i < (int)streams.size(); i++) {
+ string port = get_http_stream_listen(i);
+ if (std::find(tcp_ports.begin(), tcp_ports.end(), port) != tcp_ports.end()) {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "HTTP port=%s duplicated", port.c_str());
+ }
+ tcp_ports.push_back(port);
+
+ vector ports = get_listens(i);
+ for (int j = 0; j < (int)ports.size(); j++) {
+ port = ports.at(j);
+ if (std::find(tcp_ports.begin(), tcp_ports.end(), port) != tcp_ports.end()) {
+ return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "RTMP port=%s duplicated", port.c_str());
+ }
+ tcp_ports.push_back(port);
+ }
+ }
+
+ return err;
+}
+
srs_error_t SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
{
srs_error_t err = srs_success;
@@ -4088,23 +3993,6 @@ srs_error_t SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
return srs_error_wrap(err, "root parse");
}
- // mock by dolphin mode.
- // for the dolphin will start srs with specified params.
- if (dolphin) {
- // for RTMP.
- set_config_directive(root, "listen", dolphin_rtmp_port);
-
- // for HTTP
- set_config_directive(root, "http_server", "");
- SrsConfDirective* http_server = root->get("http_server");
- set_config_directive(http_server, "enabled", "on");
- set_config_directive(http_server, "listen", dolphin_http_port);
-
- // others.
- set_config_directive(root, "daemon", "off");
- set_config_directive(root, "srs_log_tank", "console");
- }
-
return err;
}
@@ -4133,11 +4021,36 @@ SrsConfDirective* SrsConfig::get_root()
return root;
}
-int SrsConfig::get_max_connections()
+SrsConfDirective* SrsConfig::get_stream_at(int stream_index)
+{
+ int matched = 0;
+ for (int i = 0; i < (int)root->directives.size(); i++) {
+ SrsConfDirective* conf = root->at(i);
+
+ if (conf->name != "stream") {
+ continue;
+ }
+
+ if (matched++ != stream_index) {
+ continue;
+ }
+
+ return conf;
+ }
+
+ return NULL;
+}
+
+int SrsConfig::get_max_connections(int stream_index)
{
static int DEFAULT = 1000;
- SrsConfDirective* conf = root->get("max_connections");
+ SrsConfDirective* conf = get_stream_at(stream_index);
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("max_connections");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
@@ -4145,11 +4058,16 @@ int SrsConfig::get_max_connections()
return ::atoi(conf->arg0().c_str());
}
-vector SrsConfig::get_listens()
+vector SrsConfig::get_listens(int stream_index)
{
std::vector ports;
- SrsConfDirective* conf = root->get("listen");
+ SrsConfDirective* conf = get_stream_at(stream_index);
+ if (!conf) {
+ return ports;
+ }
+
+ conf = conf->get("listen");
if (!conf) {
return ports;
}
@@ -4321,6 +4239,222 @@ double SrsConfig::tcmalloc_release_rate()
return trr;
}
+srs_utime_t SrsConfig::get_threads_interval()
+{
+ static srs_utime_t DEFAULT = 5 * SRS_UTIME_SECONDS;
+
+ SrsConfDirective* conf = root->get("threads");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("interval");
+ if (!conf || conf->arg0().empty()) {
+ return DEFAULT;
+ }
+
+ int v = ::atoi(conf->arg0().c_str());
+ if (v <= 0) {
+ return DEFAULT;
+ }
+
+ return v * SRS_UTIME_SECONDS;
+}
+
+int SrsConfig::get_threads_hybrids()
+{
+ static int DEFAULT = 1;
+
+ SrsConfDirective* conf = root->get("threads");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("hybrids");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
+bool SrsConfig::get_threads_generate_stream()
+{
+ static bool DEFAULT = false;
+
+ SrsConfDirective* conf = root->get("threads");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("generate_streams");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return SRS_CONF_PERFER_FALSE(conf->arg0());
+}
+
+bool SrsConfig::get_threads_cpu_affinity(std::string label, int* start, int* end)
+{
+ static int DEFAULT_START = 0;
+ static int DEFAULT_END = 63;
+
+ *start = DEFAULT_START;
+ *end = DEFAULT_END;
+
+ SrsConfDirective* conf = root->get("threads");
+ if (!conf) {
+ return false;
+ }
+
+ conf = conf->get("cpu_affinity");
+ if (!conf) {
+ return false;
+ }
+
+ conf = conf->get(label);
+ if (!conf) {
+ return false;
+ }
+
+ string v = conf->arg0();
+ size_t pos = v.find("-");
+ if (pos == string::npos) {
+ *start = *end = ::atoi(v.c_str());
+ return true;
+ }
+
+ string sv = v.substr(0, pos);
+ string ev = v.substr(pos + 1);
+ if (!sv.empty()) {
+ *start = ::atoi(sv.c_str());
+ }
+ if (!ev.empty()) {
+ *end = ::atoi(ev.c_str());
+ }
+ return true;
+}
+
+bool SrsConfig::get_circuit_breaker()
+{
+ static bool DEFAULT = true;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("enabled");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return SRS_CONF_PERFER_TRUE(conf->arg0());
+}
+
+int SrsConfig::get_high_threshold()
+{
+ static int DEFAULT = 90;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("high_threshold");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
+int SrsConfig::get_high_pulse()
+{
+ static int DEFAULT = 2;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("high_pulse");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
+int SrsConfig::get_critical_threshold()
+{
+ static int DEFAULT = 95;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("critical_threshold");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
+int SrsConfig::get_critical_pulse()
+{
+ static int DEFAULT = 1;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("critical_pulse");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
+int SrsConfig::get_dying_threshold()
+{
+ static int DEFAULT = 99;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("dying_threshold");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
+int SrsConfig::get_dying_pulse()
+{
+ static int DEFAULT = 5;
+
+ SrsConfDirective* conf = root->get("circuit_breaker");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("dying_pulse");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return ::atoi(conf->arg0().c_str());
+}
+
vector SrsConfig::get_stream_casters()
{
srs_assert(root);
@@ -4748,9 +4882,19 @@ 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);
}
-bool SrsConfig::get_rtc_server_enabled()
+SrsConfDirective* SrsConfig::get_rtc_server_at(int stream_index)
+{
+ SrsConfDirective* conf = get_stream_at(stream_index);
+ if (!conf) {
+ return NULL;
+ }
+
+ return conf->get("rtc_server");
+}
+
+bool SrsConfig::get_rtc_server_enabled(int stream_index)
{
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
return get_rtc_server_enabled(conf);
}
@@ -4770,11 +4914,11 @@ bool SrsConfig::get_rtc_server_enabled(SrsConfDirective* conf)
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
-int SrsConfig::get_rtc_server_listen()
+int SrsConfig::get_rtc_server_listen(int stream_index)
{
static int DEFAULT = 8000;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4787,11 +4931,11 @@ int SrsConfig::get_rtc_server_listen()
return ::atoi(conf->arg0().c_str());
}
-std::string SrsConfig::get_rtc_server_candidates()
+std::string SrsConfig::get_rtc_server_candidates(int stream_index)
{
static string DEFAULT = "*";
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4814,11 +4958,11 @@ std::string SrsConfig::get_rtc_server_candidates()
return conf->arg0();
}
-std::string SrsConfig::get_rtc_server_ip_family()
+std::string SrsConfig::get_rtc_server_ip_family(int stream_index)
{
static string DEFAULT = "ipv4";
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4831,11 +4975,11 @@ std::string SrsConfig::get_rtc_server_ip_family()
return conf->arg0();
}
-bool SrsConfig::get_rtc_server_ecdsa()
+bool SrsConfig::get_rtc_server_ecdsa(int stream_index)
{
static bool DEFAULT = true;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4848,11 +4992,11 @@ bool SrsConfig::get_rtc_server_ecdsa()
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
-bool SrsConfig::get_rtc_server_encrypt()
+bool SrsConfig::get_rtc_server_encrypt(int stream_index)
{
static bool DEFAULT = true;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4865,9 +5009,9 @@ bool SrsConfig::get_rtc_server_encrypt()
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
-int SrsConfig::get_rtc_server_reuseport()
+int SrsConfig::get_rtc_server_reuseport(int stream_index)
{
- int v = get_rtc_server_reuseport2();
+ int v = get_rtc_server_reuseport2(stream_index);
#if !defined(SO_REUSEPORT)
if (v > 1) {
@@ -4879,11 +5023,11 @@ int SrsConfig::get_rtc_server_reuseport()
return v;
}
-int SrsConfig::get_rtc_server_reuseport2()
+int SrsConfig::get_rtc_server_reuseport2(int stream_index)
{
static int DEFAULT = 1;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4896,11 +5040,11 @@ int SrsConfig::get_rtc_server_reuseport2()
return ::atoi(conf->arg0().c_str());
}
-bool SrsConfig::get_rtc_server_merge_nalus()
+bool SrsConfig::get_rtc_server_merge_nalus(int stream_index)
{
static int DEFAULT = false;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4913,11 +5057,11 @@ bool SrsConfig::get_rtc_server_merge_nalus()
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
-bool SrsConfig::get_rtc_server_perf_stat()
+bool SrsConfig::get_rtc_server_perf_stat(int stream_index)
{
static bool DEFAULT = false;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4930,9 +5074,9 @@ bool SrsConfig::get_rtc_server_perf_stat()
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
-SrsConfDirective* SrsConfig::get_rtc_server_rtp_cache()
+SrsConfDirective* SrsConfig::get_rtc_server_rtp_cache(int stream_index)
{
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return NULL;
}
@@ -4945,11 +5089,11 @@ SrsConfDirective* SrsConfig::get_rtc_server_rtp_cache()
return conf;
}
-bool SrsConfig::get_rtc_server_rtp_cache_enabled()
+bool SrsConfig::get_rtc_server_rtp_cache_enabled(int stream_index)
{
static bool DEFAULT = true;
- SrsConfDirective* conf = get_rtc_server_rtp_cache();
+ SrsConfDirective* conf = get_rtc_server_rtp_cache(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4962,11 +5106,11 @@ bool SrsConfig::get_rtc_server_rtp_cache_enabled()
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
-uint64_t SrsConfig::get_rtc_server_rtp_cache_pkt_size()
+uint64_t SrsConfig::get_rtc_server_rtp_cache_pkt_size(int stream_index)
{
int DEFAULT = 64 * 1024 * 1024;
- SrsConfDirective* conf = get_rtc_server_rtp_cache();
+ SrsConfDirective* conf = get_rtc_server_rtp_cache(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4979,11 +5123,11 @@ uint64_t SrsConfig::get_rtc_server_rtp_cache_pkt_size()
return 1024 * (uint64_t)(1024 * ::atof(conf->arg0().c_str()));
}
-uint64_t SrsConfig::get_rtc_server_rtp_cache_payload_size()
+uint64_t SrsConfig::get_rtc_server_rtp_cache_payload_size(int stream_index)
{
int DEFAULT = 16 * 1024 * 1024;
- SrsConfDirective* conf = get_rtc_server_rtp_cache();
+ SrsConfDirective* conf = get_rtc_server_rtp_cache(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -4996,9 +5140,9 @@ uint64_t SrsConfig::get_rtc_server_rtp_cache_payload_size()
return 1024 * (uint64_t)(1024 * ::atof(conf->arg0().c_str()));
}
-SrsConfDirective* SrsConfig::get_rtc_server_rtp_msg_cache()
+SrsConfDirective* SrsConfig::get_rtc_server_rtp_msg_cache(int stream_index)
{
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return NULL;
}
@@ -5011,11 +5155,11 @@ SrsConfDirective* SrsConfig::get_rtc_server_rtp_msg_cache()
return conf;
}
-bool SrsConfig::get_rtc_server_rtp_msg_cache_enabled()
+bool SrsConfig::get_rtc_server_rtp_msg_cache_enabled(int stream_index)
{
static bool DEFAULT = true;
- SrsConfDirective* conf = get_rtc_server_rtp_msg_cache();
+ SrsConfDirective* conf = get_rtc_server_rtp_msg_cache(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -5028,11 +5172,11 @@ bool SrsConfig::get_rtc_server_rtp_msg_cache_enabled()
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
-uint64_t SrsConfig::get_rtc_server_rtp_msg_cache_msg_size()
+uint64_t SrsConfig::get_rtc_server_rtp_msg_cache_msg_size(int stream_index)
{
int DEFAULT = 16 * 1024 * 1024;
- SrsConfDirective* conf = get_rtc_server_rtp_msg_cache();
+ SrsConfDirective* conf = get_rtc_server_rtp_msg_cache(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -5045,11 +5189,11 @@ uint64_t SrsConfig::get_rtc_server_rtp_msg_cache_msg_size()
return 1024 * (uint64_t)(1024 * ::atof(conf->arg0().c_str()));
}
-uint64_t SrsConfig::get_rtc_server_rtp_msg_cache_buffer_size()
+uint64_t SrsConfig::get_rtc_server_rtp_msg_cache_buffer_size(int stream_index)
{
int DEFAULT = 512 * 1024 * 1024;
- SrsConfDirective* conf = get_rtc_server_rtp_msg_cache();
+ SrsConfDirective* conf = get_rtc_server_rtp_msg_cache(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -5062,11 +5206,11 @@ uint64_t SrsConfig::get_rtc_server_rtp_msg_cache_buffer_size()
return 1024 * (uint64_t)(1024 * ::atof(conf->arg0().c_str()));
}
-bool SrsConfig::get_rtc_server_black_hole()
+bool SrsConfig::get_rtc_server_black_hole(int stream_index)
{
static bool DEFAULT = false;
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -5084,11 +5228,11 @@ bool SrsConfig::get_rtc_server_black_hole()
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
-std::string SrsConfig::get_rtc_server_black_hole_addr()
+std::string SrsConfig::get_rtc_server_black_hole_addr(int stream_index)
{
static string DEFAULT = "";
- SrsConfDirective* conf = root->get("rtc_server");
+ SrsConfDirective* conf = get_rtc_server_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -7042,6 +7186,23 @@ string SrsConfig::get_log_file()
return conf->arg0();
}
+srs_utime_t SrsConfig::srs_log_flush_interval()
+{
+ srs_utime_t DEFAULT = 1300 * SRS_UTIME_MILLISECONDS;
+
+ SrsConfDirective* conf = root->get("srs_log_flush_interval");
+ if (!conf || conf->arg0().empty()) {
+ return DEFAULT;
+ }
+
+ srs_utime_t v = ::atoi(conf->arg0().c_str()) * SRS_UTIME_MILLISECONDS;
+ if (v <= 0) {
+ return DEFAULT;
+ }
+
+ return v;
+}
+
bool SrsConfig::get_ff_log_enabled()
{
string log = get_ff_log_dir();
@@ -8226,9 +8387,19 @@ string SrsConfig::get_default_app_name() {
return conf->arg0();
}
-bool SrsConfig::get_http_stream_enabled()
+SrsConfDirective* SrsConfig::get_http_stream_at(int stream_index)
+{
+ SrsConfDirective* conf = get_stream_at(stream_index);
+ if (!conf) {
+ return NULL;
+ }
+
+ return conf->get("http_server");
+}
+
+bool SrsConfig::get_http_stream_enabled(int stream_index)
{
- SrsConfDirective* conf = root->get("http_server");
+ SrsConfDirective* conf = get_http_stream_at(stream_index);
return get_http_stream_enabled(conf);
}
@@ -8248,11 +8419,11 @@ bool SrsConfig::get_http_stream_enabled(SrsConfDirective* conf)
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
-string SrsConfig::get_http_stream_listen()
+string SrsConfig::get_http_stream_listen(int stream_index)
{
static string DEFAULT = "8080";
- SrsConfDirective* conf = root->get("http_server");
+ SrsConfDirective* conf = get_http_stream_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -8265,11 +8436,11 @@ string SrsConfig::get_http_stream_listen()
return conf->arg0();
}
-string SrsConfig::get_http_stream_dir()
+string SrsConfig::get_http_stream_dir(int stream_index)
{
static string DEFAULT = "./objs/nginx/html";
- SrsConfDirective* conf = root->get("http_server");
+ SrsConfDirective* conf = get_http_stream_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -8282,11 +8453,11 @@ string SrsConfig::get_http_stream_dir()
return conf->arg0();
}
-bool SrsConfig::get_http_stream_crossdomain()
+bool SrsConfig::get_http_stream_crossdomain(int stream_index)
{
static bool DEFAULT = true;
- SrsConfDirective* conf = root->get("http_server");
+ SrsConfDirective* conf = get_http_stream_at(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -8299,9 +8470,9 @@ bool SrsConfig::get_http_stream_crossdomain()
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
-SrsConfDirective* SrsConfig::get_https_stream()
+SrsConfDirective* SrsConfig::get_https_stream(int stream_index)
{
- SrsConfDirective* conf = root->get("http_server");
+ SrsConfDirective* conf = get_http_stream_at(stream_index);
if (!conf) {
return NULL;
}
@@ -8309,11 +8480,11 @@ SrsConfDirective* SrsConfig::get_https_stream()
return conf->get("https");
}
-bool SrsConfig::get_https_stream_enabled()
+bool SrsConfig::get_https_stream_enabled(int stream_index)
{
static bool DEFAULT = false;
- SrsConfDirective* conf = get_https_stream();
+ SrsConfDirective* conf = get_https_stream(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -8326,11 +8497,11 @@ bool SrsConfig::get_https_stream_enabled()
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
-string SrsConfig::get_https_stream_listen()
+string SrsConfig::get_https_stream_listen(int stream_index)
{
static string DEFAULT = "8088";
- SrsConfDirective* conf = get_https_stream();
+ SrsConfDirective* conf = get_https_stream(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -8343,11 +8514,11 @@ string SrsConfig::get_https_stream_listen()
return conf->arg0();
}
-string SrsConfig::get_https_stream_ssl_key()
+string SrsConfig::get_https_stream_ssl_key(int stream_index)
{
static string DEFAULT = "./conf/server.key";
- SrsConfDirective* conf = get_https_stream();
+ SrsConfDirective* conf = get_https_stream(stream_index);
if (!conf) {
return DEFAULT;
}
@@ -8360,11 +8531,11 @@ string SrsConfig::get_https_stream_ssl_key()
return conf->arg0();
}
-string SrsConfig::get_https_stream_ssl_cert()
+string SrsConfig::get_https_stream_ssl_cert(int stream_index)
{
static string DEFAULT = "./conf/server.crt";
- SrsConfDirective* conf = get_https_stream();
+ SrsConfDirective* conf = get_https_stream(stream_index);
if (!conf) {
return DEFAULT;
}
diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp
index 9e6d848807..27db20f986 100644
--- a/trunk/src/app/srs_app_config.hpp
+++ b/trunk/src/app/srs_app_config.hpp
@@ -46,6 +46,7 @@ class SrsConfig;
class SrsRequest;
class SrsJsonArray;
class SrsConfDirective;
+class SrsThreadMutex;
/**
* whether the two vector actual equals, for instance,
@@ -137,8 +138,11 @@ extern std::string srs_config_bool2switch(std::string sbool);
// so we must transform the vhost directive anytime load the config.
// @param root the root directive to transform, in and out parameter.
extern srs_error_t srs_config_transform_vhost(SrsConfDirective* root);
+extern srs_error_t srs_config_transform_vhost2(SrsConfDirective* root);
+extern srs_error_t srs_config_generate_stream(SrsConfDirective* root, SrsConfDirective* tmpl, int nn);
-// @global config object.
+// TODO: FIXME: It should be thread-local or thread-safe.
+// TODO: FIXME: We should use channel to deliver changes of config.
extern SrsConfig* _srs_config;
// The config directive.
@@ -271,11 +275,6 @@ class SrsConfig
{
// user command
private:
- // Whether srs is run in dolphin mode.
- // @see https://github.com/ossrs/srs-dolphin
- bool dolphin;
- std::string dolphin_rtmp_port;
- std::string dolphin_http_port;
// Whether show help and exit.
bool show_help;
// Whether test config file and exit.
@@ -303,13 +302,10 @@ class SrsConfig
private:
// The reload subscribers, when reload, callback all handlers.
std::vector subscribes;
+ SrsThreadMutex* lock_;
public:
SrsConfig();
virtual ~SrsConfig();
- // dolphin
-public:
- // Whether srs is in dolphin mode.
- virtual bool is_dolphin();
// Reload
public:
// For reload handler to register itself,
@@ -367,16 +363,8 @@ class SrsConfig
virtual srs_error_t raw_set_chunk_size(std::string chunk_size, bool& applied);
// RAW set the global ffmpeg log dir.
virtual srs_error_t raw_set_ff_log_dir(std::string ff_log_dir, bool& applied);
- // RAW set the global log tank.
- virtual srs_error_t raw_set_srs_log_tank(std::string srs_log_tank, bool& applied);
- // RAW set the global log level.
- virtual srs_error_t raw_set_srs_log_level(std::string srs_log_level, bool& applied);
- // RAW set the global log file path for file tank.
- virtual srs_error_t raw_set_srs_log_file(std::string srs_log_file, bool& applied);
// RAW set the global max connections of srs.
virtual srs_error_t raw_set_max_connections(std::string max_connections, bool& applied);
- // RAW set the global whether use utc time.
- virtual srs_error_t raw_set_utc_time(std::string utc_time, bool& applied);
// RAW set the global pithy print interval in ms.
virtual srs_error_t raw_set_pithy_print_ms(std::string pithy_print_ms, bool& applied);
// RAW create the new vhost.
@@ -396,11 +384,7 @@ class SrsConfig
private:
virtual srs_error_t do_reload_listen();
virtual srs_error_t do_reload_pid();
- virtual srs_error_t do_reload_srs_log_tank();
- virtual srs_error_t do_reload_srs_log_level();
- virtual srs_error_t do_reload_srs_log_file();
virtual srs_error_t do_reload_max_connections();
- virtual srs_error_t do_reload_utc_time();
virtual srs_error_t do_reload_pithy_print_ms();
virtual srs_error_t do_reload_vhost_added(std::string vhost);
virtual srs_error_t do_reload_vhost_removed(std::string vhost);
@@ -421,6 +405,7 @@ class SrsConfig
protected:
virtual srs_error_t check_normal_config();
virtual srs_error_t check_number_connections();
+ virtual srs_error_t check_hybrids();
protected:
// Parse config from the buffer.
// @param buffer, the config buffer, user must delete it.
@@ -438,6 +423,8 @@ class SrsConfig
// The root directive, no name and args, contains directives.
// All directive parsed can retrieve from root.
virtual SrsConfDirective* get_root();
+ // Get the stream config at index.
+ virtual SrsConfDirective* get_stream_at(int index);
// Get the daemon config.
// If true, SRS will run in daemon mode, fork and fork to reap the
// grand-child process to init process.
@@ -448,11 +435,11 @@ class SrsConfig
// for example, when you need SRS to service 10000+ connections,
// user must use "ulimit -HSn 10000" and config the max connections
// of SRS.
- virtual int get_max_connections();
+ virtual int get_max_connections(int stream_index = 0);
// Get the listen port of SRS.
// user can specifies multiple listen ports,
// each args of directive is a listen port.
- virtual std::vector get_listens();
+ virtual std::vector get_listens(int stream_index = 0);
// Get the pid file path.
// The pid file is used to save the pid of SRS,
// use file lock to prevent multiple SRS starting.
@@ -487,6 +474,19 @@ class SrsConfig
virtual bool auto_reload_for_docker();
// For tcmalloc, get the release rate.
virtual double tcmalloc_release_rate();
+// Thread pool section.
+public:
+ virtual srs_utime_t get_threads_interval();
+ virtual int get_threads_hybrids();
+ virtual bool get_threads_generate_stream();
+ virtual bool get_threads_cpu_affinity(std::string label, int* start, int* end);
+ virtual bool get_circuit_breaker();
+ virtual int get_high_threshold();
+ virtual int get_high_pulse();
+ virtual int get_critical_threshold();
+ virtual int get_critical_pulse();
+ virtual int get_dying_threshold();
+ virtual int get_dying_pulse();
// stream_caster section
public:
// Get all stream_caster in config file.
@@ -523,34 +523,37 @@ class SrsConfig
virtual srs_utime_t get_stream_caster_gb28181_sip_query_catalog_interval(SrsConfDirective* conf);
// rtc section
+private:
+ // Get the RTC server config at index.
+ SrsConfDirective* get_rtc_server_at(int index);
public:
- virtual bool get_rtc_server_enabled();
+ virtual bool get_rtc_server_enabled(int stream_index = 0);
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 bool get_rtc_server_encrypt();
- virtual int get_rtc_server_reuseport();
- virtual bool get_rtc_server_merge_nalus();
- virtual bool get_rtc_server_perf_stat();
+ virtual int get_rtc_server_listen(int stream_index = 0);
+ virtual std::string get_rtc_server_candidates(int stream_index = 0);
+ virtual std::string get_rtc_server_ip_family(int stream_index = 0);
+ virtual bool get_rtc_server_ecdsa(int stream_index = 0);
+ virtual bool get_rtc_server_encrypt(int stream_index = 0);
+ virtual int get_rtc_server_reuseport(int stream_index = 0);
+ virtual bool get_rtc_server_merge_nalus(int stream_index = 0);
+ virtual bool get_rtc_server_perf_stat(int stream_index = 0);
private:
- SrsConfDirective* get_rtc_server_rtp_cache();
+ SrsConfDirective* get_rtc_server_rtp_cache(int stream_index = 0);
public:
- virtual bool get_rtc_server_rtp_cache_enabled();
- virtual uint64_t get_rtc_server_rtp_cache_pkt_size();
- virtual uint64_t get_rtc_server_rtp_cache_payload_size();
+ virtual bool get_rtc_server_rtp_cache_enabled(int stream_index = 0);
+ virtual uint64_t get_rtc_server_rtp_cache_pkt_size(int stream_index = 0);
+ virtual uint64_t get_rtc_server_rtp_cache_payload_size(int stream_index = 0);
private:
- virtual SrsConfDirective* get_rtc_server_rtp_msg_cache();
+ virtual SrsConfDirective* get_rtc_server_rtp_msg_cache(int stream_index = 0);
public:
- virtual bool get_rtc_server_rtp_msg_cache_enabled();
- virtual uint64_t get_rtc_server_rtp_msg_cache_msg_size();
- virtual uint64_t get_rtc_server_rtp_msg_cache_buffer_size();
+ virtual bool get_rtc_server_rtp_msg_cache_enabled(int stream_index = 0);
+ virtual uint64_t get_rtc_server_rtp_msg_cache_msg_size(int stream_index = 0);
+ virtual uint64_t get_rtc_server_rtp_msg_cache_buffer_size(int stream_index = 0);
public:
- virtual bool get_rtc_server_black_hole();
- virtual std::string get_rtc_server_black_hole_addr();
+ virtual bool get_rtc_server_black_hole(int stream_index = 0);
+ virtual std::string get_rtc_server_black_hole_addr(int stream_index = 0);
private:
- virtual int get_rtc_server_reuseport2();
+ virtual int get_rtc_server_reuseport2(int stream_index = 0);
public:
SrsConfDirective* get_rtc(std::string vhost);
@@ -903,6 +906,8 @@ class SrsConfig
virtual std::string get_log_level();
// Get the log file path.
virtual std::string get_log_file();
+ // Get the interval in ms to flush async log.
+ virtual srs_utime_t srs_log_flush_interval();
// Whether ffmpeg log enabled
virtual bool get_ff_log_enabled();
// The ffmpeg log dir.
@@ -1046,26 +1051,29 @@ class SrsConfig
virtual std::string get_https_api_ssl_cert();
// http stream section
private:
+ // Get the HTTP stream config at index.
+ SrsConfDirective* get_http_stream_at(int index);
// Whether http stream enabled.
virtual bool get_http_stream_enabled(SrsConfDirective* conf);
public:
// Whether http stream enabled.
// TODO: FIXME: rename to http_static.
- virtual bool get_http_stream_enabled();
+ virtual bool get_http_stream_enabled(int stream_index = 0);
// Get the http stream listen port.
- virtual std::string get_http_stream_listen();
+ virtual std::string get_http_stream_listen(int stream_index = 0);
// Get the http stream root dir.
- virtual std::string get_http_stream_dir();
+ virtual std::string get_http_stream_dir(int stream_index = 0);
// Whether enable crossdomain for http static and stream server.
- virtual bool get_http_stream_crossdomain();
+ virtual bool get_http_stream_crossdomain(int stream_index = 0);
// https api section
private:
- SrsConfDirective* get_https_stream();
+ // Get the HTTPS stream config at index.
+ SrsConfDirective* get_https_stream(int index);
public:
- virtual bool get_https_stream_enabled();
- virtual std::string get_https_stream_listen();
- virtual std::string get_https_stream_ssl_key();
- virtual std::string get_https_stream_ssl_cert();
+ virtual bool get_https_stream_enabled(int stream_index = 0);
+ virtual std::string get_https_stream_listen(int stream_index = 0);
+ virtual std::string get_https_stream_ssl_key(int stream_index = 0);
+ virtual std::string get_https_stream_ssl_cert(int stream_index = 0);
public:
// Get whether vhost enabled http stream
virtual bool get_vhost_http_enabled(std::string vhost);
diff --git a/trunk/src/app/srs_app_conn.cpp b/trunk/src/app/srs_app_conn.cpp
index 42534c0238..56fccd4e4b 100644
--- a/trunk/src/app/srs_app_conn.cpp
+++ b/trunk/src/app/srs_app_conn.cpp
@@ -38,10 +38,10 @@ using namespace std;
#include
-SrsPps* _srs_pps_ids = new SrsPps();
-SrsPps* _srs_pps_fids = new SrsPps();
-SrsPps* _srs_pps_fids_level0 = new SrsPps();
-SrsPps* _srs_pps_dispose = new SrsPps();
+__thread SrsPps* _srs_pps_ids = NULL;
+__thread SrsPps* _srs_pps_fids = NULL;
+__thread SrsPps* _srs_pps_fids_level0 = NULL;
+__thread SrsPps* _srs_pps_dispose = NULL;
ISrsDisposingHandler::ISrsDisposingHandler()
{
diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp
index fdc421fbeb..d09ddc8e20 100644
--- a/trunk/src/app/srs_app_gb28181.hpp
+++ b/trunk/src/app/srs_app_gb28181.hpp
@@ -501,7 +501,7 @@ class SrsGb28181StreamChannel
};
-// Global singleton instance.
+// TODO: FIXME: It should be thread-local or thread-safe.
extern SrsGb28181Manger* _srs_gb28181;
//gb28181 module management, management of all RTMP multiplexers,
diff --git a/trunk/src/app/srs_app_hourglass.cpp b/trunk/src/app/srs_app_hourglass.cpp
index 16bd200e65..c54f546e00 100644
--- a/trunk/src/app/srs_app_hourglass.cpp
+++ b/trunk/src/app/srs_app_hourglass.cpp
@@ -32,17 +32,17 @@ using namespace std;
#include
-SrsPps* _srs_pps_timer = new SrsPps();
-
-extern SrsPps* _srs_pps_clock_15ms;
-extern SrsPps* _srs_pps_clock_20ms;
-extern SrsPps* _srs_pps_clock_25ms;
-extern SrsPps* _srs_pps_clock_30ms;
-extern SrsPps* _srs_pps_clock_35ms;
-extern SrsPps* _srs_pps_clock_40ms;
-extern SrsPps* _srs_pps_clock_80ms;
-extern SrsPps* _srs_pps_clock_160ms;
-extern SrsPps* _srs_pps_timer_s;
+__thread SrsPps* _srs_pps_timer = NULL;
+
+extern __thread SrsPps* _srs_pps_clock_15ms;
+extern __thread SrsPps* _srs_pps_clock_20ms;
+extern __thread SrsPps* _srs_pps_clock_25ms;
+extern __thread SrsPps* _srs_pps_clock_30ms;
+extern __thread SrsPps* _srs_pps_clock_35ms;
+extern __thread SrsPps* _srs_pps_clock_40ms;
+extern __thread SrsPps* _srs_pps_clock_80ms;
+extern __thread SrsPps* _srs_pps_clock_160ms;
+extern __thread SrsPps* _srs_pps_timer_s;
ISrsHourGlass::ISrsHourGlass()
{
diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp
index 1a720d0f60..35619a46f7 100644
--- a/trunk/src/app/srs_app_http_api.cpp
+++ b/trunk/src/app/srs_app_http_api.cpp
@@ -1083,36 +1083,6 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
srs_error_reset(err);
return srs_api_response_code(w, r, code);
}
- } else if (scope == "srs_log_tank") {
- if (value.empty() || (value != "file" && value != "console")) {
- return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_PARAMS);
- }
-
- if ((err = _srs_config->raw_set_srs_log_tank(value, applied)) != srs_success) {
- int code = srs_error_code(err);
- srs_error_reset(err);
- return srs_api_response_code(w, r, code);
- }
- } else if (scope == "srs_log_level") {
- if (value != "verbose" && value != "info" && value != "trace" && value != "warn" && value != "error") {
- return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_PARAMS);
- }
-
- if ((err = _srs_config->raw_set_srs_log_level(value, applied)) != srs_success) {
- int code = srs_error_code(err);
- srs_error_reset(err);
- return srs_api_response_code(w, r, code);
- }
- } else if (scope == "srs_log_file") {
- if (value.empty() || !srs_string_starts_with(value, "./", "/tmp/", "/var/") || !srs_string_ends_with(value, ".log")) {
- return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_PARAMS);
- }
-
- if ((err = _srs_config->raw_set_srs_log_file(value, applied)) != srs_success) {
- int code = srs_error_code(err);
- srs_error_reset(err);
- return srs_api_response_code(w, r, code);
- }
} else if (scope == "max_connections") {
int mcv = ::atoi(value.c_str());
if (mcv < 10 || mcv > 65535 || !srs_is_digit_number(value)) {
@@ -1124,14 +1094,6 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage*
srs_error_reset(err);
return srs_api_response_code(w, r, code);
}
- } else if (scope == "utc_time") {
- if (!srs_is_boolean(value)) {
- return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_PARAMS);
- }
-
- if ((err = _srs_config->raw_set_utc_time(srs_config_bool2switch(value), applied)) != srs_success) {
- return srs_api_response_code(w, r, srs_error_wrap(err, "raw api update utc_time=%s", value.c_str()));
- }
} else if (scope == "pithy_print_ms") {
int ppmv = ::atoi(value.c_str());
if (ppmv < 100 || ppmv > 300000 || !srs_is_digit_number(value)) {
diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp
index 0d878d6583..564d019057 100644
--- a/trunk/src/app/srs_app_hybrid.cpp
+++ b/trunk/src/app/srs_app_hybrid.cpp
@@ -28,106 +28,108 @@
#include
#include
#include
+#include
+#include
using namespace std;
-extern SrsPps* _srs_pps_cids_get;
-extern SrsPps* _srs_pps_cids_set;
+extern __thread SrsPps* _srs_pps_cids_get;
+extern __thread SrsPps* _srs_pps_cids_set;
-extern SrsPps* _srs_pps_timer;
-extern SrsPps* _srs_pps_pub;
-extern SrsPps* _srs_pps_conn;
-extern SrsPps* _srs_pps_dispose;
+extern __thread SrsPps* _srs_pps_timer;
+extern __thread SrsPps* _srs_pps_pub;
+extern __thread SrsPps* _srs_pps_conn;
+extern __thread SrsPps* _srs_pps_dispose;
#if defined(SRS_DEBUG) && defined(SRS_DEBUG_STATS)
-extern unsigned long long _st_stat_recvfrom;
-extern unsigned long long _st_stat_recvfrom_eagain;
-extern unsigned long long _st_stat_sendto;
-extern unsigned long long _st_stat_sendto_eagain;
-SrsPps* _srs_pps_recvfrom = new SrsPps();
-SrsPps* _srs_pps_recvfrom_eagain = new SrsPps();
-SrsPps* _srs_pps_sendto = new SrsPps();
-SrsPps* _srs_pps_sendto_eagain = new SrsPps();
-
-extern unsigned long long _st_stat_read;
-extern unsigned long long _st_stat_read_eagain;
-extern unsigned long long _st_stat_readv;
-extern unsigned long long _st_stat_readv_eagain;
-extern unsigned long long _st_stat_writev;
-extern unsigned long long _st_stat_writev_eagain;
-SrsPps* _srs_pps_read = new SrsPps();
-SrsPps* _srs_pps_read_eagain = new SrsPps();
-SrsPps* _srs_pps_readv = new SrsPps();
-SrsPps* _srs_pps_readv_eagain = new SrsPps();
-SrsPps* _srs_pps_writev = new SrsPps();
-SrsPps* _srs_pps_writev_eagain = new SrsPps();
-
-extern unsigned long long _st_stat_recvmsg;
-extern unsigned long long _st_stat_recvmsg_eagain;
-extern unsigned long long _st_stat_sendmsg;
-extern unsigned long long _st_stat_sendmsg_eagain;
-SrsPps* _srs_pps_recvmsg = new SrsPps();
-SrsPps* _srs_pps_recvmsg_eagain = new SrsPps();
-SrsPps* _srs_pps_sendmsg = new SrsPps();
-SrsPps* _srs_pps_sendmsg_eagain = new SrsPps();
-
-extern unsigned long long _st_stat_epoll;
-extern unsigned long long _st_stat_epoll_zero;
-extern unsigned long long _st_stat_epoll_shake;
-extern unsigned long long _st_stat_epoll_spin;
-SrsPps* _srs_pps_epoll = new SrsPps();
-SrsPps* _srs_pps_epoll_zero = new SrsPps();
-SrsPps* _srs_pps_epoll_shake = new SrsPps();
-SrsPps* _srs_pps_epoll_spin = new SrsPps();
-
-extern unsigned long long _st_stat_sched_15ms;
-extern unsigned long long _st_stat_sched_20ms;
-extern unsigned long long _st_stat_sched_25ms;
-extern unsigned long long _st_stat_sched_30ms;
-extern unsigned long long _st_stat_sched_35ms;
-extern unsigned long long _st_stat_sched_40ms;
-extern unsigned long long _st_stat_sched_80ms;
-extern unsigned long long _st_stat_sched_160ms;
-extern unsigned long long _st_stat_sched_s;
-SrsPps* _srs_pps_sched_15ms = new SrsPps();
-SrsPps* _srs_pps_sched_20ms = new SrsPps();
-SrsPps* _srs_pps_sched_25ms = new SrsPps();
-SrsPps* _srs_pps_sched_30ms = new SrsPps();
-SrsPps* _srs_pps_sched_35ms = new SrsPps();
-SrsPps* _srs_pps_sched_40ms = new SrsPps();
-SrsPps* _srs_pps_sched_80ms = new SrsPps();
-SrsPps* _srs_pps_sched_160ms = new SrsPps();
-SrsPps* _srs_pps_sched_s = new SrsPps();
+extern __thread unsigned long long _st_stat_recvfrom;
+extern __thread unsigned long long _st_stat_recvfrom_eagain;
+extern __thread unsigned long long _st_stat_sendto;
+extern __thread unsigned long long _st_stat_sendto_eagain;
+__thread SrsPps* _srs_pps_recvfrom = NULL;
+__thread SrsPps* _srs_pps_recvfrom_eagain = NULL;
+__thread SrsPps* _srs_pps_sendto = NULL;
+__thread SrsPps* _srs_pps_sendto_eagain = NULL;
+
+extern __thread unsigned long long _st_stat_read;
+extern __thread unsigned long long _st_stat_read_eagain;
+extern __thread unsigned long long _st_stat_readv;
+extern __thread unsigned long long _st_stat_readv_eagain;
+extern __thread unsigned long long _st_stat_writev;
+extern __thread unsigned long long _st_stat_writev_eagain;
+__thread SrsPps* _srs_pps_read = NULL;
+__thread SrsPps* _srs_pps_read_eagain = NULL;
+__thread SrsPps* _srs_pps_readv = NULL;
+__thread SrsPps* _srs_pps_readv_eagain = NULL;
+__thread SrsPps* _srs_pps_writev = NULL;
+__thread SrsPps* _srs_pps_writev_eagain = NULL;
+
+extern __thread unsigned long long _st_stat_recvmsg;
+extern __thread unsigned long long _st_stat_recvmsg_eagain;
+extern __thread unsigned long long _st_stat_sendmsg;
+extern __thread unsigned long long _st_stat_sendmsg_eagain;
+__thread SrsPps* _srs_pps_recvmsg = NULL;
+__thread SrsPps* _srs_pps_recvmsg_eagain = NULL;
+__thread SrsPps* _srs_pps_sendmsg = NULL;
+__thread SrsPps* _srs_pps_sendmsg_eagain = NULL;
+
+extern __thread unsigned long long _st_stat_epoll;
+extern __thread unsigned long long _st_stat_epoll_zero;
+extern __thread unsigned long long _st_stat_epoll_shake;
+extern __thread unsigned long long _st_stat_epoll_spin;
+__thread SrsPps* _srs_pps_epoll = NULL;
+__thread SrsPps* _srs_pps_epoll_zero = NULL;
+__thread SrsPps* _srs_pps_epoll_shake = NULL;
+__thread SrsPps* _srs_pps_epoll_spin = NULL;
+
+extern __thread unsigned long long _st_stat_sched_15ms;
+extern __thread unsigned long long _st_stat_sched_20ms;
+extern __thread unsigned long long _st_stat_sched_25ms;
+extern __thread unsigned long long _st_stat_sched_30ms;
+extern __thread unsigned long long _st_stat_sched_35ms;
+extern __thread unsigned long long _st_stat_sched_40ms;
+extern __thread unsigned long long _st_stat_sched_80ms;
+extern __thread unsigned long long _st_stat_sched_160ms;
+extern __thread unsigned long long _st_stat_sched_s;
+__thread SrsPps* _srs_pps_sched_15ms = NULL;
+__thread SrsPps* _srs_pps_sched_20ms = NULL;
+__thread SrsPps* _srs_pps_sched_25ms = NULL;
+__thread SrsPps* _srs_pps_sched_30ms = NULL;
+__thread SrsPps* _srs_pps_sched_35ms = NULL;
+__thread SrsPps* _srs_pps_sched_40ms = NULL;
+__thread SrsPps* _srs_pps_sched_80ms = NULL;
+__thread SrsPps* _srs_pps_sched_160ms = NULL;
+__thread SrsPps* _srs_pps_sched_s = NULL;
#endif
-SrsPps* _srs_pps_clock_15ms = new SrsPps();
-SrsPps* _srs_pps_clock_20ms = new SrsPps();
-SrsPps* _srs_pps_clock_25ms = new SrsPps();
-SrsPps* _srs_pps_clock_30ms = new SrsPps();
-SrsPps* _srs_pps_clock_35ms = new SrsPps();
-SrsPps* _srs_pps_clock_40ms = new SrsPps();
-SrsPps* _srs_pps_clock_80ms = new SrsPps();
-SrsPps* _srs_pps_clock_160ms = new SrsPps();
-SrsPps* _srs_pps_timer_s = new SrsPps();
+__thread SrsPps* _srs_pps_clock_15ms = NULL;
+__thread SrsPps* _srs_pps_clock_20ms = NULL;
+__thread SrsPps* _srs_pps_clock_25ms = NULL;
+__thread SrsPps* _srs_pps_clock_30ms = NULL;
+__thread SrsPps* _srs_pps_clock_35ms = NULL;
+__thread SrsPps* _srs_pps_clock_40ms = NULL;
+__thread SrsPps* _srs_pps_clock_80ms = NULL;
+__thread SrsPps* _srs_pps_clock_160ms = NULL;
+__thread SrsPps* _srs_pps_timer_s = NULL;
#if defined(SRS_DEBUG) && defined(SRS_DEBUG_STATS)
-extern int _st_active_count;
-extern unsigned long long _st_stat_thread_run;
-extern unsigned long long _st_stat_thread_idle;
-extern unsigned long long _st_stat_thread_yield;
-extern unsigned long long _st_stat_thread_yield2;
-SrsPps* _srs_pps_thread_run = new SrsPps();
-SrsPps* _srs_pps_thread_idle = new SrsPps();
-SrsPps* _srs_pps_thread_yield = new SrsPps();
-SrsPps* _srs_pps_thread_yield2 = new SrsPps();
+extern __thread int _st_active_count;
+extern __thread unsigned long long _st_stat_thread_run;
+extern __thread unsigned long long _st_stat_thread_idle;
+extern __thread unsigned long long _st_stat_thread_yield;
+extern __thread unsigned long long _st_stat_thread_yield2;
+__thread SrsPps* _srs_pps_thread_run = NULL;
+__thread SrsPps* _srs_pps_thread_idle = NULL;
+__thread SrsPps* _srs_pps_thread_yield = NULL;
+__thread SrsPps* _srs_pps_thread_yield2 = NULL;
#endif
-extern SrsPps* _srs_pps_objs_rtps;
-extern SrsPps* _srs_pps_objs_rraw;
-extern SrsPps* _srs_pps_objs_rfua;
-extern SrsPps* _srs_pps_objs_rbuf;
-extern SrsPps* _srs_pps_objs_msgs;
-extern SrsPps* _srs_pps_objs_rothers;
+extern __thread SrsPps* _srs_pps_objs_rtps;
+extern __thread SrsPps* _srs_pps_objs_rraw;
+extern __thread SrsPps* _srs_pps_objs_rfua;
+extern __thread SrsPps* _srs_pps_objs_rbuf;
+extern __thread SrsPps* _srs_pps_objs_msgs;
+extern __thread SrsPps* _srs_pps_objs_rothers;
ISrsHybridServer::ISrsHybridServer()
{
@@ -145,6 +147,8 @@ SrsHybridServer::SrsHybridServer()
timer5s_ = NULL;
clock_monitor_ = new SrsClockWallMonitor();
+
+ stream_index_ = -1;
}
SrsHybridServer::~SrsHybridServer()
@@ -170,11 +174,6 @@ srs_error_t SrsHybridServer::initialize()
{
srs_error_t err = srs_success;
- // init st
- if ((err = srs_st_init()) != srs_success) {
- return srs_error_wrap(err, "initialize st failed");
- }
-
// Create global shared timer.
timer20ms_ = new SrsFastTimer("hybrid", 20 * SRS_UTIME_MILLISECONDS);
timer100ms_ = new SrsFastTimer("hybrid", 100 * SRS_UTIME_MILLISECONDS);
@@ -212,6 +211,19 @@ srs_error_t SrsHybridServer::initialize()
}
}
+ // Create slots for other threads to communicate with us.
+ SrsThreadEntry* self = _srs_thread_pool->self();
+
+ self->slot_ = new SrsThreadPipeSlot(1);
+
+ if ((err = self->slot_->initialize()) != srs_success) {
+ return srs_error_wrap(err, "init slot");
+ }
+
+ if ((err = self->slot_->open_responder(this)) != srs_success) {
+ return srs_error_wrap(err, "init slot");
+ }
+
return err;
}
@@ -219,6 +231,7 @@ srs_error_t SrsHybridServer::run()
{
srs_error_t err = srs_success;
+ // Run all servers, which should never block.
vector::iterator it;
for (it = servers.begin(); it != servers.end(); ++it) {
ISrsHybridServer* server = *it;
@@ -228,7 +241,7 @@ srs_error_t SrsHybridServer::run()
}
}
- // Wait for all server to quit.
+ // Wait util quit.
srs_usleep(SRS_UTIME_NO_TIMEOUT);
return err;
@@ -409,5 +422,57 @@ srs_error_t SrsHybridServer::on_timer(srs_utime_t interval)
return err;
}
-SrsHybridServer* _srs_hybrid = new SrsHybridServer();
+srs_error_t SrsHybridServer::on_thread_message(SrsThreadMessage* msg, SrsThreadPipeChannel* channel)
+{
+ srs_error_t err = srs_success;
+
+ RtcServerAdapter* adapter = NULL;
+ if (true) {
+ vector servers = _srs_hybrid->servers;
+ for (vector::iterator it = servers.begin(); it != servers.end(); ++it) {
+ RtcServerAdapter* server = dynamic_cast(*it);
+ if (server) {
+ adapter = server;
+ break;
+ }
+ }
+ }
+
+ if (!adapter) {
+ // TODO: FIXME: Response with error information?
+ srs_error_t r0 = channel->responder()->write(msg, sizeof(SrsThreadMessage), NULL);
+ srs_freep(r0); // Always response it, ignore any error.
+
+ return err;
+ }
+
+ if (msg->id == (uint64_t)SrsThreadMessageIDRtcCreateSession) {
+ SrsThreadMessageRtcCreateSession* s = (SrsThreadMessageRtcCreateSession*)msg->ptr;
+ err = adapter->rtc->create_session(s->ruc, *s->local_sdp, &s->session);
+
+ if (err != srs_success) {
+ // TODO: FIXME: Response with error information?
+ srs_error_t r0 = channel->responder()->write(msg, sizeof(SrsThreadMessage), NULL);
+ srs_freep(r0); // Always response it, ignore any error.
+
+ return srs_error_wrap(err, "create session");
+ }
+
+ // TODO: FIXME: Response timeout if error?
+ // TODO: FIXME: Response a different message? With trace ID?
+ // We're responder, write response to responder.
+ err = channel->responder()->write(msg, sizeof(SrsThreadMessage), NULL);
+ if (err != srs_success) {
+ return srs_error_wrap(err, "response");
+ }
+ } else {
+ // TODO: FIXME: Response with error information?
+ srs_error_t r0 = channel->responder()->write(msg, sizeof(SrsThreadMessage), NULL);
+ srs_freep(r0); // Always response it, ignore any error.
+ }
+
+ return err;
+}
+
+ __thread SrsHybridServer* _srs_hybrid = NULL;
diff --git a/trunk/src/app/srs_app_hybrid.hpp b/trunk/src/app/srs_app_hybrid.hpp
index 729f00016d..514b5f4529 100644
--- a/trunk/src/app/srs_app_hybrid.hpp
+++ b/trunk/src/app/srs_app_hybrid.hpp
@@ -29,6 +29,7 @@
#include
#include
+#include
class SrsServer;
class SrsServerAdapter;
@@ -49,7 +50,7 @@ class ISrsHybridServer
};
// The hybrid server manager.
-class SrsHybridServer : public ISrsFastTimer
+class SrsHybridServer : public ISrsFastTimer, public ISrsThreadResponder
{
private:
std::vector servers;
@@ -58,11 +59,17 @@ class SrsHybridServer : public ISrsFastTimer
SrsFastTimer* timer1s_;
SrsFastTimer* timer5s_;
SrsClockWallMonitor* clock_monitor_;
+private:
+ // The config index for hybrid/stream server.
+ int stream_index_;
public:
SrsHybridServer();
virtual ~SrsHybridServer();
public:
virtual void register_server(ISrsHybridServer* svr);
+public:
+ int stream_index() { return stream_index_; } // SrsHybridServer::stream_index()
+ void set_stream_index(int v) { stream_index_ = v; } // SrsHybridServer::set_stream_index()
public:
virtual srs_error_t initialize();
virtual srs_error_t run();
@@ -76,8 +83,10 @@ class SrsHybridServer : public ISrsFastTimer
// interface ISrsFastTimer
private:
srs_error_t on_timer(srs_utime_t interval);
+private:
+ srs_error_t on_thread_message(SrsThreadMessage* msg, SrsThreadPipeChannel* channel);
};
-extern SrsHybridServer* _srs_hybrid;
+extern __thread SrsHybridServer* _srs_hybrid;
#endif
diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp
index 0037a6d9c7..fb38d5bae2 100755
--- a/trunk/src/app/srs_app_listener.cpp
+++ b/trunk/src/app/srs_app_listener.cpp
@@ -42,17 +42,19 @@ using namespace std;
#include
#include
#include
+#include
+#include
#include
-SrsPps* _srs_pps_rpkts = new SrsPps();
-SrsPps* _srs_pps_addrs = new SrsPps();
-SrsPps* _srs_pps_fast_addrs = new SrsPps();
+__thread SrsPps* _srs_pps_rpkts = NULL;
+__thread SrsPps* _srs_pps_addrs = NULL;
+__thread SrsPps* _srs_pps_fast_addrs = NULL;
-SrsPps* _srs_pps_spkts = new SrsPps();
+__thread SrsPps* _srs_pps_spkts = NULL;
// set the max packet size.
-#define SRS_UDP_MAX_PACKET_SIZE 65535
+const int SRS_UDP_MAX_PACKET_SIZE = 1500;
// sleep in srs_utime_t for udp recv packet.
#define SrsUdpPacketRecvCycleInterval 0
@@ -300,6 +302,7 @@ SrsUdpMuxSocket::SrsUdpMuxSocket(srs_netfd_t fd)
nread = 0;
lfd = fd;
+ handler_ = NULL;
fromlen = 0;
peer_port = 0;
@@ -323,6 +326,11 @@ int SrsUdpMuxSocket::recvfrom(srs_utime_t timeout)
return nread;
}
+ return on_recvfrom();
+}
+
+int SrsUdpMuxSocket::on_recvfrom()
+{
// Reset the fast cache buffer size.
cache_buffer_->set_size(nread);
cache_buffer_->skip(-1 * cache_buffer_->pos());
@@ -361,8 +369,8 @@ srs_error_t SrsUdpMuxSocket::sendto(void* data, int size, srs_utime_t timeout)
if (nb_write <= 0) {
if (nb_write < 0 && errno == ETIME) {
return srs_error_new(ERROR_SOCKET_TIMEOUT, "sendto timeout %d ms", srsu2msi(timeout));
- }
-
+ }
+
return srs_error_new(ERROR_SOCKET_WRITE, "sendto");
}
@@ -491,9 +499,42 @@ SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly()
sendonly->fast_id_ = fast_id_;
sendonly->address_changed_ = address_changed_;
+ sendonly->handler_ = handler_;
+
return sendonly;
}
+SrsUdpMuxSocket* SrsUdpMuxSocket::copy()
+{
+ SrsUdpMuxSocket* cp = new SrsUdpMuxSocket(lfd);
+
+ cp->nb_buf = nb_buf;
+ if (nread) {
+ memcpy(cp->buf, buf, nread);
+ }
+ cp->nread = nread;
+ cp->lfd = lfd;
+ cp->from = from;
+ cp->fromlen = fromlen;
+ cp->peer_ip = peer_ip;
+ cp->peer_port = peer_port;
+
+ // Copy the fast id.
+ cp->peer_id_ = peer_id_;
+ cp->fast_id_ = fast_id_;
+ cp->address_changed_ = address_changed_;
+
+ if (nread) {
+ // Reset the fast cache buffer size.
+ cp->cache_buffer_->set_size(nread);
+ cp->cache_buffer_->skip(-1 * cache_buffer_->pos());
+ }
+
+ cp->handler_ = handler_;
+
+ return cp;
+}
+
SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p)
{
handler = h;
diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp
index e3ba3e975b..54de6b30e0 100644
--- a/trunk/src/app/srs_app_listener.hpp
+++ b/trunk/src/app/srs_app_listener.hpp
@@ -162,9 +162,20 @@ class SrsUdpMuxSocket
public:
SrsUdpMuxSocket(srs_netfd_t fd);
virtual ~SrsUdpMuxSocket();
+private:
+ ISrsUdpMuxHandler* handler_;
+public:
+ // SrsUdpMuxSocket::set_handler
+ void set_handler(ISrsUdpMuxHandler* h) { handler_ = h; }
+ // SrsUdpMuxSocket::handler
+ ISrsUdpMuxHandler* handler() { return handler_; }
public:
int recvfrom(srs_utime_t timeout);
+private:
+ int on_recvfrom();
+public:
srs_error_t sendto(void* data, int size, srs_utime_t timeout);
+public:
srs_netfd_t stfd();
sockaddr_in* peer_addr();
socklen_t peer_addrlen();
@@ -176,6 +187,8 @@ class SrsUdpMuxSocket
uint64_t fast_id();
SrsBuffer* buffer();
SrsUdpMuxSocket* copy_sendonly();
+public:
+ SrsUdpMuxSocket* copy();
};
class SrsUdpMuxListener : public ISrsCoroutineHandler
diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp
index 28ff755ef1..6e1a62e011 100644
--- a/trunk/src/app/srs_app_log.cpp
+++ b/trunk/src/app/srs_app_log.cpp
@@ -30,68 +30,64 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
// the max size of a line of log.
-#define LOG_MAX_SIZE 8192
+int LOG_MAX_SIZE = 8192;
// the tail append to each log.
#define LOG_TAIL '\n'
// reserved for the end of log data, it must be strlen(LOG_TAIL)
#define LOG_TAIL_SIZE 1
+// Thread local log cache.
+__thread char* _srs_log_data = NULL;
+
SrsFileLog::SrsFileLog()
{
level = SrsLogLevelTrace;
- log_data = new char[LOG_MAX_SIZE];
-
- fd = -1;
log_to_file_tank = false;
utc = false;
+
+ writer_ = NULL;
}
SrsFileLog::~SrsFileLog()
{
- srs_freepa(log_data);
-
- if (fd > 0) {
- ::close(fd);
- fd = -1;
- }
-
- if (_srs_config) {
- _srs_config->unsubscribe(this);
- }
}
+// @remark Note that we should never write logs, because log is not ready not.
srs_error_t SrsFileLog::initialize()
{
+ srs_error_t err = srs_success;
+
if (_srs_config) {
- _srs_config->subscribe(this);
-
log_to_file_tank = _srs_config->get_log_tank_file();
+ filename_ = _srs_config->get_log_file();
level = srs_get_log_level(_srs_config->get_log_level());
utc = _srs_config->get_utc_time();
}
-
- return srs_success;
-}
-void SrsFileLog::reopen()
-{
- if (fd > 0) {
- ::close(fd);
- }
-
if (!log_to_file_tank) {
- return;
+ return err;
+ }
+
+ if (filename_.empty()) {
+ return srs_error_new(ERROR_SYSTEM_LOGFILE, "no log filename");
+ }
+
+ // We only use the log writer, which is managed by another thread.
+ if ((err = _srs_async_log->create_writer(filename_, &writer_)) != srs_success) {
+ return srs_error_wrap(err, "create async writer for %s", filename_.c_str());
}
- open_log_file();
+ return err;
}
void SrsFileLog::verbose(const char* tag, SrsContextId context_id, const char* fmt, ...)
@@ -101,17 +97,17 @@ void SrsFileLog::verbose(const char* tag, SrsContextId context_id, const char* f
}
int size = 0;
- if (!srs_log_header(log_data, LOG_MAX_SIZE, utc, false, tag, context_id, "Verb", &size)) {
+ if (!srs_log_header(_srs_log_data, LOG_MAX_SIZE, utc, false, tag, context_id, "Verb", &size)) {
return;
}
va_list ap;
va_start(ap, fmt);
// we reserved 1 bytes for the new line.
- size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
+ size += vsnprintf(_srs_log_data + size, LOG_MAX_SIZE - size, fmt, ap);
va_end(ap);
- write_log(fd, log_data, size, SrsLogLevelVerbose);
+ write_log(_srs_log_data, size, SrsLogLevelVerbose);
}
void SrsFileLog::info(const char* tag, SrsContextId context_id, const char* fmt, ...)
@@ -121,17 +117,17 @@ void SrsFileLog::info(const char* tag, SrsContextId context_id, const char* fmt,
}
int size = 0;
- if (!srs_log_header(log_data, LOG_MAX_SIZE, utc, false, tag, context_id, "Debug", &size)) {
+ if (!srs_log_header(_srs_log_data, LOG_MAX_SIZE, utc, false, tag, context_id, "Debug", &size)) {
return;
}
va_list ap;
va_start(ap, fmt);
// we reserved 1 bytes for the new line.
- size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
+ size += vsnprintf(_srs_log_data + size, LOG_MAX_SIZE - size, fmt, ap);
va_end(ap);
- write_log(fd, log_data, size, SrsLogLevelInfo);
+ write_log(_srs_log_data, size, SrsLogLevelInfo);
}
void SrsFileLog::trace(const char* tag, SrsContextId context_id, const char* fmt, ...)
@@ -141,17 +137,17 @@ void SrsFileLog::trace(const char* tag, SrsContextId context_id, const char* fmt
}
int size = 0;
- if (!srs_log_header(log_data, LOG_MAX_SIZE, utc, false, tag, context_id, "Trace", &size)) {
+ if (!srs_log_header(_srs_log_data, LOG_MAX_SIZE, utc, false, tag, context_id, "Trace", &size)) {
return;
}
va_list ap;
va_start(ap, fmt);
// we reserved 1 bytes for the new line.
- size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
+ size += vsnprintf(_srs_log_data + size, LOG_MAX_SIZE - size, fmt, ap);
va_end(ap);
- write_log(fd, log_data, size, SrsLogLevelTrace);
+ write_log(_srs_log_data, size, SrsLogLevelTrace);
}
void SrsFileLog::warn(const char* tag, SrsContextId context_id, const char* fmt, ...)
@@ -161,17 +157,17 @@ void SrsFileLog::warn(const char* tag, SrsContextId context_id, const char* fmt,
}
int size = 0;
- if (!srs_log_header(log_data, LOG_MAX_SIZE, utc, true, tag, context_id, "Warn", &size)) {
+ if (!srs_log_header(_srs_log_data, LOG_MAX_SIZE, utc, true, tag, context_id, "Warn", &size)) {
return;
}
va_list ap;
va_start(ap, fmt);
// we reserved 1 bytes for the new line.
- size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
+ size += vsnprintf(_srs_log_data + size, LOG_MAX_SIZE - size, fmt, ap);
va_end(ap);
- write_log(fd, log_data, size, SrsLogLevelWarn);
+ write_log(_srs_log_data, size, SrsLogLevelWarn);
}
void SrsFileLog::error(const char* tag, SrsContextId context_id, const char* fmt, ...)
@@ -181,103 +177,40 @@ void SrsFileLog::error(const char* tag, SrsContextId context_id, const char* fmt
}
int size = 0;
- if (!srs_log_header(log_data, LOG_MAX_SIZE, utc, true, tag, context_id, "Error", &size)) {
+ if (!srs_log_header(_srs_log_data, LOG_MAX_SIZE, utc, true, tag, context_id, "Error", &size)) {
return;
}
va_list ap;
va_start(ap, fmt);
// we reserved 1 bytes for the new line.
- size += vsnprintf(log_data + size, LOG_MAX_SIZE - size, fmt, ap);
+ size += vsnprintf(_srs_log_data + size, LOG_MAX_SIZE - size, fmt, ap);
va_end(ap);
// add strerror() to error msg.
// Check size to avoid security issue https://github.com/ossrs/srs/issues/1229
if (errno != 0 && size < LOG_MAX_SIZE) {
- size += snprintf(log_data + size, LOG_MAX_SIZE - size, "(%s)", strerror(errno));
+ size += snprintf(_srs_log_data + size, LOG_MAX_SIZE - size, "(%s)", strerror(errno));
}
- write_log(fd, log_data, size, SrsLogLevelError);
-}
-
-srs_error_t SrsFileLog::on_reload_utc_time()
-{
- utc = _srs_config->get_utc_time();
-
- return srs_success;
+ write_log(_srs_log_data, size, SrsLogLevelError);
}
-srs_error_t SrsFileLog::on_reload_log_tank()
+void SrsFileLog::write_log(char *str_log, int size, int level)
{
srs_error_t err = srs_success;
-
- if (!_srs_config) {
- return err;
- }
-
- bool tank = log_to_file_tank;
- log_to_file_tank = _srs_config->get_log_tank_file();
-
- if (tank) {
- return err;
- }
-
- if (!log_to_file_tank) {
- return err;
- }
-
- if (fd > 0) {
- ::close(fd);
- }
- open_log_file();
-
- return err;
-}
-srs_error_t SrsFileLog::on_reload_log_level()
-{
- srs_error_t err = srs_success;
-
- if (!_srs_config) {
- return err;
- }
-
- level = srs_get_log_level(_srs_config->get_log_level());
-
- return err;
-}
-
-srs_error_t SrsFileLog::on_reload_log_file()
-{
- srs_error_t err = srs_success;
-
- if (!_srs_config) {
- return err;
- }
-
- if (!log_to_file_tank) {
- return err;
- }
-
- if (fd > 0) {
- ::close(fd);
- }
- open_log_file();
-
- return err;
-}
-
-void SrsFileLog::write_log(int& fd, char *str_log, int size, int level)
-{
// ensure the tail and EOF of string
// LOG_TAIL_SIZE for the TAIL char.
// 1 for the last char(0).
- size = srs_min(LOG_MAX_SIZE - 1 - LOG_TAIL_SIZE, size);
+ size = srs_min(LOG_MAX_SIZE - 2 - LOG_TAIL_SIZE, size);
// add some to the end of char.
str_log[size++] = LOG_TAIL;
-
+ str_log[size] = 0;
+
// if not to file, to console and return.
+ // @remark Its value changes, because there is some log before config loaded.
if (!log_to_file_tank) {
// if is error msg, then print color msg.
// \033[31m : red text code in shell
@@ -295,33 +228,10 @@ void SrsFileLog::write_log(int& fd, char *str_log, int size, int level)
return;
}
-
- // open log file. if specified
- if (fd < 0) {
- open_log_file();
- }
-
- // write log to file.
- if (fd > 0) {
- ::write(fd, str_log, size);
- }
-}
-void SrsFileLog::open_log_file()
-{
- if (!_srs_config) {
- return;
- }
-
- std::string filename = _srs_config->get_log_file();
-
- if (filename.empty()) {
- return;
+ // write log to file.
+ if ((err = writer_->write(str_log, size, NULL)) != srs_success) {
+ srs_error_reset(err); // Ignore any error for log writing.
}
-
- fd = ::open(filename.c_str(),
- O_RDWR | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
- );
}
diff --git a/trunk/src/app/srs_app_log.hpp b/trunk/src/app/srs_app_log.hpp
index 85907e29a2..f349b9e3ed 100644
--- a/trunk/src/app/srs_app_log.hpp
+++ b/trunk/src/app/srs_app_log.hpp
@@ -32,6 +32,8 @@
#include
#include
+class SrsAsyncFileWriter;
+
// For log TAGs.
#define TAG_MAIN "MAIN"
#define TAG_MAYBE "MAYBE"
@@ -45,15 +47,16 @@
// when you want to use different level, override this classs, set the protected _level.
class SrsFileLog : public ISrsLog, public ISrsReloadHandler
{
+private:
+ // Async file writer.
+ SrsAsyncFileWriter* writer_;
private:
// Defined in SrsLogLevel.
SrsLogLevel level;
-private:
- char* log_data;
- // Log to file if specified srs_log_file
- int fd;
// Whether log to file tank
bool log_to_file_tank;
+ // If log to file, the log filename.
+ std::string filename_;
// Whether use utc time.
bool utc;
public:
@@ -62,21 +65,13 @@ class SrsFileLog : public ISrsLog, public ISrsReloadHandler
// Interface ISrsLog
public:
virtual srs_error_t initialize();
- virtual void reopen();
virtual void verbose(const char* tag, SrsContextId context_id, const char* fmt, ...);
virtual void info(const char* tag, SrsContextId context_id, const char* fmt, ...);
virtual void trace(const char* tag, SrsContextId context_id, const char* fmt, ...);
virtual void warn(const char* tag, SrsContextId context_id, const char* fmt, ...);
virtual void error(const char* tag, SrsContextId context_id, const char* fmt, ...);
-// Interface ISrsReloadHandler.
-public:
- virtual srs_error_t on_reload_utc_time();
- virtual srs_error_t on_reload_log_tank();
- virtual srs_error_t on_reload_log_level();
- virtual srs_error_t on_reload_log_file();
private:
- virtual void write_log(int& fd, char* str_log, int size, int level);
- virtual void open_log_file();
+ virtual void write_log(char* str_log, int size, int level);
};
#endif
diff --git a/trunk/src/app/srs_app_pithy_print.cpp b/trunk/src/app/srs_app_pithy_print.cpp
index 98137326b6..d344857b9b 100644
--- a/trunk/src/app/srs_app_pithy_print.cpp
+++ b/trunk/src/app/srs_app_pithy_print.cpp
@@ -192,8 +192,8 @@ bool SrsAlonePithyPrint::can_print()
return info_.can_print();
}
-// The global stage manager for pithy print, multiple stages.
-static SrsStageManager* _srs_stages = new SrsStageManager();
+// It MUST be thread-local, by design.
+__thread SrsStageManager* _srs_stages = NULL;
SrsPithyPrint::SrsPithyPrint(int _stage_id)
{
diff --git a/trunk/src/app/srs_app_reload.cpp b/trunk/src/app/srs_app_reload.cpp
index 28c4dfc858..4c9256b6b5 100644
--- a/trunk/src/app/srs_app_reload.cpp
+++ b/trunk/src/app/srs_app_reload.cpp
@@ -40,11 +40,6 @@ srs_error_t ISrsReloadHandler::on_reload_listen()
return srs_success;
}
-srs_error_t ISrsReloadHandler::on_reload_utc_time()
-{
- return srs_success;
-}
-
srs_error_t ISrsReloadHandler::on_reload_max_conns()
{
return srs_success;
@@ -55,21 +50,6 @@ srs_error_t ISrsReloadHandler::on_reload_pid()
return srs_success;
}
-srs_error_t ISrsReloadHandler::on_reload_log_tank()
-{
- return srs_success;
-}
-
-srs_error_t ISrsReloadHandler::on_reload_log_level()
-{
- return srs_success;
-}
-
-srs_error_t ISrsReloadHandler::on_reload_log_file()
-{
- return srs_success;
-}
-
srs_error_t ISrsReloadHandler::on_reload_pithy_print()
{
return srs_success;
diff --git a/trunk/src/app/srs_app_reload.hpp b/trunk/src/app/srs_app_reload.hpp
index 9a1668d8e1..a63e2b5d83 100644
--- a/trunk/src/app/srs_app_reload.hpp
+++ b/trunk/src/app/srs_app_reload.hpp
@@ -39,13 +39,9 @@ class ISrsReloadHandler
ISrsReloadHandler();
virtual ~ISrsReloadHandler();
public:
- virtual srs_error_t on_reload_utc_time();
virtual srs_error_t on_reload_max_conns();
virtual srs_error_t on_reload_listen();
virtual srs_error_t on_reload_pid();
- virtual srs_error_t on_reload_log_tank();
- virtual srs_error_t on_reload_log_level();
- virtual srs_error_t on_reload_log_file();
virtual srs_error_t on_reload_pithy_print();
virtual srs_error_t on_reload_http_api_enabled();
virtual srs_error_t on_reload_http_api_disabled();
diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp
index e183604035..67daf8ab32 100644
--- a/trunk/src/app/srs_app_rtc_api.cpp
+++ b/trunk/src/app/srs_app_rtc_api.cpp
@@ -38,7 +38,15 @@ using namespace std;
uint32_t SrsGoApiRtcPlay::ssrc_num = 0;
-SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsRtcServer* server)
+ISrsRtcServer::ISrsRtcServer()
+{
+}
+
+ISrsRtcServer::~ISrsRtcServer()
+{
+}
+
+SrsGoApiRtcPlay::SrsGoApiRtcPlay(ISrsRtcServer* server)
{
server_ = server;
}
@@ -413,7 +421,7 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(SrsRequest* req, const SrsSdp& remote_
uint32_t SrsGoApiRtcPublish::ssrc_num = 0;
-SrsGoApiRtcPublish::SrsGoApiRtcPublish(SrsRtcServer* server)
+SrsGoApiRtcPublish::SrsGoApiRtcPublish(ISrsRtcServer* server)
{
server_ = server;
}
diff --git a/trunk/src/app/srs_app_rtc_api.hpp b/trunk/src/app/srs_app_rtc_api.hpp
index c7bc6596ba..df3aca6f9c 100644
--- a/trunk/src/app/srs_app_rtc_api.hpp
+++ b/trunk/src/app/srs_app_rtc_api.hpp
@@ -26,20 +26,33 @@
#include
+#include
+
#include
class SrsRtcServer;
class SrsRequest;
class SrsSdp;
+class SrsRtcConnection;
+class SrsRtcUserConfig;
+
+class ISrsRtcServer
+{
+public:
+ ISrsRtcServer();
+ virtual ~ISrsRtcServer();
+public:
+ virtual srs_error_t create_session(SrsRtcUserConfig* ruc, SrsSdp& local_sdp, SrsRtcConnection** psession) = 0;
+};
class SrsGoApiRtcPlay : public ISrsHttpHandler
{
public:
static uint32_t ssrc_num;
private:
- SrsRtcServer* server_;
+ ISrsRtcServer* server_;
public:
- SrsGoApiRtcPlay(SrsRtcServer* server);
+ SrsGoApiRtcPlay(ISrsRtcServer* server);
virtual ~SrsGoApiRtcPlay();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
@@ -54,9 +67,9 @@ class SrsGoApiRtcPublish : public ISrsHttpHandler
public:
static uint32_t ssrc_num;
private:
- SrsRtcServer* server_;
+ ISrsRtcServer* server_;
public:
- SrsGoApiRtcPublish(SrsRtcServer* server);
+ SrsGoApiRtcPublish(ISrsRtcServer* server);
virtual ~SrsGoApiRtcPublish();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp
index 57ddb76f8a..4f032eb142 100644
--- a/trunk/src/app/srs_app_rtc_conn.cpp
+++ b/trunk/src/app/srs_app_rtc_conn.cpp
@@ -57,24 +57,26 @@ using namespace std;
#include
#include
#include
+#include
#include
-SrsPps* _srs_pps_sstuns = new SrsPps();
-SrsPps* _srs_pps_srtcps = new SrsPps();
-SrsPps* _srs_pps_srtps = new SrsPps();
+__thread SrsPps* _srs_pps_sstuns = NULL;
+__thread SrsPps* _srs_pps_srtcps = NULL;
+__thread SrsPps* _srs_pps_srtps = NULL;
-SrsPps* _srs_pps_pli = new SrsPps();
-SrsPps* _srs_pps_twcc = new SrsPps();
-SrsPps* _srs_pps_rr = new SrsPps();
-SrsPps* _srs_pps_pub = new SrsPps();
-SrsPps* _srs_pps_conn = new SrsPps();
+__thread SrsPps* _srs_pps_pli = NULL;
+__thread SrsPps* _srs_pps_twcc = NULL;
+__thread SrsPps* _srs_pps_rr = NULL;
+__thread SrsPps* _srs_pps_pub = NULL;
+__thread SrsPps* _srs_pps_conn = NULL;
-extern SrsPps* _srs_pps_snack;
-extern SrsPps* _srs_pps_snack2;
+extern __thread SrsPps* _srs_pps_snack;
+extern __thread SrsPps* _srs_pps_snack2;
-extern SrsPps* _srs_pps_rnack;
-extern SrsPps* _srs_pps_rnack2;
+extern __thread SrsPps* _srs_pps_rnack;
+extern __thread SrsPps* _srs_pps_rnack2;
+extern __thread SrsPps* _srs_pps_snack4;
ISrsRtcTransport::ISrsRtcTransport()
{
@@ -256,7 +258,7 @@ srs_error_t SrsPlaintextTransport::on_dtls_alert(std::string type, std::string d
srs_error_t SrsPlaintextTransport::on_dtls_handshake_done()
{
- srs_trace("RTC: DTLS handshake done.");
+ srs_trace("RTC: DTLS plaintext handshake done.");
return session_->on_connection_established();
}
@@ -593,6 +595,9 @@ srs_error_t SrsRtcPlayStream::cycle()
}
}
+ // How many messages to run a yield.
+ uint32_t nn_msgs_for_yield = 0;
+
while (true) {
if ((err = trd_->pull()) != srs_success) {
return srs_error_wrap(err, "rtc sender thread");
@@ -620,6 +625,13 @@ srs_error_t SrsRtcPlayStream::cycle()
// Release the packet to cache.
// @remark Note that the pkt might be set to NULL.
_srs_rtp_cache->recycle(pkt);
+
+ // Yield to another coroutines.
+ // @see https://github.com/ossrs/srs/issues/2194#issuecomment-777485531
+ if (++nn_msgs_for_yield > 10) {
+ nn_msgs_for_yield = 0;
+ srs_thread_yield();
+ }
}
}
@@ -1217,6 +1229,12 @@ srs_error_t SrsRtcPublishStream::on_rtp(char* data, int nb_data)
return err;
}
+ // For async SRTP, the nb_plaintext might be zero, which means we do not got the plaintext
+ // right now, and it will callback if get one.
+ if (nb_plaintext == 0) {
+ return err;
+ }
+
// Handle the plaintext RTP packet.
if ((err = on_rtp_plaintext(plaintext, nb_plaintext)) != srs_success) {
// We try to decode the RTP header for more detail error informations.
@@ -1299,6 +1317,12 @@ srs_error_t SrsRtcPublishStream::do_on_rtp_plaintext(SrsRtpPacket2*& pkt, SrsBuf
}
}
+ // If circuit-breaker is enabled, disable nack.
+ if (_srs_circuit_breaker->hybrid_critical_water_level()) {
+ ++_srs_pps_snack4->sugar;
+ return err;
+ }
+
// For NACK to handle packet.
// @remark Note that the pkt might be set to NULL.
if (nack_enabled_) {
@@ -1547,6 +1571,12 @@ srs_error_t SrsRtcPublishStream::on_timer(srs_utime_t interval)
if (twcc_enabled_) {
++_srs_pps_twcc->sugar;
+ // If circuit-breaker is dropping packet, disable TWCC.
+ if (_srs_circuit_breaker->hybrid_critical_water_level()) {
+ ++_srs_pps_snack4->sugar;
+ return err;
+ }
+
// We should not depends on the received packet,
// instead we should send feedback every Nms.
if ((err = send_periodic_twcc()) != srs_success) {
@@ -2004,6 +2034,23 @@ srs_error_t SrsRtcConnection::on_rtcp(char* data, int nb_data)
return srs_error_wrap(err, "rtcp unprotect");
}
+ // For async SRTP, the nb_unprotected_buf might be zero, which means we do not got the plaintext
+ // right now, and it will callback if get one.
+ if (nb_unprotected_buf == 0) {
+ return err;
+ }
+
+ if ((err = on_rtcp_plaintext(data, nb_unprotected_buf)) != srs_success) {
+ return srs_error_wrap(err, "cipher=%d", nb_data);
+ }
+
+ return err;
+}
+
+srs_error_t SrsRtcConnection::on_rtcp_plaintext(char* data, int nb_unprotected_buf)
+{
+ srs_error_t err = srs_success;
+
char* unprotected_buf = data;
if (_srs_blackhole->blackhole) {
_srs_blackhole->sendto(unprotected_buf, nb_unprotected_buf);
@@ -2025,7 +2072,7 @@ srs_error_t SrsRtcConnection::on_rtcp(char* data, int nb_data)
SrsAutoFree(SrsRtcpCommon, rtcp);
if(srs_success != err) {
- return srs_error_wrap(err, "cipher=%u, plaintext=%u, bytes=[%s], rtcp=(%u,%u,%u,%u)", nb_data, nb_unprotected_buf,
+ return srs_error_wrap(err, "plaintext=%u, bytes=[%s], rtcp=(%u,%u,%u,%u)", nb_unprotected_buf,
srs_string_dumps_hex(rtcp->data(), rtcp->size(), rtcp->size()).c_str(),
rtcp->get_rc(), rtcp->type(), rtcp->get_ssrc(), rtcp->size());
}
@@ -2034,6 +2081,28 @@ srs_error_t SrsRtcConnection::on_rtcp(char* data, int nb_data)
return err;
}
+srs_error_t SrsRtcConnection::on_rtp_cipher(char* cipher, int size)
+{
+ srs_error_t err = srs_success;
+
+ if ((err = sendonly_skt->sendto(cipher, size, 0)) != srs_success) {
+ srs_error_reset(err); // Ignore any error.
+ }
+
+ return err;
+}
+
+srs_error_t SrsRtcConnection::on_rtcp_cipher(char* cipher, int size)
+{
+ srs_error_t err = srs_success;
+
+ if ((err = sendonly_skt->sendto(cipher, size, 0)) != srs_success) {
+ srs_error_reset(err); // Ignore any error.
+ }
+
+ return err;
+}
+
srs_error_t SrsRtcConnection::dispatch_rtcp(SrsRtcpCommon* rtcp)
{
srs_error_t err = srs_success;
@@ -2146,6 +2215,22 @@ srs_error_t SrsRtcConnection::on_rtp(char* data, int nb_data)
return publisher->on_rtp(data, nb_data);
}
+srs_error_t SrsRtcConnection::on_rtp_plaintext(char* plaintext, int nb_plaintext)
+{
+ srs_error_t err = srs_success;
+
+ // We should keep alive here, for tunnel is enabled.
+ alive();
+
+ SrsRtcPublishStream* publisher = NULL;
+ if ((err = find_publisher(plaintext, nb_plaintext, &publisher)) != srs_success) {
+ return srs_error_wrap(err, "find");
+ }
+ srs_assert(publisher);
+
+ return publisher->on_rtp_plaintext(plaintext, nb_plaintext);
+}
+
srs_error_t SrsRtcConnection::find_publisher(char* buf, int size, SrsRtcPublishStream** ppublisher)
{
srs_error_t err = srs_success;
@@ -2334,10 +2419,13 @@ srs_error_t SrsRtcConnection::on_timer(srs_utime_t interval)
++_srs_pps_conn->sugar;
- // For publisher to send NACK.
- // TODO: FIXME: Merge with hybrid system clock.
- srs_update_system_time();
+ // If circuit-breaker is enabled, disable nack.
+ if (_srs_circuit_breaker->hybrid_critical_water_level()) {
+ ++_srs_pps_snack4->sugar;
+ return err;
+ }
+ // For publisher to send NACK.
std::map::iterator it;
for (it = publishers_.begin(); it != publishers_.end(); it++) {
SrsRtcPublishStream* publisher = it->second;
@@ -2362,11 +2450,12 @@ srs_error_t SrsRtcConnection::send_rtcp(char *data, int nb_data)
return srs_error_wrap(err, "protect rtcp");
}
- if ((err = sendonly_skt->sendto(data, nb_buf, 0)) != srs_success) {
- return srs_error_wrap(err, "send");
+ // Async SRTP encrypt.
+ if (nb_buf <= 0) {
+ return err;
}
- return err;
+ return on_rtcp_cipher(data, nb_buf);
}
void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc, uint32_t& sent_nacks, uint32_t& timeout_nacks)
@@ -2552,6 +2641,11 @@ srs_error_t SrsRtcConnection::do_send_packet(SrsRtpPacket2* pkt)
iov->iov_len = (size_t)nn_encrypt;
}
+ // Async SRTP encrypt.
+ if (iov->iov_len <= 0) {
+ return err;
+ }
+
// For NACK simulator, drop packet.
if (nn_simulate_player_nack_drop) {
simulate_player_drop_packet(&pkt->header, (int)iov->iov_len);
@@ -2561,14 +2655,11 @@ srs_error_t SrsRtcConnection::do_send_packet(SrsRtpPacket2* pkt)
++_srs_pps_srtps->sugar;
- // TODO: FIXME: Handle error.
- sendonly_skt->sendto(iov->iov_base, iov->iov_len, 0);
-
// Detail log, should disable it in release version.
srs_info("RTC: SEND PT=%u, SSRC=%#x, SEQ=%u, Time=%u, %u/%u bytes", pkt->header.get_payload_type(), pkt->header.get_ssrc(),
pkt->header.get_sequence(), pkt->header.get_timestamp(), pkt->nb_bytes(), iov->iov_len);
- return err;
+ return on_rtp_cipher((char*)iov->iov_base, iov->iov_len);
}
void SrsRtcConnection::set_all_tracks_status(std::string stream_uri, bool is_publish, bool status)
diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp
index ab3d0a4e08..495816273b 100644
--- a/trunk/src/app/srs_app_rtc_conn.hpp
+++ b/trunk/src/app/srs_app_rtc_conn.hpp
@@ -29,7 +29,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -334,7 +333,7 @@ class SrsRtcPublishStream : public ISrsFastTimer, public ISrsRtpPacketDecodeHand
srs_error_t send_rtcp_xr_rrtr();
public:
srs_error_t on_rtp(char* buf, int nb_buf);
-private:
+public:
// @remark We copy the plaintext, user should free it.
srs_error_t on_rtp_plaintext(char* plaintext, int nb_plaintext);
private:
@@ -492,10 +491,16 @@ class SrsRtcConnection : public ISrsResource, public ISrsFastTimer, public ISrsD
srs_error_t on_dtls(char* data, int nb_data);
srs_error_t on_rtp(char* data, int nb_data);
private:
+ srs_error_t on_rtp_plaintext(char* plaintext, int size);
// Decode the RTP header from buf, find the publisher by SSRC.
srs_error_t find_publisher(char* buf, int size, SrsRtcPublishStream** ppublisher);
public:
srs_error_t on_rtcp(char* data, int nb_data);
+private:
+ srs_error_t on_rtcp_plaintext(char* plaintext, int size);
+private:
+ srs_error_t on_rtp_cipher(char* cipher, int size);
+ srs_error_t on_rtcp_cipher(char* cipher, int size);
private:
srs_error_t dispatch_rtcp(SrsRtcpCommon* rtcp);
public:
@@ -568,6 +573,8 @@ class ISrsRtcHijacker
virtual srs_error_t on_start_consume(SrsRtcConnection* session, SrsRtcPlayStream* player, SrsRequest* req, SrsRtcConsumer* consumer) = 0;
};
+// TODO: FIXME: It should be thread-local or thread-safe.
+// TODO: FIXME: It seems thread-local make sense.
extern ISrsRtcHijacker* _srs_rtc_hijacker;
#endif
diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp
index 0938f30c66..9236a41188 100644
--- a/trunk/src/app/srs_app_rtc_dtls.hpp
+++ b/trunk/src/app/srs_app_rtc_dtls.hpp
@@ -35,6 +35,7 @@
#include
class SrsRequest;
+class SrsUdpMuxSocket;
class SrsDtlsCertificate
{
@@ -62,7 +63,7 @@ class SrsDtlsCertificate
bool is_ecdsa();
};
-// @global config object.
+// It's shared global object, MUST be thread-safe.
extern SrsDtlsCertificate* _srs_rtc_dtls_certificate;
// @remark: play the role of DTLS_CLIENT, will send handshake
@@ -231,20 +232,20 @@ class SrsDtls
class SrsSRTP
{
-private:
+protected:
srtp_t recv_ctx_;
srtp_t send_ctx_;
public:
SrsSRTP();
virtual ~SrsSRTP();
public:
- // Intialize srtp context with recv_key and send_key.
- srs_error_t initialize(std::string recv_key, std::string send_key);
+ // Initialize srtp context with recv_key and send_key.
+ virtual srs_error_t initialize(std::string recv_key, std::string send_key);
public:
- srs_error_t protect_rtp(void* packet, int* nb_cipher);
- srs_error_t protect_rtcp(void* packet, int* nb_cipher);
- srs_error_t unprotect_rtp(void* packet, int* nb_plaintext);
- srs_error_t unprotect_rtcp(void* packet, int* nb_plaintext);
+ virtual srs_error_t protect_rtp(void* packet, int* nb_cipher);
+ virtual srs_error_t protect_rtcp(void* packet, int* nb_cipher);
+ virtual srs_error_t unprotect_rtp(void* packet, int* nb_plaintext);
+ virtual srs_error_t unprotect_rtcp(void* packet, int* nb_plaintext);
};
#endif
diff --git a/trunk/src/app/srs_app_rtc_queue.cpp b/trunk/src/app/srs_app_rtc_queue.cpp
index 7a19f2b579..9bdf246fc9 100644
--- a/trunk/src/app/srs_app_rtc_queue.cpp
+++ b/trunk/src/app/srs_app_rtc_queue.cpp
@@ -33,6 +33,12 @@ using namespace std;
#include
#include
#include
+#include
+
+#include
+
+extern __thread SrsPps* _srs_pps_snack3;
+extern __thread SrsPps* _srs_pps_snack4;
SrsRtpRingBuffer::SrsRtpRingBuffer(int capacity)
{
@@ -228,6 +234,12 @@ SrsRtpNackForReceiver::~SrsRtpNackForReceiver()
void SrsRtpNackForReceiver::insert(uint16_t first, uint16_t last)
{
+ // If circuit-breaker is enabled, disable nack.
+ if (_srs_circuit_breaker->hybrid_high_water_level()) {
+ ++_srs_pps_snack4->sugar;
+ return;
+ }
+
for (uint16_t s = first; s != last; ++s) {
queue_[s] = SrsRtpNackInfo();
}
@@ -259,6 +271,13 @@ void SrsRtpNackForReceiver::check_queue_size()
void SrsRtpNackForReceiver::get_nack_seqs(SrsRtcpNack& seqs, uint32_t& timeout_nacks)
{
+ // If circuit-breaker is enabled, disable nack.
+ if (_srs_circuit_breaker->hybrid_high_water_level()) {
+ queue_.clear();
+ ++_srs_pps_snack4->sugar;
+ return;
+ }
+
srs_utime_t now = srs_get_system_time();
srs_utime_t interval = now - pre_check_time_;
@@ -294,6 +313,8 @@ void SrsRtpNackForReceiver::get_nack_seqs(SrsRtcpNack& seqs, uint32_t& timeout_n
++nack_info.req_nack_count_;
nack_info.pre_req_nack_time_ = now;
seqs.add_lost_sn(seq);
+
+ ++_srs_pps_snack3->sugar;
}
++iter;
diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp
index 1fa107b600..2deca9cd68 100644
--- a/trunk/src/app/srs_app_rtc_server.cpp
+++ b/trunk/src/app/srs_app_rtc_server.cpp
@@ -45,35 +45,42 @@ using namespace std;
#include
#include
-extern SrsPps* _srs_pps_rpkts;
-SrsPps* _srs_pps_rstuns = new SrsPps();
-SrsPps* _srs_pps_rrtps = new SrsPps();
-SrsPps* _srs_pps_rrtcps = new SrsPps();
-extern SrsPps* _srs_pps_addrs;
-extern SrsPps* _srs_pps_fast_addrs;
-
-extern SrsPps* _srs_pps_spkts;
-extern SrsPps* _srs_pps_sstuns;
-extern SrsPps* _srs_pps_srtcps;
-extern SrsPps* _srs_pps_srtps;
-
-extern SrsPps* _srs_pps_ids;
-extern SrsPps* _srs_pps_fids;
-extern SrsPps* _srs_pps_fids_level0;
-
-extern SrsPps* _srs_pps_pli;
-extern SrsPps* _srs_pps_twcc;
-extern SrsPps* _srs_pps_rr;
-
-extern SrsPps* _srs_pps_snack;
-extern SrsPps* _srs_pps_snack2;
-extern SrsPps* _srs_pps_sanack;
-extern SrsPps* _srs_pps_svnack;
-
-extern SrsPps* _srs_pps_rnack;
-extern SrsPps* _srs_pps_rnack2;
-extern SrsPps* _srs_pps_rhnack;
-extern SrsPps* _srs_pps_rmnack;
+extern __thread SrsPps* _srs_pps_rpkts;
+__thread SrsPps* _srs_pps_rstuns = NULL;
+__thread SrsPps* _srs_pps_rrtps = NULL;
+__thread SrsPps* _srs_pps_rrtcps = NULL;
+extern __thread SrsPps* _srs_pps_addrs;
+extern __thread SrsPps* _srs_pps_fast_addrs;
+
+extern __thread SrsPps* _srs_pps_spkts;
+extern __thread SrsPps* _srs_pps_sstuns;
+extern __thread SrsPps* _srs_pps_srtcps;
+extern __thread SrsPps* _srs_pps_srtps;
+
+extern __thread SrsPps* _srs_pps_ids;
+extern __thread SrsPps* _srs_pps_fids;
+extern __thread SrsPps* _srs_pps_fids_level0;
+
+extern __thread SrsPps* _srs_pps_pli;
+extern __thread SrsPps* _srs_pps_twcc;
+extern __thread SrsPps* _srs_pps_rr;
+
+extern __thread SrsPps* _srs_pps_snack;
+extern __thread SrsPps* _srs_pps_snack2;
+extern __thread SrsPps* _srs_pps_snack3;
+extern __thread SrsPps* _srs_pps_snack4;
+extern __thread SrsPps* _srs_pps_sanack;
+extern __thread SrsPps* _srs_pps_svnack;
+
+extern __thread SrsPps* _srs_pps_rnack;
+extern __thread SrsPps* _srs_pps_rnack2;
+extern __thread SrsPps* _srs_pps_rhnack;
+extern __thread SrsPps* _srs_pps_rmnack;
+
+extern __thread SrsPps* _srs_pps_rloss;
+extern __thread SrsPps* _srs_pps_sloss;
+extern __thread SrsPps* _srs_pps_aloss;
+extern __thread SrsPps* _srs_pps_aloss2;
SrsRtcBlackhole::SrsRtcBlackhole()
{
@@ -132,7 +139,7 @@ void SrsRtcBlackhole::sendto(void* data, int len)
srs_sendto(blackhole_stfd, data, len, (sockaddr*)blackhole_addr, sizeof(sockaddr_in), SRS_UTIME_NO_TIMEOUT);
}
-SrsRtcBlackhole* _srs_blackhole = new SrsRtcBlackhole();
+__thread SrsRtcBlackhole* _srs_blackhole = NULL;
// @global dtls certficate for rtc module.
SrsDtlsCertificate* _srs_rtc_dtls_certificate = new SrsDtlsCertificate();
@@ -284,6 +291,7 @@ srs_error_t SrsRtcServer::initialize()
_srs_hybrid->timer5s()->subscribe(this);
// Initialize the black hole.
+ // TODO: FIXME: It should be thread-local or thread-safe.
if ((err = _srs_blackhole->initialize()) != srs_success) {
return srs_error_wrap(err, "black hole");
}
@@ -305,7 +313,8 @@ srs_error_t SrsRtcServer::initialize()
rtp_cache_enabled, (int)(rtp_cache_pkt_size/1024/1024), _srs_rtp_cache->capacity()/10000,
(int)(rtp_cache_payload_size/1024/1024), _srs_rtp_raw_cache->capacity()/10000, _srs_rtp_fua_cache->capacity()/10000,
rtp_msg_cache_enabled, (int)(rtp_msg_cache_msg_size/1024/1024), _srs_rtp_msg_cache_objs->capacity()/10000,
- (int)(rtp_msg_cache_buffer_size/1024/1024), _srs_rtp_msg_cache_buffers->capacity()/10000);
+ (int)(rtp_msg_cache_buffer_size/1024/1024), _srs_rtp_msg_cache_buffers->capacity()/10000
+ );
return err;
}
@@ -364,7 +373,7 @@ srs_error_t SrsRtcServer::listen_udp()
return err;
}
- int port = _srs_config->get_rtc_server_listen();
+ int port = _srs_config->get_rtc_server_listen(_srs_hybrid->stream_index());
if (port <= 0) {
return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port);
}
@@ -481,33 +490,11 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* skt)
if (srs_is_dtls((uint8_t*)data, size)) {
++_srs_pps_rstuns->sugar;
- return session->on_dtls(data, size);
- }
- return srs_error_new(ERROR_RTC_UDP, "unknown packet");
-}
-
-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");
- }
+ err = session->on_dtls(data, size);
-#ifdef SRS_SIMULATOR
- if ((err = http_api_mux->handle("/rtc/v1/nack/", new SrsGoApiRtcNACK(this))) != srs_success) {
- return srs_error_wrap(err, "handle nack");
+ return err;
}
-#endif
-
- return err;
+ return srs_error_new(ERROR_RTC_UDP, "unknown packet");
}
srs_error_t SrsRtcServer::create_session(SrsRtcUserConfig* ruc, SrsSdp& local_sdp, SrsRtcConnection** psession)
@@ -580,7 +567,7 @@ srs_error_t SrsRtcServer::do_create_session(SrsRtcUserConfig* ruc, SrsSdp& local
// We allows to mock the eip of server.
if (!ruc->eip_.empty()) {
string host;
- int port = _srs_config->get_rtc_server_listen();
+ int port = _srs_config->get_rtc_server_listen(_srs_hybrid->stream_index());
srs_parse_hostport(ruc->eip_, host, port);
local_sdp.add_candidate(host, port, "host");
@@ -588,7 +575,7 @@ srs_error_t SrsRtcServer::do_create_session(SrsRtcUserConfig* ruc, SrsSdp& local
} else {
std::vector 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");
+ local_sdp.add_candidate(candidate_ips[i], _srs_config->get_rtc_server_listen(_srs_hybrid->stream_index()), "host");
}
srs_trace("RTC: Use candidates %s", srs_join_vector_string(candidate_ips, ", ").c_str());
}
@@ -693,9 +680,9 @@ srs_error_t SrsRtcServer::on_timer(srs_utime_t interval)
}
string snk_desc;
- _srs_pps_snack->update(); _srs_pps_snack2->update(); _srs_pps_sanack->update(); _srs_pps_svnack->update();
- if (_srs_pps_snack->r10s() || _srs_pps_sanack->r10s() || _srs_pps_svnack->r10s() || _srs_pps_snack2->r10s()) {
- snprintf(buf, sizeof(buf), ", snk=(%d,a:%d,v:%d,h:%d)", _srs_pps_snack->r10s(), _srs_pps_sanack->r10s(), _srs_pps_svnack->r10s(), _srs_pps_snack2->r10s());
+ _srs_pps_snack->update(); _srs_pps_snack2->update(); _srs_pps_snack3->update(); _srs_pps_snack4->update(); _srs_pps_sanack->update(); _srs_pps_svnack->update();
+ if (_srs_pps_snack->r10s() || _srs_pps_sanack->r10s() || _srs_pps_svnack->r10s() || _srs_pps_snack2->r10s() || _srs_pps_snack3->r10s() || _srs_pps_snack4->r10s()) {
+ snprintf(buf, sizeof(buf), ", snk=(%d,a:%d,v:%d,h:%d,h3:%d,h4:%d)", _srs_pps_snack->r10s(), _srs_pps_sanack->r10s(), _srs_pps_svnack->r10s(), _srs_pps_snack2->r10s(), _srs_pps_snack3->r10s(), _srs_pps_snack4->r10s());
snk_desc = buf;
}
@@ -706,10 +693,11 @@ srs_error_t SrsRtcServer::on_timer(srs_utime_t interval)
rnk_desc = buf;
}
+ // TODO: FIXME: Should move to Hybrid server stat.
string loss_desc;
- SrsSnmpUdpStat* s = srs_get_udp_snmp_stat();
- if (s->rcv_buf_errors_delta || s->snd_buf_errors_delta) {
- snprintf(buf, sizeof(buf), ", loss=(r:%d,s:%d)", s->rcv_buf_errors_delta, s->snd_buf_errors_delta);
+ _srs_pps_aloss->update(); _srs_pps_aloss2->update();
+ if (_srs_pps_rloss->r1s() || _srs_pps_rloss->r10s() || _srs_pps_sloss->r10s() || _srs_pps_aloss->r10s() || _srs_pps_aloss2->r10s()) {
+ snprintf(buf, sizeof(buf), ", loss=(r:%d/%d,s:%d,a:%d/%d)", _srs_pps_rloss->r1s(), _srs_pps_rloss->r10s(), _srs_pps_sloss->r10s(), _srs_pps_aloss->r10s(), _srs_pps_aloss2->r10s());
loss_desc = buf;
}
@@ -742,10 +730,6 @@ srs_error_t RtcServerAdapter::initialize()
{
srs_error_t err = srs_success;
- if ((err = _srs_rtc_dtls_certificate->initialize()) != srs_success) {
- return srs_error_wrap(err, "rtc dtls certificate initialize");
- }
-
if ((err = rtc->initialize()) != srs_success) {
return srs_error_wrap(err, "rtc server initialize");
}
@@ -761,10 +745,6 @@ srs_error_t RtcServerAdapter::run()
return srs_error_wrap(err, "listen udp");
}
- if ((err = rtc->listen_api()) != srs_success) {
- return srs_error_wrap(err, "listen api");
- }
-
if ((err = _srs_rtc_manager->start()) != srs_success) {
return srs_error_wrap(err, "start manager");
}
@@ -776,5 +756,5 @@ void RtcServerAdapter::stop()
{
}
-SrsResourceManager* _srs_rtc_manager = new SrsResourceManager("RTC", true);
+__thread SrsResourceManager* _srs_rtc_manager = NULL;
diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp
index d302ad64be..ac9c727cb2 100644
--- a/trunk/src/app/srs_app_rtc_server.hpp
+++ b/trunk/src/app/srs_app_rtc_server.hpp
@@ -61,7 +61,8 @@ class SrsRtcBlackhole
void sendto(void* data, int len);
};
-extern SrsRtcBlackhole* _srs_blackhole;
+// It MUST be thread-local, because it create ST socket.
+extern __thread SrsRtcBlackhole* _srs_blackhole;
// The handler for RTC server to call.
class ISrsRtcServerHandler
@@ -128,7 +129,6 @@ class SrsRtcServer : public ISrsUdpMuxHandler, public ISrsFastTimer, public ISrs
// 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(SrsRtcUserConfig* ruc, SrsSdp& local_sdp, SrsRtcConnection** psession);
@@ -144,6 +144,7 @@ class SrsRtcServer : public ISrsUdpMuxHandler, public ISrsFastTimer, public ISrs
// The RTC server adapter.
class RtcServerAdapter : public ISrsHybridServer
{
+ friend class SrsHybridServer;
private:
SrsRtcServer* rtc;
public:
@@ -155,8 +156,8 @@ class RtcServerAdapter : public ISrsHybridServer
virtual void stop();
};
-// Manager for RTC connections.
-extern SrsResourceManager* _srs_rtc_manager;
+// It SHOULD be thread-local, because used to find connection for each UDP packet.
+extern __thread SrsResourceManager* _srs_rtc_manager;
#endif
diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp
index 8ecabee05e..e055f88ae1 100644
--- a/trunk/src/app/srs_app_rtc_source.cpp
+++ b/trunk/src/app/srs_app_rtc_source.cpp
@@ -43,6 +43,8 @@
#include
#include
#include
+#include
+#include
#ifdef SRS_FFMPEG_FIT
#include
@@ -51,15 +53,19 @@
#include
// The NACK sent by us(SFU).
-SrsPps* _srs_pps_snack = new SrsPps();
-SrsPps* _srs_pps_snack2 = new SrsPps();
-SrsPps* _srs_pps_sanack = new SrsPps();
-SrsPps* _srs_pps_svnack = new SrsPps();
+__thread SrsPps* _srs_pps_snack = NULL;
+__thread SrsPps* _srs_pps_snack2 = NULL;
+__thread SrsPps* _srs_pps_snack3 = NULL;
+__thread SrsPps* _srs_pps_snack4 = NULL;
+__thread SrsPps* _srs_pps_sanack = NULL;
+__thread SrsPps* _srs_pps_svnack = NULL;
-SrsPps* _srs_pps_rnack = new SrsPps();
-SrsPps* _srs_pps_rnack2 = new SrsPps();
-SrsPps* _srs_pps_rhnack = new SrsPps();
-SrsPps* _srs_pps_rmnack = new SrsPps();
+__thread SrsPps* _srs_pps_rnack = NULL;
+__thread SrsPps* _srs_pps_rnack2 = NULL;
+__thread SrsPps* _srs_pps_rhnack = NULL;
+__thread SrsPps* _srs_pps_rmnack = NULL;
+
+extern __thread SrsPps* _srs_pps_aloss2;
// Firefox defaults as 109, Chrome is 111.
const int kAudioPayloadType = 111;
@@ -310,7 +316,7 @@ SrsRtcStream* SrsRtcStreamManager::fetch(SrsRequest* r)
return source;
}
-SrsRtcStreamManager* _srs_rtc_sources = new SrsRtcStreamManager();
+__thread SrsRtcStreamManager* _srs_rtc_sources = NULL;
ISrsRtcPublishStream::ISrsRtcPublishStream()
{
@@ -576,6 +582,12 @@ srs_error_t SrsRtcStream::on_rtp(SrsRtpPacket2* pkt)
{
srs_error_t err = srs_success;
+ // If circuit-breaker is dying, drop packet.
+ if (_srs_circuit_breaker->hybrid_dying_water_level()) {
+ _srs_pps_aloss2->sugar += (int64_t)consumers.size();
+ return err;
+ }
+
for (int i = 0; i < (int)consumers.size(); i++) {
SrsRtcConsumer* consumer = consumers.at(i);
if ((err = consumer->enqueue(pkt->copy())) != srs_success) {
diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp
index 19172304b8..8a2da97368 100644
--- a/trunk/src/app/srs_app_rtc_source.hpp
+++ b/trunk/src/app/srs_app_rtc_source.hpp
@@ -137,8 +137,8 @@ class SrsRtcStreamManager
virtual SrsRtcStream* fetch(SrsRequest* r);
};
-// Global singleton instance.
-extern SrsRtcStreamManager* _srs_rtc_sources;
+// It SHOULD be thread-local, because stream source is isolated by threads.
+extern __thread SrsRtcStreamManager* _srs_rtc_sources;
// A publish stream interface, for source to callback with.
class ISrsRtcPublishStream
diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp
index da93d1c4f8..a8b940d5d0 100644
--- a/trunk/src/app/srs_app_server.cpp
+++ b/trunk/src/app/srs_app_server.cpp
@@ -40,6 +40,7 @@ using namespace std;
#include
#include
#include
+#include
#include
#include
#include
@@ -54,6 +55,7 @@ using namespace std;
#include
#include
#include
+#include
std::string srs_listener_type2string(SrsListenerType type)
{
@@ -83,7 +85,15 @@ std::string srs_listener_type2string(SrsListenerType type)
}
}
-SrsListener::SrsListener(SrsServer* svr, SrsListenerType t)
+ISrsTcpMuxHandler::ISrsTcpMuxHandler()
+{
+}
+
+ISrsTcpMuxHandler::~ISrsTcpMuxHandler()
+{
+}
+
+SrsListener::SrsListener(ISrsTcpMuxHandler* svr, SrsListenerType t)
{
port = 0;
server = svr;
@@ -99,7 +109,7 @@ SrsListenerType SrsListener::listen_type()
return type;
}
-SrsBufferListener::SrsBufferListener(SrsServer* svr, SrsListenerType t) : SrsListener(svr, t)
+SrsBufferListener::SrsBufferListener(ISrsTcpMuxHandler* svr, SrsListenerType t) : SrsListener(svr, t)
{
listener = NULL;
}
@@ -131,7 +141,7 @@ srs_error_t SrsBufferListener::listen(string i, int p)
srs_error_t SrsBufferListener::on_tcp_client(srs_netfd_t stfd)
{
- srs_error_t err = server->accept_client(type, stfd);
+ srs_error_t err = server->accept_tcp_client(type, stfd);
if (err != srs_success) {
srs_warn("accept client failed, err is %s", srs_error_desc(err).c_str());
srs_freep(err);
@@ -394,39 +404,42 @@ SrsSignalManager* SrsSignalManager::instance = NULL;
SrsSignalManager::SrsSignalManager(SrsServer* s)
{
SrsSignalManager::instance = this;
-
+
+ pipe_ = new SrsThreadPipePair();
+
server = s;
- sig_pipe[0] = sig_pipe[1] = -1;
trd = new SrsSTCoroutine("signal", this, _srs_context->get_id());
- signal_read_stfd = NULL;
}
SrsSignalManager::~SrsSignalManager()
{
- srs_close_stfd(signal_read_stfd);
-
- if (sig_pipe[0] > 0) {
- ::close(sig_pipe[0]);
- }
- if (sig_pipe[1] > 0) {
- ::close(sig_pipe[1]);
- }
-
srs_freep(trd);
+
+ // Note that it's optional, because the read/write pair is in the same thread.
+ pipe_->close_read();
+ pipe_->close_write();
+
+ // If in the same thread, we could directly free the pipe, which will close all FDs.
+ srs_freep(pipe_);
}
srs_error_t SrsSignalManager::initialize()
{
- /* Create signal pipe */
- if (pipe(sig_pipe) < 0) {
- return srs_error_new(ERROR_SYSTEM_CREATE_PIPE, "create pipe");
+ srs_error_t err = srs_success;
+
+ if ((err = pipe_->initialize()) != srs_success) {
+ return srs_error_wrap(err, "init pipe");
}
-
- if ((signal_read_stfd = srs_netfd_open(sig_pipe[0])) == NULL) {
- return srs_error_new(ERROR_SYSTEM_CREATE_PIPE, "open pipe");
+
+ if ((err = pipe_->open_read()) != srs_success) {
+ return srs_error_wrap(err, "init read pipe");
}
-
- return srs_success;
+
+ if ((err = pipe_->open_write()) != srs_success) {
+ return srs_error_wrap(err, "init write pipe");
+ }
+
+ return err;
}
srs_error_t SrsSignalManager::start()
@@ -486,11 +499,12 @@ srs_error_t SrsSignalManager::cycle()
}
int signo;
+ // Read the next signal from the pipe
+ if ((err = pipe_->read(&signo, sizeof(int), NULL)) != srs_success) {
+ srs_freep(err); // Ignore any error.
+ }
- /* Read the next signal from the pipe */
- srs_read(signal_read_stfd, &signo, sizeof(int), SRS_UTIME_NO_TIMEOUT);
-
- /* Process signal synchronously */
+ // Process signal synchronously
server->on_signal(signo);
}
@@ -501,13 +515,15 @@ void SrsSignalManager::sig_catcher(int signo)
{
int err;
- /* Save errno to restore it after the write() */
+ // Save errno to restore it after the write()
err = errno;
-
- /* write() is reentrant/async-safe */
- int fd = SrsSignalManager::instance->sig_pipe[1];
- write(fd, &signo, sizeof(int));
-
+
+ // write() is reentrant/async-safe
+ srs_error_t r0 = SrsSignalManager::instance->pipe_->write(&signo, sizeof(int), NULL);
+ if (r0 != srs_success) {
+ srs_freep(r0); // Ignore any error.
+ }
+
errno = err;
}
@@ -671,7 +687,6 @@ SrsServer::SrsServer()
signal_gmc_stop = false;
signal_fast_quit = false;
signal_gracefully_quit = false;
- pid_fd = -1;
signal_manager = new SrsSignalManager(this);
conn_manager = new SrsResourceManager("TCP", true);
@@ -682,7 +697,6 @@ SrsServer::SrsServer()
// donot new object in constructor,
// for some global instance is not ready now,
// new these objects in initialize instead.
- http_api_mux = new SrsHttpServeMux();
http_server = new SrsHttpServer(this);
http_heartbeat = new SrsHttpHeartbeat();
ingester = new SrsIngester();
@@ -703,17 +717,11 @@ void SrsServer::destroy()
srs_freep(timer_);
dispose();
-
- srs_freep(http_api_mux);
+
srs_freep(http_server);
srs_freep(http_heartbeat);
srs_freep(ingester);
- if (pid_fd > 0) {
- ::close(pid_fd);
- pid_fd = -1;
- }
-
srs_freep(signal_manager);
srs_freep(conn_manager);
@@ -798,16 +806,13 @@ srs_error_t SrsServer::initialize(ISrsServerCycle* ch)
// instead, subscribe handler in initialize method.
srs_assert(_srs_config);
_srs_config->subscribe(this);
-
+
+ // TODO: FIXME: It should be thread-local or thread-safe.
handler = ch;
if(handler && (err = handler->initialize()) != srs_success){
return srs_error_wrap(err, "handler initialize");
}
- if ((err = http_api_mux->initialize()) != srs_success) {
- return srs_error_wrap(err, "http api initialize");
- }
-
if ((err = http_server->initialize()) != srs_success) {
return srs_error_wrap(err, "http server initialize");
}
@@ -836,69 +841,6 @@ srs_error_t SrsServer::initialize_signal()
return signal_manager->initialize();
}
-srs_error_t SrsServer::acquire_pid_file()
-{
- // when srs in dolphin mode, no need the pid file.
- if (_srs_config->is_dolphin()) {
- return srs_success;
- }
-
- std::string pid_file = _srs_config->get_pid_file();
-
- // -rw-r--r--
- // 644
- int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
-
- int fd;
- // open pid file
- if ((fd = ::open(pid_file.c_str(), O_WRONLY | O_CREAT, mode)) == -1) {
- return srs_error_new(ERROR_SYSTEM_PID_ACQUIRE, "open pid file=%s", pid_file.c_str());
- }
-
- // require write lock
- struct flock lock;
-
- lock.l_type = F_WRLCK; // F_RDLCK, F_WRLCK, F_UNLCK
- lock.l_start = 0; // type offset, relative to l_whence
- lock.l_whence = SEEK_SET; // SEEK_SET, SEEK_CUR, SEEK_END
- lock.l_len = 0;
-
- if (fcntl(fd, F_SETLK, &lock) == -1) {
- if(errno == EACCES || errno == EAGAIN) {
- ::close(fd);
- srs_error("srs is already running!");
- return srs_error_new(ERROR_SYSTEM_PID_ALREADY_RUNNING, "srs is already running");
- }
- return srs_error_new(ERROR_SYSTEM_PID_LOCK, "access to pid=%s", pid_file.c_str());
- }
-
- // truncate file
- if (ftruncate(fd, 0) != 0) {
- return srs_error_new(ERROR_SYSTEM_PID_TRUNCATE_FILE, "truncate pid file=%s", pid_file.c_str());
- }
-
- // write the pid
- string pid = srs_int2str(getpid());
- if (write(fd, pid.c_str(), pid.length()) != (int)pid.length()) {
- return srs_error_new(ERROR_SYSTEM_PID_WRITE_FILE, "write pid=%s to file=%s", pid.c_str(), pid_file.c_str());
- }
-
- // auto close when fork child process.
- int val;
- if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
- return srs_error_new(ERROR_SYSTEM_PID_GET_FILE_INFO, "fcntl fd=%d", fd);
- }
- val |= FD_CLOEXEC;
- if (fcntl(fd, F_SETFD, val) < 0) {
- return srs_error_new(ERROR_SYSTEM_PID_SET_FILE_INFO, "lock file=%s fd=%d", pid_file.c_str(), fd);
- }
-
- srs_trace("write pid=%s to %s success!", pid.c_str(), pid_file.c_str());
- pid_fd = fd;
-
- return srs_success;
-}
-
srs_error_t SrsServer::listen()
{
srs_error_t err = srs_success;
@@ -907,14 +849,6 @@ srs_error_t SrsServer::listen()
return srs_error_wrap(err, "rtmp listen");
}
- if ((err = listen_http_api()) != srs_success) {
- return srs_error_wrap(err, "http api listen");
- }
-
- if ((err = listen_https_api()) != srs_success) {
- return srs_error_wrap(err, "https api listen");
- }
-
if ((err = listen_http_stream()) != srs_success) {
return srs_error_wrap(err, "http stream listen");
}
@@ -945,107 +879,10 @@ srs_error_t SrsServer::register_signal()
return err;
}
-srs_error_t SrsServer::http_handle()
-{
- srs_error_t err = srs_success;
-
- 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");
- }
- if ((err = http_api_mux->handle("/api/v1/", new SrsGoApiV1())) != srs_success) {
- return srs_error_wrap(err, "handle v1");
- }
- if ((err = http_api_mux->handle("/api/v1/versions", new SrsGoApiVersion())) != srs_success) {
- return srs_error_wrap(err, "handle versions");
- }
- if ((err = http_api_mux->handle("/api/v1/summaries", new SrsGoApiSummaries())) != srs_success) {
- return srs_error_wrap(err, "handle summaries");
- }
- if ((err = http_api_mux->handle("/api/v1/rusages", new SrsGoApiRusages())) != srs_success) {
- return srs_error_wrap(err, "handle rusages");
- }
- if ((err = http_api_mux->handle("/api/v1/self_proc_stats", new SrsGoApiSelfProcStats())) != srs_success) {
- return srs_error_wrap(err, "handle self proc stats");
- }
- if ((err = http_api_mux->handle("/api/v1/system_proc_stats", new SrsGoApiSystemProcStats())) != srs_success) {
- return srs_error_wrap(err, "handle system proc stats");
- }
- if ((err = http_api_mux->handle("/api/v1/meminfos", new SrsGoApiMemInfos())) != srs_success) {
- return srs_error_wrap(err, "handle meminfos");
- }
- if ((err = http_api_mux->handle("/api/v1/authors", new SrsGoApiAuthors())) != srs_success) {
- return srs_error_wrap(err, "handle authors");
- }
- if ((err = http_api_mux->handle("/api/v1/features", new SrsGoApiFeatures())) != srs_success) {
- return srs_error_wrap(err, "handle features");
- }
- if ((err = http_api_mux->handle("/api/v1/vhosts/", new SrsGoApiVhosts())) != srs_success) {
- return srs_error_wrap(err, "handle vhosts");
- }
- if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) {
- return srs_error_wrap(err, "handle streams");
- }
- if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) {
- return srs_error_wrap(err, "handle clients");
- }
- if ((err = http_api_mux->handle("/api/v1/raw", new SrsGoApiRaw(this))) != srs_success) {
- return srs_error_wrap(err, "handle raw");
- }
- if ((err = http_api_mux->handle("/api/v1/clusters", new SrsGoApiClusters())) != srs_success) {
- return srs_error_wrap(err, "handle clusters");
- }
- if ((err = http_api_mux->handle("/api/v1/perf", new SrsGoApiPerf())) != srs_success) {
- return srs_error_wrap(err, "handle perf");
- }
-#ifdef SRS_GB28181
- if ((err = http_api_mux->handle("/api/v1/gb28181", new SrsGoApiGb28181())) != srs_success) {
- return srs_error_wrap(err, "handle raw");
- }
-#endif
-
- // test the request info.
- if ((err = http_api_mux->handle("/api/v1/tests/requests", new SrsGoApiRequests())) != srs_success) {
- return srs_error_wrap(err, "handle tests requests");
- }
- // test the error code response.
- if ((err = http_api_mux->handle("/api/v1/tests/errors", new SrsGoApiError())) != srs_success) {
- return srs_error_wrap(err, "handle tests errors");
- }
- // test the redirect mechenism.
- if ((err = http_api_mux->handle("/api/v1/tests/redirects", new SrsHttpRedirectHandler("/api/v1/tests/errors", SRS_CONSTS_HTTP_MovedPermanently))) != srs_success) {
- return srs_error_wrap(err, "handle tests redirects");
- }
- // test the http vhost.
- if ((err = http_api_mux->handle("error.srs.com/api/v1/tests/errors", new SrsGoApiError())) != srs_success) {
- return srs_error_wrap(err, "handle tests errors for error.srs.com");
- }
-
-#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) {
- return srs_error_wrap(err, "handle tests errors");
- }
-#endif
-
- // TODO: FIXME: for console.
- // TODO: FIXME: support reload.
- std::string dir = _srs_config->get_http_stream_dir() + "/console";
- if ((err = http_api_mux->handle("/console/", new SrsHttpFileServer(dir))) != srs_success) {
- return srs_error_wrap(err, "handle console at %s", dir.c_str());
- }
- srs_trace("http: api mount /console to %s", dir.c_str());
-
- return err;
-}
-
srs_error_t SrsServer::ingest()
{
srs_error_t err = srs_success;
-
+
if ((err = ingester->start()) != srs_success) {
return srs_error_wrap(err, "ingest start");
}
@@ -1076,12 +913,14 @@ srs_error_t SrsServer::cycle()
{
srs_error_t err = srs_success;
+ // TODO: FIXME: It should be thread-local or thread-safe.
// Start the inotify auto reload by watching config file.
SrsInotifyWorker inotify(this);
if ((err = inotify.start()) != srs_success) {
return srs_error_wrap(err, "start inotify");
}
+ // TODO: FIXME: It should be thread-local or thread-safe.
// Do server main cycle.
err = do_cycle();
@@ -1112,11 +951,12 @@ srs_error_t SrsServer::cycle()
}
srs_trace("srs terminated");
-
+
// for valgrind to detect.
srs_freep(_srs_config);
srs_freep(_srs_log);
+ // TODO: FIXME: Should return to exit the thread, and quit by thread pool manager.
exit(0);
return err;
@@ -1132,7 +972,7 @@ void SrsServer::on_signal(int signo)
#ifndef SRS_GPERF_MC
if (signo == SRS_SIGNAL_REOPEN_LOG) {
- _srs_log->reopen();
+ _srs_async_log->reopen();
if (handler) {
handler->on_logrotate();
@@ -1280,10 +1120,6 @@ srs_error_t SrsServer::setup_ticks()
if ((err = timer_->tick(8, 3 * SRS_UTIME_SECONDS)) != srs_success) {
return srs_error_wrap(err, "tick");
}
-
- if ((err = timer_->tick(10, 9 * SRS_UTIME_SECONDS)) != srs_success) {
- return srs_error_wrap(err, "tick");
- }
}
if (_srs_config->get_heartbeat_enabled()) {
@@ -1305,14 +1141,16 @@ srs_error_t SrsServer::notify(int event, srs_utime_t interval, srs_utime_t tick)
switch (event) {
case 2: srs_update_system_rusage(); break;
- case 3: srs_update_proc_stat(); break;
+ case 3:
+ srs_update_system_proc_stat();
+ srs_update_self_proc_stat();
+ break;
case 4: srs_update_disk_stat(); break;
case 5: srs_update_meminfo(); break;
case 6: srs_update_platform_info(); break;
case 7: srs_update_network_devices(); break;
case 8: resample_kbps(); break;
case 9: http_heartbeat->heartbeat(); break;
- case 10: srs_update_udp_snmp_statistic(); break;
}
return err;
@@ -1343,52 +1181,6 @@ srs_error_t SrsServer::listen_rtmp()
return err;
}
-srs_error_t SrsServer::listen_http_api()
-{
- srs_error_t err = srs_success;
-
- close_listeners(SrsListenerHttpApi);
- if (_srs_config->get_http_api_enabled()) {
- SrsListener* listener = new SrsBufferListener(this, SrsListenerHttpApi);
- listeners.push_back(listener);
-
- std::string ep = _srs_config->get_http_api_listen();
-
- std::string ip;
- int port;
- srs_parse_endpoint(ep, ip, port);
-
- if ((err = listener->listen(ip, port)) != srs_success) {
- return srs_error_wrap(err, "http api listen %s:%d", ip.c_str(), port);
- }
- }
-
- return err;
-}
-
-srs_error_t SrsServer::listen_https_api()
-{
- srs_error_t err = srs_success;
-
- close_listeners(SrsListenerHttpsApi);
- if (_srs_config->get_https_api_enabled()) {
- SrsListener* listener = new SrsBufferListener(this, SrsListenerHttpsApi);
- listeners.push_back(listener);
-
- std::string ep = _srs_config->get_https_api_listen();
-
- std::string ip;
- int port;
- srs_parse_endpoint(ep, ip, port);
-
- if ((err = listener->listen(ip, port)) != srs_success) {
- return srs_error_wrap(err, "https api listen %s:%d", ip.c_str(), port);
- }
- }
-
- return err;
-}
-
srs_error_t SrsServer::listen_http_stream()
{
srs_error_t err = srs_success;
@@ -1570,7 +1362,7 @@ void SrsServer::resample_kbps()
srs_update_rtmp_server((int)conn_manager->size(), kbps);
}
-srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
+srs_error_t SrsServer::accept_tcp_client(SrsListenerType type, srs_netfd_t stfd)
{
srs_error_t err = srs_success;
@@ -1595,11 +1387,6 @@ srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
return err;
}
-SrsHttpServeMux* SrsServer::api_server()
-{
- return http_api_mux;
-}
-
srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, ISrsStartableConneciton** pr)
{
srs_error_t err = srs_success;
@@ -1644,10 +1431,6 @@ srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, IS
if (type == SrsListenerRtmpStream) {
*pr = new SrsRtmpConn(this, stfd, ip, port);
- } else if (type == SrsListenerHttpApi) {
- *pr = new SrsHttpApi(false, this, stfd, http_api_mux, ip, port);
- } else if (type == SrsListenerHttpsApi) {
- *pr = new SrsHttpApi(true, this, stfd, http_api_mux, ip, port);
} else if (type == SrsListenerHttpStream) {
*pr = new SrsResponseOnlyHttpConn(false, this, stfd, http_server, ip, port);
} else if (type == SrsListenerHttpsStream) {
@@ -1687,16 +1470,7 @@ srs_error_t SrsServer::on_reload_listen()
srs_error_t SrsServer::on_reload_pid()
{
srs_error_t err = srs_success;
-
- if (pid_fd > 0) {
- ::close(pid_fd);
- pid_fd = -1;
- }
-
- if ((err = acquire_pid_file()) != srs_success) {
- return srs_error_wrap(err, "reload pid");
- }
-
+ // TODO: FIXME: Do not support reload pid.
return err;
}
@@ -1731,15 +1505,7 @@ srs_error_t SrsServer::on_reload_vhost_removed(std::string /*vhost*/)
srs_error_t SrsServer::on_reload_http_api_enabled()
{
srs_error_t err = srs_success;
-
- if ((err = listen_http_api()) != srs_success) {
- return srs_error_wrap(err, "reload http_api");
- }
-
- if ((err = listen_https_api()) != srs_success) {
- return srs_error_wrap(err, "reload https_api");
- }
-
+ // TODO: FIXME: Remove support for reloading HTTP API.
return err;
}
@@ -1838,14 +1604,12 @@ srs_error_t SrsServerAdapter::run()
return srs_error_wrap(err, "server initialize");
}
+ // TODO: FIXME: It should be thread-local or thread-safe.
if ((err = srs->initialize_st()) != srs_success) {
return srs_error_wrap(err, "initialize st");
}
- if ((err = srs->acquire_pid_file()) != srs_success) {
- return srs_error_wrap(err, "acquire pid file");
- }
-
+ // TODO: FIXME: It should be thread-local or thread-safe.
if ((err = srs->initialize_signal()) != srs_success) {
return srs_error_wrap(err, "initialize signal");
}
@@ -1854,14 +1618,12 @@ srs_error_t SrsServerAdapter::run()
return srs_error_wrap(err, "listen");
}
+ // TODO: FIXME: It should be thread-local or thread-safe.
if ((err = srs->register_signal()) != srs_success) {
return srs_error_wrap(err, "register signal");
}
- if ((err = srs->http_handle()) != srs_success) {
- return srs_error_wrap(err, "http handle");
- }
-
+ // TODO: FIXME: It should be thread-local or thread-safe.
if ((err = srs->ingest()) != srs_success) {
return srs_error_wrap(err, "ingest");
}
@@ -1882,3 +1644,372 @@ SrsServer* SrsServerAdapter::instance()
return srs;
}
+SrsApiServer::SrsApiServer()
+{
+ http_api_mux_ = new SrsHttpServeMux();
+ http_ = new SrsBufferListener(this, SrsListenerHttpApi);
+ https_ = new SrsBufferListener(this, SrsListenerHttpApi);
+ conn_manager_ = new SrsResourceManager("api");
+ lock_ = srs_mutex_new();
+}
+
+SrsApiServer::~SrsApiServer()
+{
+ srs_freep(http_api_mux_);
+ srs_freep(http_);
+ srs_freep(https_);
+ srs_freep(conn_manager_);
+ srs_mutex_destroy(lock_);
+}
+
+srs_error_t SrsApiServer::initialize()
+{
+ srs_error_t err = srs_success;
+
+ if ((err = http_api_mux_->initialize()) != srs_success) {
+ return srs_error_wrap(err, "http api initialize");
+ }
+
+ if ((err = http_handle()) != srs_success) {
+ return srs_error_wrap(err, "http handle");
+ }
+
+ if ((err = listen_api()) != srs_success) {
+ return srs_error_wrap(err, "listen api");
+ }
+
+ if ((err = listen_http_api()) != srs_success) {
+ return srs_error_wrap(err, "http api listen");
+ }
+
+ if ((err = listen_https_api()) != srs_success) {
+ return srs_error_wrap(err, "https api listen");
+ }
+
+ if ((err = conn_manager_->start()) != srs_success) {
+ return srs_error_wrap(err, "connection manager");
+ }
+
+ return err;
+}
+
+srs_error_t SrsApiServer::listen_http_api()
+{
+ srs_error_t err = srs_success;
+
+ if (!_srs_config->get_http_api_enabled()) {
+ return err;
+ }
+
+ std::string ep = _srs_config->get_http_api_listen();
+
+ std::string ip;
+ int port;
+ srs_parse_endpoint(ep, ip, port);
+
+ if ((err = http_->listen(ip, port)) != srs_success) {
+ return srs_error_wrap(err, "http api listen %s:%d", ip.c_str(), port);
+ }
+
+ return err;
+}
+
+srs_error_t SrsApiServer::listen_https_api()
+{
+ srs_error_t err = srs_success;
+
+ if (!_srs_config->get_https_api_enabled()) {
+ return err;
+ }
+
+ std::string ep = _srs_config->get_https_api_listen();
+
+ std::string ip;
+ int port;
+ srs_parse_endpoint(ep, ip, port);
+
+ if ((err = https_->listen(ip, port)) != srs_success) {
+ return srs_error_wrap(err, "https api listen %s:%d", ip.c_str(), port);
+ }
+
+ return err;
+}
+
+srs_error_t SrsApiServer::accept_tcp_client(SrsListenerType type, srs_netfd_t stfd)
+{
+ srs_error_t err = srs_success;
+
+ ISrsStartableConneciton* conn = NULL;
+
+ if ((err = fd_to_resource(type, stfd, &conn)) != srs_success) {
+ if (srs_error_code(err) == ERROR_SOCKET_GET_PEER_IP && _srs_config->empty_ip_ok()) {
+ srs_close_stfd(stfd); srs_error_reset(err);
+ return srs_success;
+ }
+ return srs_error_wrap(err, "fd to resource");
+ }
+ srs_assert(conn);
+
+ // directly enqueue, the cycle thread will remove the client.
+ conn_manager_->add(conn);
+
+ if ((err = conn->start()) != srs_success) {
+ return srs_error_wrap(err, "start conn coroutine");
+ }
+
+ return err;
+}
+
+srs_error_t SrsApiServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, ISrsStartableConneciton** pr)
+{
+ srs_error_t err = srs_success;
+
+ int fd = srs_netfd_fileno(stfd);
+ string ip = srs_get_peer_ip(fd);
+ int port = srs_get_peer_port(fd);
+
+ // for some keep alive application, for example, the keepalived,
+ // will send some tcp packet which we cann't got the ip,
+ // we just ignore it.
+ if (ip.empty()) {
+ return srs_error_new(ERROR_SOCKET_GET_PEER_IP, "ignore empty ip, fd=%d", fd);
+ }
+
+ // avoid fd leak when fork.
+ // @see https://github.com/ossrs/srs/issues/518
+ if (true) {
+ int val;
+ if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
+ return srs_error_new(ERROR_SYSTEM_PID_GET_FILE_INFO, "fnctl F_GETFD error! fd=%d", fd);
+ }
+ val |= FD_CLOEXEC;
+ if (fcntl(fd, F_SETFD, val) < 0) {
+ return srs_error_new(ERROR_SYSTEM_PID_SET_FILE_INFO, "fcntl F_SETFD error! fd=%d", fd);
+ }
+ }
+
+ // The context id may change during creating the bellow objects.
+ SrsContextRestore(_srs_context->get_id());
+
+ if (type == SrsListenerHttpApi) {
+ *pr = new SrsHttpApi(false, this, stfd, http_api_mux_, ip, port);
+ } else if (type == SrsListenerHttpsApi) {
+ *pr = new SrsHttpApi(true, this, stfd, http_api_mux_, ip, port);
+ } else {
+ srs_warn("close for no service handler. fd=%d, ip=%s:%d", fd, ip.c_str(), port);
+ srs_close_stfd(stfd);
+ return err;
+ }
+
+ return err;
+}
+
+void SrsApiServer::remove(ISrsResource* c)
+{
+ conn_manager_->remove(c);
+}
+
+srs_error_t SrsApiServer::http_handle()
+{
+ srs_error_t err = srs_success;
+
+ 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");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/", new SrsGoApiV1())) != srs_success) {
+ return srs_error_wrap(err, "handle v1");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/versions", new SrsGoApiVersion())) != srs_success) {
+ return srs_error_wrap(err, "handle versions");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/summaries", new SrsGoApiSummaries())) != srs_success) {
+ return srs_error_wrap(err, "handle summaries");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/rusages", new SrsGoApiRusages())) != srs_success) {
+ return srs_error_wrap(err, "handle rusages");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/self_proc_stats", new SrsGoApiSelfProcStats())) != srs_success) {
+ return srs_error_wrap(err, "handle self proc stats");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/system_proc_stats", new SrsGoApiSystemProcStats())) != srs_success) {
+ return srs_error_wrap(err, "handle system proc stats");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/meminfos", new SrsGoApiMemInfos())) != srs_success) {
+ return srs_error_wrap(err, "handle meminfos");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/authors", new SrsGoApiAuthors())) != srs_success) {
+ return srs_error_wrap(err, "handle authors");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/features", new SrsGoApiFeatures())) != srs_success) {
+ return srs_error_wrap(err, "handle features");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/vhosts/", new SrsGoApiVhosts())) != srs_success) {
+ return srs_error_wrap(err, "handle vhosts");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) {
+ return srs_error_wrap(err, "handle streams");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) {
+ return srs_error_wrap(err, "handle clients");
+ }
+ // TODO: FIXME: Implements it.
+ //if ((err = http_api_mux_->handle("/api/v1/raw", new SrsGoApiRaw(this))) != srs_success) {
+ // return srs_error_wrap(err, "handle raw");
+ //}
+ if ((err = http_api_mux_->handle("/api/v1/clusters", new SrsGoApiClusters())) != srs_success) {
+ return srs_error_wrap(err, "handle clusters");
+ }
+ if ((err = http_api_mux_->handle("/api/v1/perf", new SrsGoApiPerf())) != srs_success) {
+ return srs_error_wrap(err, "handle perf");
+ }
+#ifdef SRS_GB28181
+ if ((err = http_api_mux_->handle("/api/v1/gb28181", new SrsGoApiGb28181())) != srs_success) {
+ return srs_error_wrap(err, "handle raw");
+ }
+#endif
+
+ // test the request info.
+ if ((err = http_api_mux_->handle("/api/v1/tests/requests", new SrsGoApiRequests())) != srs_success) {
+ return srs_error_wrap(err, "handle tests requests");
+ }
+ // test the error code response.
+ if ((err = http_api_mux_->handle("/api/v1/tests/errors", new SrsGoApiError())) != srs_success) {
+ return srs_error_wrap(err, "handle tests errors");
+ }
+ // test the redirect mechenism.
+ if ((err = http_api_mux_->handle("/api/v1/tests/redirects", new SrsHttpRedirectHandler("/api/v1/tests/errors", SRS_CONSTS_HTTP_MovedPermanently))) != srs_success) {
+ return srs_error_wrap(err, "handle tests redirects");
+ }
+ // test the http vhost.
+ if ((err = http_api_mux_->handle("error.srs.com/api/v1/tests/errors", new SrsGoApiError())) != srs_success) {
+ return srs_error_wrap(err, "handle tests errors for error.srs.com");
+ }
+
+#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) {
+ return srs_error_wrap(err, "handle tests errors");
+ }
+#endif
+
+ // TODO: FIXME: for console.
+ // TODO: FIXME: support reload.
+ std::string dir = _srs_config->get_http_stream_dir() + "/console";
+ if ((err = http_api_mux_->handle("/console/", new SrsHttpFileServer(dir))) != srs_success) {
+ return srs_error_wrap(err, "handle console at %s", dir.c_str());
+ }
+ srs_trace("http: api mount /console to %s", dir.c_str());
+
+ return err;
+}
+
+srs_error_t SrsApiServer::listen_api()
+{
+ srs_error_t err = srs_success;
+
+ 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
+ // TODO: FIXME: Implements it.
+ //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 SrsApiServer::create_session(SrsRtcUserConfig* ruc, SrsSdp& local_sdp, SrsRtcConnection** psession) {
+ srs_error_t err = srs_success;
+
+ SrsRequest* req = ruc->req_;
+
+ // TODO: FIXME: Should update the hybrids for RTMP streams.
+ // Serve all connections of a stream, which identified by url, by the same hybrid thread.
+ string url = req->get_stream_url();
+ SrsThreadEntry* hybrid = NULL;
+ if (true) {
+ map::iterator it = hybrids_.find(url);
+ if (it == hybrids_.end()) {
+ static int index = 0;
+ vector hybrids = _srs_thread_pool->hybrids();
+ hybrids_[url] = hybrid = hybrids[(index++) % (int)hybrids.size()];
+ } else {
+ hybrid = it->second;
+ }
+ }
+
+ // Allocate slot to communicate with hybrid thread.
+ SrsThreadEntry* self = _srs_thread_pool->self();
+ srs_assert(self && hybrid);
+
+ SrsThreadPipeChannel* channel = NULL;
+ if (true) {
+ map::iterator it = self->channels_.find(hybrid->trd);
+ if (it == self->channels_.end()) {
+ self->channels_[hybrid->trd] = channel = hybrid->slot_->allocate();
+ } else {
+ channel = it->second;
+ }
+ }
+ srs_assert(channel);
+
+ // We're initiator, write to initiator, read from responder.
+ if ((err = channel->initiator()->open_write()) != srs_success) {
+ return srs_error_wrap(err, "open write");
+ }
+ if ((err = channel->responder()->open_read()) != srs_success) {
+ return srs_error_wrap(err, "open read");
+ }
+
+ SrsThreadMessageRtcCreateSession s;
+ s.ruc = ruc;
+ s.local_sdp = &local_sdp;
+ s.session = NULL;
+
+ SrsThreadMessage m;
+ m.id = (uint64_t)SrsThreadMessageIDRtcCreateSession;
+ m.ptr = (uint64_t)&s;
+
+ if (true) {
+ // Process api request one by one.
+ // TODO: FIXME: The lock too big? Write log and error?
+ SrsLocker(lock_);
+
+ // We're initiator, write to initiator, read from responder.
+ // TODO: FIXME: Write important logs, and error response, and timeout?
+ if ((err = channel->initiator()->write(&m, sizeof(m), NULL)) != srs_success) {
+ return srs_error_wrap(err, "write");
+ }
+
+ // TODO: FIXME: Write important logs, and error response, and timeout?
+ // TODO: FIXME: If play a invalid stream, api will be blocked.
+ if ((err = channel->responder()->read(&m, sizeof(m), NULL)) != srs_success) {
+ return srs_error_wrap(err, "read");
+ }
+ }
+
+ // Covert to output params.
+ // TODO: FIMXE: Should never return it, for it's not thread-safe.
+ *psession = s.session;
+
+ // TODO: FIXME: Shoule return detail error by channel.
+ if (!s.session) {
+ return srs_error_new(ERROR_PIPE_READ, "no session");
+ }
+
+ return err;
+}
+
+SrsApiServer* _srs_api = new SrsApiServer();
+
diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp
index 4c3986a4e7..40426b936b 100644
--- a/trunk/src/app/srs_app_server.hpp
+++ b/trunk/src/app/srs_app_server.hpp
@@ -28,6 +28,7 @@
#include
#include
+#include