From 93aa0eb5ba7b089105f54080d02a891e8e8ae81b Mon Sep 17 00:00:00 2001
From: winlin <winlin@vip.126.com>
Date: Thu, 13 Jan 2022 18:26:28 +0800
Subject: [PATCH] Squash: Fix bugs

---
 .github/workflows/release.yml                 |   8 +-
 README.md                                     |   1 +
 trunk/Dockerfile                              |   2 +
 trunk/Dockerfile.pkg                          |   4 +-
 trunk/auto/auto_headers.sh                    |   1 +
 trunk/auto/options.sh                         |   4 +
 trunk/conf/vm.conf                            |  48 +++++++
 trunk/configure                               |   4 +-
 trunk/doc/CHANGELOG.md                        |   9 +-
 trunk/etc/init.d/srs-api                      | 127 ------------------
 .../research/api-server/static-dir/index.html |  82 ++++++++---
 trunk/research/players/js/srs.page.js         |   6 +-
 trunk/research/players/js/srs.sdk.js          |  13 ++
 trunk/scripts/install.sh                      |   2 +-
 trunk/src/app/srs_app_config.cpp              |   2 +-
 trunk/src/app/srs_app_rtc_api.cpp             |   9 +-
 trunk/src/app/srs_app_rtc_conn.cpp            |  12 +-
 trunk/src/app/srs_app_rtc_source.cpp          |   9 +-
 trunk/src/app/srs_app_rtc_source.hpp          |   3 +-
 trunk/src/app/srs_app_source.cpp              |   9 +-
 trunk/src/app/srs_app_source.hpp              |   1 -
 trunk/src/core/srs_core_autofree.hpp          |  18 ++-
 trunk/src/core/srs_core_version4.hpp          |   2 +-
 trunk/src/core/srs_core_version5.hpp          |   2 +-
 trunk/src/main/srs_main_server.cpp            |   4 +-
 25 files changed, 198 insertions(+), 184 deletions(-)
 create mode 100644 trunk/conf/vm.conf
 delete mode 100755 trunk/etc/init.d/srs-api

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9353fdf47..d1d398a41 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -50,8 +50,10 @@ jobs:
       #   SRS_PACKAGE_ZIP=SRS-CentOS7-x86_64-4.0.145.zip
       #   SRS_PACKAGE_MD5=3880a26e30b283edf05700a4e69956e5
       - name: Create package zip
+        env:
+          PACKAGER: ${{ secrets.SRS_PACKAGER_BINARY }}
         run: |
-          docker build --tag srs:pkg --build-arg version=$SRS_VERSION -f trunk/Dockerfile.pkg . &&
+          docker build --tag srs:pkg --build-arg version=$SRS_VERSION --build-arg SRS_AUTO_PACKAGER=$PACKAGER -f trunk/Dockerfile.pkg . &&
           SRS_PACKAGE_ZIP=SRS-CentOS7-x86_64-$SRS_VERSION.zip &&
           docker run --rm -v $(pwd):/output srs:pkg cp objs/$SRS_PACKAGE_ZIP /output/ &&
           du -sh $SRS_PACKAGE_ZIP &&
@@ -73,9 +75,11 @@ jobs:
       # Build
       # Build SRS image
       - name: Build SRS docker image
+        env:
+          PACKAGER: ${{ secrets.SRS_PACKAGER_DOCKER }}
         run: |
           echo "Release ossrs/srs:$SRS_TAG"
-          docker build --tag ossrs/srs:$SRS_TAG -f trunk/Dockerfile .
+          docker build --tag ossrs/srs:$SRS_TAG --build-arg SRS_AUTO_PACKAGER=$PACKAGER -f trunk/Dockerfile .
 
       ################################################################
       # Docker
diff --git a/README.md b/README.md
index 5884efe13..4d1e7fd75 100755
--- a/README.md
+++ b/README.md
@@ -125,6 +125,7 @@ A big `THANK YOU` also goes to:
 
 ## Releases
 
+* 2022-01-13, Release [v4.0-b3](https://github.com/ossrs/srs/releases/tag/v4.0-b3), v4.0-b3, 4.0 beta3, v4.0.229, 144393 lines.
 * 2022-01-03, Release [v4.0-b2](https://github.com/ossrs/srs/releases/tag/v4.0-b2), v4.0-b2, 4.0 beta2, v4.0.215, 144278 lines.
 * 2021-12-19, Release [v4.0-b1](https://github.com/ossrs/srs/releases/tag/v4.0-b1), v4.0-b1, 4.0 beta1, v4.0.206, 144126 lines.
 * 2021-12-01, Release [v4.0-b0](https://github.com/ossrs/srs/releases/tag/v4.0-b0), v4.0-b0, 4.0 beta0, v4.0.201, 144022 lines.
diff --git a/trunk/Dockerfile b/trunk/Dockerfile
index bd37ef08c..922cf2eed 100644
--- a/trunk/Dockerfile
+++ b/trunk/Dockerfile
@@ -3,6 +3,8 @@ FROM ossrs/srs:dev AS build
 # Install depends tools.
 RUN yum install -y gcc make gcc-c++ patch unzip perl git
 
+ARG SRS_AUTO_PACKAGER
+
 # Build and install SRS.
 COPY . /srs
 WORKDIR /srs/trunk
diff --git a/trunk/Dockerfile.pkg b/trunk/Dockerfile.pkg
index ade5778cd..1fb3d600a 100644
--- a/trunk/Dockerfile.pkg
+++ b/trunk/Dockerfile.pkg
@@ -2,13 +2,11 @@ FROM ossrs/srs:dev
 
 # version=4.0.145
 ARG version
+ARG SRS_AUTO_PACKAGER
 
 # Install depends tools.
 RUN yum install -y zip
 
-# Setup the packager env.
-ENV SRS_AUTO_PACKAGER ossrs
-
 # Build and install SRS.
 ADD srs-server-${version}.tar.gz /srs
 WORKDIR /srs/srs-server-${version}/trunk
diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh
index 6c2125755..73bc0ae3f 100755
--- a/trunk/auto/auto_headers.sh
+++ b/trunk/auto/auto_headers.sh
@@ -177,6 +177,7 @@ fi
 # prefix
 echo "" >> $SRS_AUTO_HEADERS_H
 echo "#define SRS_PREFIX \"${SRS_PREFIX}\"" >> $SRS_AUTO_HEADERS_H
+echo "#define SRS_DEFAULT_CONFIG \"${SRS_DEFAULT_CONFIG}\"" >> $SRS_AUTO_HEADERS_H
 
 echo "" >> $SRS_AUTO_HEADERS_H
 
diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh
index 2152c4f08..59bc9f7d5 100755
--- a/trunk/auto/options.sh
+++ b/trunk/auto/options.sh
@@ -36,6 +36,7 @@ SRS_FFMPEG_TOOL=NO
 SRS_FFMPEG_FIT=RESERVED
 # arguments
 SRS_PREFIX=/usr/local/srs
+SRS_DEFAULT_CONFIG=conf/srs.conf
 SRS_JOBS=1
 SRS_STATIC=NO
 # If enabled, link shared libraries for libst.so which uses MPL license.
@@ -127,6 +128,7 @@ Features:
   --ffmpeg-fit=on|off       Whether enable the FFmpeg fit(source code). Default: $(value2switch $SRS_FFMPEG_FIT)
 
   --prefix=<path>           The absolute installation path. Default: $SRS_PREFIX
+  --config=<path>           The default config file for SRS. Default: $SRS_DEFAULT_CONFIG
   --gcov=on|off             Whether enable the GCOV compiler options. Default: $(value2switch $SRS_GCOV)
   --debug=on|off            Whether enable the debug code, may hurt performance. Default: $(value2switch $SRS_DEBUG)
   --debug-stats=on|off      Whether enable the debug stats, may hurt performance. Default: $(value2switch $SRS_DEBUG_STATS)
@@ -220,6 +222,7 @@ function parse_user_option() {
         
         --jobs)                         SRS_JOBS=${value}           ;;
         --prefix)                       SRS_PREFIX=${value}         ;;
+        --config)                       SRS_DEFAULT_CONFIG=${value} ;;
 
         --static)                       SRS_STATIC=$(switch2value $value) ;;
         --cpu)                          SRS_CROSS_BUILD_CPU=${value} ;;
@@ -495,6 +498,7 @@ function regenerate_options() {
     SRS_AUTO_USER_CONFIGURE=`echo $opt`
     # regenerate the options for default values.
     SRS_AUTO_CONFIGURE="--prefix=${SRS_PREFIX}"
+    SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --config=$SRS_DEFAULT_CONFIG"
     SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --hls=$(value2switch $SRS_HLS)"
     SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --hds=$(value2switch $SRS_HDS)"
     SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --dvr=$(value2switch $SRS_DVR)"
diff --git a/trunk/conf/vm.conf b/trunk/conf/vm.conf
new file mode 100644
index 000000000..fd363e350
--- /dev/null
+++ b/trunk/conf/vm.conf
@@ -0,0 +1,48 @@
+
+listen              1935;
+max_connections     1000;
+daemon              on;
+srs_log_tank        file;
+
+# For LightHouse VM to run SRS, never enable docker.
+in_docker off;
+disable_daemon_for_docker off;
+auto_reload_for_docker off;
+
+http_server {
+    enabled         on;
+    listen          8080;
+    dir             ./objs/nginx/html;
+}
+
+http_api {
+    enabled         on;
+    listen          1985;
+}
+stats {
+    network         0;
+}
+rtc_server {
+    enabled on;
+    listen 8000; # UDP port
+    # @see https://github.com/ossrs/srs/wiki/v4_CN_WebRTC#config-candidate
+    candidate $CANDIDATE;
+}
+
+vhost __defaultVhost__ {
+    hls {
+        enabled         on;
+    }
+    http_remux {
+        enabled     on;
+        mount       [vhost]/[app]/[stream].flv;
+    }
+    rtc {
+        enabled     on;
+        # @see https://github.com/ossrs/srs/wiki/v4_CN_WebRTC#rtmp-to-rtc
+        rtmp_to_rtc on;
+        # @see https://github.com/ossrs/srs/wiki/v4_CN_WebRTC#rtc-to-rtmp
+        rtc_to_rtmp on;
+    }
+}
+
diff --git a/trunk/configure b/trunk/configure
index efcdbf7bb..d71715c54 100755
--- a/trunk/configure
+++ b/trunk/configure
@@ -460,6 +460,7 @@ CXXFLAGS = ${CXXFLAGS}
 
 # install prefix.
 SRS_PREFIX=${SRS_PREFIX}
+SRS_DEFAULT_CONFIG=${SRS_DEFAULT_CONFIG}
 __REAL_INSTALL=\$(DESTDIR)\$(SRS_PREFIX)
 
 default: server
@@ -592,11 +593,12 @@ install:
 	@mkdir -p \$(__REAL_INSTALL)/etc/init.d
 	@cp -f etc/init.d/srs \$(__REAL_INSTALL)/etc/init.d
 	@sed -i "s|^ROOT=.*|ROOT=\"\$(SRS_PREFIX)\"|g" \$(__REAL_INSTALL)/etc/init.d/srs
+	@sed -i "s|^CONFIG=.*|CONFIG=\"\$(SRS_DEFAULT_CONFIG)\"|g" \$(__REAL_INSTALL)/etc/init.d/srs
 	@echo "Now copy systemctl service files"
 	@mkdir -p \$(__REAL_INSTALL)/usr/lib/systemd/system
 	@cp -f usr/lib/systemd/system/srs.service \$(__REAL_INSTALL)/usr/lib/systemd/system/srs.service
 	@echo ""
-	@echo "@see: https://github.com/ossrs/srs/wiki/v3_CN_LinuxService"
+	@echo "@see: https://github.com/ossrs/srs/wiki/v4_CN_LinuxService"
 
 END
 
diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md
index 25d306570..47371c13b 100644
--- a/trunk/doc/CHANGELOG.md
+++ b/trunk/doc/CHANGELOG.md
@@ -30,7 +30,14 @@ The changelog for SRS.
 
 ## SRS 4.0 Changelog
 
-* v4.0, 2022-01-20, Merge [#2863](https://github.com/ossrs/srs/pull/2863): RTC: fix play crash or no stream for rtmp2rtc tips.(#2863). v4.0.220
+* v4.0, 2022-01-13, Merge [#2872](https://github.com/ossrs/srs/pull/2872): RTC: fix play rtc judge for config rtc2rtmp on. (#2872). v4.0.229
+* v4.0, 2022-01-13, Support configure with --config as default config file. v4.0.227
+* v4.0, 2022-01-13, For [#2880](https://github.com/ossrs/srs/pull/2880): Add SrsAutoFreeH to release ptr with hooks. (#2880). v4.0.226
+* v4.0, 2022-01-13, Support api_port to specify the WebRTC API port. v4.0.224
+* v4.0, 2022-01-13, Merge [#2873](https://github.com/ossrs/srs/pull/2873): LiveSource: Refine fetch for external exposed interface. (#2873). v4.0.223
+* v4.0, 2022-01-13, Add conf/vm.conf for cloud virtual machine. v4.0.222
+* v4.0, 2022-01-12, Refine the running homepage. v4.0.221
+* v4.0, 2022-01-12, Merge [#2863](https://github.com/ossrs/srs/pull/2863): RTC: fix play crash or no stream for rtmp2rtc tips. (#2863). v4.0.220
 * v4.0, 2022-01-05, For [#2717](https://github.com/ossrs/srs/issues/2717): When reopening segment, never update the duration. (#2717). v4.0.219
 * v4.0, 2022-01-04, Discover api server and ip as candidates. v4.0.218
 * v4.0, 2022-01-04, Install test-on self-sign certificate. v4.0.217
diff --git a/trunk/etc/init.d/srs-api b/trunk/etc/init.d/srs-api
deleted file mode 100755
index 64e5413c7..000000000
--- a/trunk/etc/init.d/srs-api
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-### BEGIN INIT INFO
-# Provides:          ossrs-api(srs-api)
-# Required-Start:    $all
-# Required-Stop:     $all
-# Default-Start:     2 3 4 5
-# Default-Stop:      0 1 6
-# Short-Description: ossrs-api(srs-api)
-# Description:       https://github.com/ossrs/srs
-### END INIT INFO
-
-# the config of ROOT, user must modify it when start srs from other directory,
-# it's ok to use the script by command ./etc/init.d/ossrs
-ROOT="./"
-APP="python ./research/api-server/server.py"
-CONFIG="8085"
-
-########################################################################
-# utility functions
-########################################################################
-RED="\\033[31m"
-GREEN="\\033[32m"
-YELLOW="\\033[33m"
-BLACK="\\033[0m"
-POS="\\033[60G"
-
-ok_msg(){
-    echo -e "${1}${POS}${BLACK}[${GREEN}  OK  ${BLACK}]"
-}
-
-failed_msg(){
-    echo -e "${1}${POS}${BLACK}[${RED}FAILED${BLACK}]"
-}
-
-# load process info of srs-api
-# @set variable $srs_api_id to the process id.
-# @return 0, if process exists; otherwise:
-#       1, for srs-api not exists.
-# @set variable $error_msg if error.
-load_process_info() {
-    srs_api_id=`ps aux|grep python|grep research|grep "api-server"|awk '{print $2}'`
-    if [[ -z $srs_api_id ]]; then error_msg="srs-api process does not exists"; return 1; fi
-    
-    return 0;
-}
-
-start() {
-    # if exists, exit.
-    load_process_info
-    if [[ 0 -eq $? ]]; then failed_msg "SRS-api started(pid ${srs_api_id}), should not start it again."; return 0; fi
-    
-    # not exists, start server
-    ok_msg "Starting SRS-api..."
-    # TODO: FIXME: set limit by, for instance, "ulimit -HSn 10000"
-    # TODO: FIXME: write log to, for instance, the same dir of log.
-    # TODO: FIXME: support daemon, without nohup.
-    (cd ${ROOT}; nohup ${APP} ${CONFIG} >/dev/null 2>&1 &)
-    
-    # check again after start server
-    load_process_info
-    ret=$?; if [[ 0 -eq $? ]]; then ok_msg "SRS-api started(pid ${srs_api_id})"; return 0; fi
-    
-    failed_msg "SRS-api not started"
-    return $ret
-}
-
-stop() {
-    # not start, exit
-    load_process_info
-    if [[ 0 -ne $? ]]; then failed_msg "SRS-api not start."; return 0; fi
-    
-    ok_msg "Stopping SRS-api(pid ${srs_api_id})..."
-    
-    # process exists, kill util stop
-    for((;;)); do
-        load_process_info
-        if [[ 0 -eq $? ]]; then
-            kill -s SIGKILL ${srs_api_id} 2>/dev/null
-            ret=$?; if [[ 0 -ne $ret ]]; then failed_msg "send signal SIGKILL failed ret=$ret"; return $ret; fi
-            sleep 0.1
-        else
-            ok_msg "SRS-api stopped"
-            break;
-        fi
-    done
-    
-    sleep 0.1
-    return 0
-}
-
-# get the status of srs-api process
-# @return 0 if srs-api is running; otherwise, 1 for stopped.
-status() {
-    load_process_info
-    ret=$?; if [[ 0 -eq $ret ]]; then echo "SRS-api(pid ${srs_api_id}) is running."; return 0; fi
-    
-    echo "SRS-api is stopped"
-    return 1
-}
-
-menu() {
-    case "$1" in
-        start)
-            start
-            ;;
-        stop)
-            stop
-            ;;
-        restart)
-            stop
-            start
-            ;;
-        status)
-            status
-            ;;
-        *)
-            echo "Usage: $0 {start|stop|status|restart}"
-            return 1
-            ;;
-    esac
-}
-
-menu $1
-
-code=$?
-exit ${code}
diff --git a/trunk/research/api-server/static-dir/index.html b/trunk/research/api-server/static-dir/index.html
index e73a6e75b..8d92fc12c 100755
--- a/trunk/research/api-server/static-dir/index.html
+++ b/trunk/research/api-server/static-dir/index.html
@@ -3,24 +3,70 @@
 <head>
     <title>SRS</title>
     <meta charset="utf-8">
+    <style>
+        .span6 {
+            width: 480px;
+        }
+        .code {
+            background-color: rgb(246 248 250);
+            padding: 8px;
+            overflow: auto;
+            font-size: 85%;
+            line-height: 1.45;
+            border-radius: 6px;
+            word-break: normal;
+            word-wrap: normal;
+            box-sizing: border-box;
+            display: block;
+            white-space: pre;
+        }
+    </style>
 </head>
 <body>
-<h3><a href="https://github.com/ossrs/srs">SRS</a> works!</h3>
-<p>
-    Click <a id="en" href="#">here</a> to enter SRS console.<br/>
-    点击进入<a id="cn" href="#">SRS控制台</a>
-</p>
-<p>
-    Click <a href="players/?autostart=true">here</a> to start SRS player.<br/>
-    点击进入<a href="players/?autostart=true">SRS播放器</a>
-</p>
-<p><a href="https://github.com/ossrs/srs">SRS Team &copy; 2021</a></p>
-<script type="text/javascript">
-    // http://localhost:8080/console/ng_index.html#/connect?port=1985
-    // http://localhost:8080/console/ng_index.html#/summaries?port=1985
-    var en_url = window.location.protocol + "//" + window.location.host + "/console/en_index.html#/summaries?port=1985";
-    var cn_url = window.location.protocol + "//" + window.location.host + "/console/ng_index.html#/summaries?port=1985";
-    document.getElementById("en").setAttribute('href', en_url);
-    document.getElementById("cn").setAttribute('href', cn_url);
-</script>
+    <div>
+        <h3><a href="https://github.com/ossrs/srs">SRS</a> works!</h3>
+        <p>
+            Click <a id="enConsole" href="#">here</a> to enter SRS console.<br/>
+            点击进入<a id="cnConsole" href="#">SRS控制台</a>
+        </p>
+        <p>
+            Publish stream by <a href="https://ffmpeg.org/download.html">FFmpeg</a> or <a href="https://obsproject.com/download">OBS</a>:<br/>
+            请使用工具<a href="https://ffmpeg.org/download.html">FFmpeg</a>或者<a href="https://obsproject.com/download">OBS</a>推流到下面地址:
+            <pre id="url" class="code span6"></pre>
+        </p>
+        <p>
+            Click <a id="enPlayer" href="#">here</a> to start SRS player.<br/>
+            点击进入<a id="cnPlayer" href="#">SRS播放器</a>
+        </p>
+        <p><a href="https://github.com/ossrs/srs">SRS Team &copy; 2022</a></p>
+    </div>
+    <script type="text/javascript">
+        // Build RTMP url.
+        if (true) {
+            const rtmpUrl = `rtmp://${window.location.hostname}/live/livestream`;
+            document.getElementById('url').innerText = rtmpUrl;
+        }
+
+        // Build console url.
+        if (true) {
+            // The prefix for default website.
+            const prefix = `${window.location.protocol}//${window.location.host}`;
+            // If not 8080, user should proxy to the default port.
+            const query = parseInt(window.location.port) === 8080 ? `?port=1985` : '';
+            const enUrl = `${prefix}/console/en_index.html#/summaries${query}`;
+            const cnUrl = `${prefix}/console/ng_index.html#/summaries${query}`;
+            document.getElementById("enConsole").setAttribute('href', enUrl);
+            document.getElementById("cnConsole").setAttribute('href', cnUrl);
+        }
+
+        // The player url.
+        if (true) {
+            const prefix = `players/?schema=${window.location.protocol.replace(':', '')}`;
+            const httpPort = window.location.port || (window.location.protocol === 'http:' ? 80 : 443);
+            // If not 8080, user should proxy both stream and API to the default port.
+            const query = parseInt(window.location.port) === 8080 ? '' : `&port=${httpPort}&api=${httpPort}`;
+            document.getElementById("enPlayer").setAttribute('href', `${prefix}${query}`);
+            document.getElementById("cnPlayer").setAttribute('href', `${prefix}${query}`);
+        }
+    </script>
 </body>
diff --git a/trunk/research/players/js/srs.page.js b/trunk/research/players/js/srs.page.js
index 26b3971e1..d680f3cbd 100755
--- a/trunk/research/players/js/srs.page.js
+++ b/trunk/research/players/js/srs.page.js
@@ -24,7 +24,7 @@ function update_nav() {
 }
 
 // Special extra params, such as auth_key.
-function user_extra_params(query, params) {
+function user_extra_params(query, params, rtc) {
     var queries = params || [];
 
     for (var key in query.user_query) {
@@ -90,6 +90,8 @@ function build_default_flv_url() {
 function build_default_rtc_url(query) {
     // The format for query string to overwrite configs of server.
     console.log('?eip=x.x.x.x to overwrite candidate. 覆盖服务器candidate(外网IP)配置');
+    console.log('?api=x to overwrite WebRTC API(1985).');
+    console.log('?schema=http|https to overwrite WebRTC API protocol.');
 
     var server = (!query.server)? window.location.hostname:query.server;
     var vhost = (!query.vhost)? window.location.hostname:query.vhost;
@@ -104,7 +106,7 @@ function build_default_rtc_url(query) {
     if (query.schema && window.location.protocol !== query.schema + ':') {
         queries.push('schema=' + query.schema);
     }
-    queries = user_extra_params(query, queries);
+    queries = user_extra_params(query, queries, true);
 
     var uri = "webrtc://" + server + api + "/" + app + "/" + stream + "?" + queries.join('&');
     while (uri.lastIndexOf("?") === uri.length - 1) {
diff --git a/trunk/research/players/js/srs.sdk.js b/trunk/research/players/js/srs.sdk.js
index ed5276b50..5cda7947c 100644
--- a/trunk/research/players/js/srs.sdk.js
+++ b/trunk/research/players/js/srs.sdk.js
@@ -185,6 +185,12 @@ function SrsRtcPublisherAsync() {
 
             var port = a.port;
             if (!port) {
+                // Finger out by webrtc url, if contains http or https port, to overwrite default 1985.
+                if (schema === 'webrtc' && url.indexOf(`webrtc://${a.host}:`) === 0) {
+                    port = (url.indexOf(`webrtc://${a.host}:80`) === 0) ? 80 : 443;
+                }
+
+                // Guess by schema.
                 if (schema === 'http') {
                     port = 80;
                 } else if (schema === 'https') {
@@ -267,6 +273,7 @@ function SrsRtcPlayerAsync() {
     //      webrtc://r.ossrs.net/live/livestream
     // or specifies the API port:
     //      webrtc://r.ossrs.net:11985/live/livestream
+    //      webrtc://r.ossrs.net:80/live/livestream
     // or autostart the play:
     //      webrtc://r.ossrs.net/live/livestream?autostart=true
     // or change the app from live to myapp:
@@ -413,6 +420,12 @@ function SrsRtcPlayerAsync() {
 
             var port = a.port;
             if (!port) {
+                // Finger out by webrtc url, if contains http or https port, to overwrite default 1985.
+                if (schema === 'webrtc' && url.indexOf(`webrtc://${a.host}:`) === 0) {
+                    port = (url.indexOf(`webrtc://${a.host}:80`) === 0) ? 80 : 443;
+                }
+
+                // Guess by schema.
                 if (schema === 'http') {
                     port = 80;
                 } else if (schema === 'https') {
diff --git a/trunk/scripts/install.sh b/trunk/scripts/install.sh
index 6f161b13f..416c6537d 100755
--- a/trunk/scripts/install.sh
+++ b/trunk/scripts/install.sh
@@ -129,7 +129,7 @@ else
 fi
 
 echo ""
-echo "see: https://github.com/ossrs/srs/wiki/v3_CN_LinuxService"
+echo "see: https://github.com/ossrs/srs/wiki/v4_CN_LinuxService"
 echo "install success, you can start SRS on CentOS6:"
 echo -e "${GREEN}      sudo /etc/init.d/srs start${BLACK}"
 echo "or CentOS7:"
diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp
index 3f0a4469e..89212d521 100644
--- a/trunk/src/app/srs_app_config.cpp
+++ b/trunk/src/app/srs_app_config.cpp
@@ -50,7 +50,7 @@ const char* _srs_version = "XCORE-" RTMP_SIG_SRS_SERVER;
 #define SRS_CONF_PERFER_TRUE(conf_arg) conf_arg != "off"
 
 // default config file.
-#define SRS_CONF_DEFAULT_COFNIG_FILE "conf/srs.conf"
+#define SRS_CONF_DEFAULT_COFNIG_FILE SRS_DEFAULT_CONFIG
 
 // '\n'
 #define SRS_LF (char)SRS_CONSTS_LF
diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp
index bce9c9b31..ddb38ae0f 100644
--- a/trunk/src/app/srs_app_rtc_api.cpp
+++ b/trunk/src/app/srs_app_rtc_api.cpp
@@ -186,8 +186,15 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
             server_enabled, rtc_enabled, ruc.req_->vhost.c_str());
     }
 
+    // Whether RTC stream is active.
+    bool is_rtc_stream_active = false;
+    if (true) {
+        SrsRtcSource* source = _srs_rtc_sources->fetch(ruc.req_);
+        is_rtc_stream_active = (source && !source->can_publish());
+    }
+
     // For RTMP to RTC, fail if disabled and RTMP is active, see https://github.com/ossrs/srs/issues/2728
-    if (!_srs_config->get_rtc_from_rtmp(ruc.req_->vhost)) {
+    if (!is_rtc_stream_active && !_srs_config->get_rtc_from_rtmp(ruc.req_->vhost)) {
         SrsLiveSource* rtmp = _srs_sources->fetch(ruc.req_);
         if (rtmp && !rtmp->inactive()) {
             return srs_error_new(ERROR_RTC_DISABLED, "Disabled rtmp_to_rtc of %s, see #2728", ruc.req_->vhost.c_str());
diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp
index c89df51a4..d264ab4c4 100644
--- a/trunk/src/app/srs_app_rtc_conn.cpp
+++ b/trunk/src/app/srs_app_rtc_conn.cpp
@@ -1183,20 +1183,20 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcSourceDescripti
     }
     source->set_publish_stream(this);
 
+    // TODO: FIMXE: Check it in SrsRtcConnection::add_publisher?
+    SrsLiveSource *rtmp = _srs_sources->fetch(r);
+    if (rtmp && !rtmp->can_publish(false)) {
+        return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "rtmp stream %s busy", r->get_stream_url().c_str());
+    }
+
     // Bridge to rtmp
 #if defined(SRS_RTC) && defined(SRS_FFMPEG_FIT)
     bool rtc_to_rtmp = _srs_config->get_rtc_to_rtmp(req_->vhost);
     if (rtc_to_rtmp) {
-        SrsLiveSource *rtmp = NULL;
         if ((err = _srs_sources->fetch_or_create(r, _srs_hybrid->srs()->instance(), &rtmp)) != srs_success) {
             return srs_error_wrap(err, "create source");
         }
 
-        // TODO: FIMXE: Check it in SrsRtcConnection::add_publisher?
-        if (!rtmp->can_publish(false)) {
-            return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "rtmp stream %s busy", r->get_stream_url().c_str());
-        }
-
         // Disable GOP cache for RTC2RTMP bridger, to keep the streams in sync,
         // especially for stream merging.
         rtmp->set_cache(false);
diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp
index ae6c3f99d..d081027c5 100644
--- a/trunk/src/app/srs_app_rtc_source.cpp
+++ b/trunk/src/app/srs_app_rtc_source.cpp
@@ -256,6 +256,10 @@ srs_error_t SrsRtcSourceManager::fetch_or_create(SrsRequest* r, SrsRtcSource** p
 
     SrsRtcSource* source = NULL;
     if ((source = fetch(r)) != NULL) {
+        // we always update the request of resource,
+        // for origin auth is on, the token in request maybe invalid,
+        // and we only need to update the token of request, it's simple.
+        source->update_auth(r);
         *pps = source;
         return err;
     }
@@ -291,11 +295,6 @@ SrsRtcSource* SrsRtcSourceManager::fetch(SrsRequest* r)
 
     source = pool[stream_url];
 
-    // we always update the request of resource,
-    // for origin auth is on, the token in request maybe invalid,
-    // and we only need to update the token of request, it's simple.
-    source->update_auth(r);
-
     return source;
 }
 
diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp
index 10e1d97c5..4bfa21352 100644
--- a/trunk/src/app/srs_app_rtc_source.hpp
+++ b/trunk/src/app/srs_app_rtc_source.hpp
@@ -112,9 +112,8 @@ public:
     // @param r the client request.
     // @param pps the matched source, if success never be NULL.
     virtual srs_error_t fetch_or_create(SrsRequest* r, SrsRtcSource** pps);
-private:
+public:
     // Get the exists source, NULL when not exists.
-    // update the request and return the exists source.
     virtual SrsRtcSource* fetch(SrsRequest* r);
 };
 
diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp
index e5dc78c89..97534cbb5 100755
--- a/trunk/src/app/srs_app_source.cpp
+++ b/trunk/src/app/srs_app_source.cpp
@@ -1713,6 +1713,10 @@ srs_error_t SrsLiveSourceManager::fetch_or_create(SrsRequest* r, ISrsLiveSourceH
     
     SrsLiveSource* source = NULL;
     if ((source = fetch(r)) != NULL) {
+        // we always update the request of resource,
+        // for origin auth is on, the token in request maybe invalid,
+        // and we only need to update the token of request, it's simple.
+        source->update_auth(r);
         *pps = source;
         return err;
     }
@@ -1751,11 +1755,6 @@ SrsLiveSource* SrsLiveSourceManager::fetch(SrsRequest* r)
     
     source = pool[stream_url];
     
-    // we always update the request of resource,
-    // for origin auth is on, the token in request maybe invalid,
-    // and we only need to update the token of request, it's simple.
-    source->update_auth(r);
-    
     return source;
 }
 
diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp
index e0ecf1421..96cdf5950 100644
--- a/trunk/src/app/srs_app_source.hpp
+++ b/trunk/src/app/srs_app_source.hpp
@@ -450,7 +450,6 @@ public:
     virtual srs_error_t fetch_or_create(SrsRequest* r, ISrsLiveSourceHandler* h, SrsLiveSource** pps);
 public:
     // Get the exists source, NULL when not exists.
-    // update the request and return the exists source.
     virtual SrsLiveSource* fetch(SrsRequest* r);
 public:
     // dispose and cycle all sources.
diff --git a/trunk/src/core/srs_core_autofree.hpp b/trunk/src/core/srs_core_autofree.hpp
index db80c3e4b..48e40369d 100644
--- a/trunk/src/core/srs_core_autofree.hpp
+++ b/trunk/src/core/srs_core_autofree.hpp
@@ -30,13 +30,16 @@
 //      where the char* pstr = new char[size].
 // To delete object.
 #define SrsAutoFree(className, instance) \
-    impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false)
+    impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, NULL)
 // To delete array.
 #define SrsAutoFreeA(className, instance) \
-    impl_SrsAutoFree<className> _auto_free_array_##instance(&instance, true, false)
+    impl_SrsAutoFree<className> _auto_free_array_##instance(&instance, true, false, NULL)
 // Use free instead of delete.
 #define SrsAutoFreeF(className, instance) \
-    impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, true)
+    impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, true, NULL)
+// Use hook instead of delete.
+#define SrsAutoFreeH(className, instance, hook) \
+    impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, hook)
 // The template implementation.
 template<class T>
 class impl_SrsAutoFree
@@ -45,11 +48,16 @@ private:
     T** ptr;
     bool is_array;
     bool _use_free;
+    void (*_hook)(T*);
 public:
-    impl_SrsAutoFree(T** p, bool array, bool use_free) {
+    // If use_free, use free(void*) to release the p.
+    // If specified hook, use hook(p) to release it.
+    // Use delete to release p, or delete[] if p is an array.
+    impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) {
         ptr = p;
         is_array = array;
         _use_free = use_free;
+        _hook = hook;
     }
     
     virtual ~impl_SrsAutoFree() {
@@ -59,6 +67,8 @@ public:
 
         if (_use_free) {
             free(*ptr);
+        } else if (_hook) {
+            _hook(*ptr);
         } else {
             if (is_array) {
                 delete[] *ptr;
diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp
index 0b2bb6fc4..498acfafc 100644
--- a/trunk/src/core/srs_core_version4.hpp
+++ b/trunk/src/core/srs_core_version4.hpp
@@ -9,6 +9,6 @@
 
 #define VERSION_MAJOR       4
 #define VERSION_MINOR       0
-#define VERSION_REVISION    220
+#define VERSION_REVISION    229
 
 #endif
diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp
index 9f0c726af..c558b09eb 100644
--- a/trunk/src/core/srs_core_version5.hpp
+++ b/trunk/src/core/srs_core_version5.hpp
@@ -9,6 +9,6 @@
 
 #define VERSION_MAJOR       5
 #define VERSION_MINOR       0
-#define VERSION_REVISION    20
+#define VERSION_REVISION    21
 
 #endif
diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp
index d39783b3f..e4c54b374 100644
--- a/trunk/src/main/srs_main_server.cpp
+++ b/trunk/src/main/srs_main_server.cpp
@@ -126,8 +126,8 @@ srs_error_t do_main(int argc, char** argv)
     // config already applied to log.
     srs_trace2(TAG_MAIN, "%s, %s", RTMP_SIG_SRS_SERVER, RTMP_SIG_SRS_LICENSE);
     srs_trace("authors: %sand %s", RTMP_SIG_SRS_AUTHORS, SRS_CONSTRIBUTORS);
-    srs_trace("cwd=%s, work_dir=%s, build: %s, configure: %s, uname: %s, osx: %d",
-        _srs_config->cwd().c_str(), cwd.c_str(), SRS_BUILD_DATE, SRS_USER_CONFIGURE, SRS_UNAME, SRS_OSX_BOOL);
+    srs_trace("cwd=%s, work_dir=%s, build: %s, configure: %s, uname: %s, osx: %d, pkg: %s",
+        _srs_config->cwd().c_str(), cwd.c_str(), SRS_BUILD_DATE, SRS_USER_CONFIGURE, SRS_UNAME, SRS_OSX_BOOL, SRS_PACKAGER);
     srs_trace("configure detail: " SRS_CONFIGURE);
 #ifdef SRS_EMBEDED_TOOL_CHAIN
     srs_trace("crossbuild tool chain: " SRS_EMBEDED_TOOL_CHAIN);