diff --git a/trunk/research/players/js/srs.page.js b/trunk/research/players/js/srs.page.js
index dbf4e7b6e..26b3971e1 100755
--- a/trunk/research/players/js/srs.page.js
+++ b/trunk/research/players/js/srs.page.js
@@ -1,6 +1,3 @@
-//////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////
 
 // to query the swf anti cache.
 function srs_get_version_code() { return "1.33"; }
@@ -12,10 +9,6 @@ function srs_get_player_modal() { return 740; }
 function srs_get_player_width() { return srs_get_player_modal() - 30; }
 function srs_get_player_height() { return srs_get_player_width() * 9 / 19; }
 
-//////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////
-
 /**
 * update the navigator, add same query string.
 */
@@ -93,34 +86,10 @@ function build_default_flv_url() {
 
     return uri;
 }
-// for the bandwidth tool to init page
-function build_default_bandwidth_rtmp_url() {
-    var query = parse_query_string();
-
-    var schema = 'rtmp';
-    var server = (!query.server)? window.location.hostname:query.server;
-    var port = (!query.port)? 1935:query.port;
-    var vhost = "bandcheck.srs.com";
-    var app = (!query.app)? "app":query.app;
-    var key = (!query.key)? "35c9b402c12a7246868752e2878f7e0e":query.key;
-
-    var uri = schema + "://" + server;
-    if (!is_default_port(schema, port)) {
-        uri += ":" + port;
-    }
-    uri += "/" + app + "?key=" + key + "&vhost=" + vhost;
-
-    return uri;
-}
 
 function build_default_rtc_url(query) {
-    // Use target to overwrite server, vhost and eip.
-    console.log('?target=x.x.x.x to overwrite server, vhost and eip.');
-    if (query.target) {
-        query.server = query.vhost = query.eip = query.target;
-        query.user_query.eip = query.target;
-        delete query.target;
-    }
+    // The format for query string to overwrite configs of server.
+    console.log('?eip=x.x.x.x to overwrite candidate. 覆盖服务器candidate(外网IP)配置');
 
     var server = (!query.server)? window.location.hostname:query.server;
     var vhost = (!query.vhost)? window.location.hostname:query.vhost;
@@ -165,253 +134,3 @@ function srs_init_rtc(id, query) {
     update_nav();
     $(id).val(build_default_rtc_url(query));
 }
-// for bw to init url
-// url: scheme://host:port/path?query#fragment
-function srs_init_bwt(rtmp_url, hls_url) {
-    update_nav();
-    
-    if (rtmp_url) {
-        $(rtmp_url).val(build_default_bandwidth_rtmp_url());
-    }
-}
-
-// check whether can republish
-function srs_can_republish() {
-    var browser = get_browser_agents();
-    
-    if (browser.Chrome || browser.Firefox) {
-        return true;
-    }
-    
-    if (browser.MSIE || browser.QQBrowser) {
-        return false;
-    }
-    
-    return false;
-}
-
-// without default values set.
-function srs_initialize_codec_page(
-    cameras, microphones,
-    sl_cameras, sl_microphones, sl_vcodec, sl_profile, sl_level, sl_gop, sl_size, sl_fps, sl_bitrate,
-    sl_acodec
-) {
-    $(sl_cameras).empty();
-    for (var i = 0; i < cameras.length; i++) {
-        $(sl_cameras).append("= 0) {
-                $(sl_cameras + " option[value='" + i + "']").attr("selected", true);
-                break;
-            }
-        }
-        if (j < matchs.length) {
-            break;
-        }
-    }
-    
-    $(sl_microphones).empty();
-    for (var i = 0; i < microphones.length; i++) {
-        $(sl_microphones).append("= 0) {
-                $(sl_microphones + " option[value='" + i + "']").attr("selected", true);
-                break;
-            }
-        }
-        if (j < matchs.length) {
-            break;
-        }
-    }
-    
-    $(sl_vcodec).empty();
-    var vcodecs = ["h264", "vp6"];
-    vcodecs = ["h264"]; // h264 only.
-    for (var i = 0; i < vcodecs.length; i++) {
-        $(sl_vcodec).append("" + profiles[i] + "" + levels[i] + "" + gops[i] + "秒" + sizes[i] + "" + Number(fpses[i]).toFixed(2) + " 帧/秒" + bitrates[i] + " kbps" + bitrates[i] + "= 0) {
+                var params = app.substr(app.indexOf("?"));
+                app = app.substr(0, app.indexOf("?"));
+
+                if (params.indexOf("vhost=") > 0) {
+                    vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
+                    if (vhost.indexOf("&") > 0) {
+                        vhost = vhost.substr(0, vhost.indexOf("&"));
+                    }
+                }
+            }
+
+            // when vhost equals to server, and server is ip,
+            // the vhost is __defaultVhost__
+            if (a.hostname === vhost) {
+                var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
+                if (re.test(a.hostname)) {
+                    vhost = "__defaultVhost__";
+                }
+            }
+
+            // parse the schema
+            var schema = "rtmp";
+            if (url.indexOf("://") > 0) {
+                schema = url.substr(0, url.indexOf("://"));
+            }
+
+            var port = a.port;
+            if (!port) {
+                if (schema === 'http') {
+                    port = 80;
+                } else if (schema === 'https') {
+                    port = 443;
+                } else if (schema === 'rtmp') {
+                    port = 1935;
+                }
+            }
+
+            var ret = {
+                url: url,
+                schema: schema,
+                server: a.hostname, port: port,
+                vhost: vhost, app: app, stream: stream
+            };
+            self.__internal.fill_query(a.search, ret);
+
+            // For webrtc API, we use 443 if page is https, or schema specified it.
+            if (!ret.port) {
+                if (schema === 'webrtc' || schema === 'rtc') {
+                    if (ret.user_query.schema === 'https') {
+                        ret.port = 443;
+                    } else if (window.location.href.indexOf('https://') === 0) {
+                        ret.port = 443;
+                    } else {
+                        // For WebRTC, SRS use 1985 as default API port.
+                        ret.port = 1985;
+                    }
+                }
+            }
+
+            return ret;
+        },
+        fill_query: function (query_string, obj) {
+            // pure user query object.
+            obj.user_query = {};
+
+            if (query_string.length === 0) {
+                return;
+            }
+
+            // split again for angularjs.
+            if (query_string.indexOf("?") >= 0) {
+                query_string = query_string.split("?")[1];
+            }
+
+            var queries = query_string.split("&");
+            for (var i = 0; i < queries.length; i++) {
+                var elem = queries[i];
+
+                var query = elem.split("=");
+                obj[query[0]] = query[1];
+                obj.user_query[query[0]] = query[1];
+            }
+
+            // alias domain for vhost.
+            if (obj.domain) {
+                obj.vhost = obj.domain;
+            }
+        }
+    };
+
+    self.pc = new RTCPeerConnection(null);
+
+    return self;
+}
+
+// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
+// Async-await-promise based SRS RTC Player.
+function SrsRtcPlayerAsync() {
+    var self = {};
+
+    // @see https://github.com/rtcdn/rtcdn-draft
+    // @url The WebRTC url to play with, for example:
+    //      webrtc://r.ossrs.net/live/livestream
+    // or specifies the API port:
+    //      webrtc://r.ossrs.net:11985/live/livestream
+    // or autostart the play:
+    //      webrtc://r.ossrs.net/live/livestream?autostart=true
+    // or change the app from live to myapp:
+    //      webrtc://r.ossrs.net:11985/myapp/livestream
+    // or change the stream from livestream to mystream:
+    //      webrtc://r.ossrs.net:11985/live/mystream
+    // or set the api server to myapi.domain.com:
+    //      webrtc://myapi.domain.com/live/livestream
+    // or set the candidate(ip) of answer:
+    //      webrtc://r.ossrs.net/live/livestream?eip=39.107.238.185
+    // or force to access https API:
+    //      webrtc://r.ossrs.net/live/livestream?schema=https
+    // or use plaintext, without SRTP:
+    //      webrtc://r.ossrs.net/live/livestream?encrypt=false
+    // or any other information, will pass-by in the query:
+    //      webrtc://r.ossrs.net/live/livestream?vhost=xxx
+    //      webrtc://r.ossrs.net/live/livestream?token=xxx
+    self.play = async function(url) {
+        var conf = self.__internal.prepareUrl(url);
+        self.pc.addTransceiver("audio", {direction: "recvonly"});
+        self.pc.addTransceiver("video", {direction: "recvonly"});
+
+        var offer = await self.pc.createOffer();
+        await self.pc.setLocalDescription(offer);
+        var session = await new Promise(function(resolve, reject) {
+            // @see https://github.com/rtcdn/rtcdn-draft
+            var data = {
+                api: conf.apiUrl, streamurl: conf.streamUrl, clientip: null, sdp: offer.sdp
+            };
+            console.log("Generated offer: ", data);
+
+            $.ajax({
+                type: "POST", url: conf.apiUrl, data: JSON.stringify(data),
+                contentType:'application/json', dataType: 'json'
+            }).done(function(data) {
+                console.log("Got answer: ", data);
+                if (data.code) {
+                    reject(data); return;
+                }
+
+                resolve(data);
+            }).fail(function(reason){
+                reject(reason);
+            });
+        });
+        await self.pc.setRemoteDescription(
+            new RTCSessionDescription({type: 'answer', sdp: session.sdp})
+        );
+        return session;
+    };
+
+    // Close the player.
+    self.close = function() {
+        self.pc.close();
+        self.pc = null;
+    };
+
+    // The callback when got remote stream.
+    self.onaddstream = function (event) {};
+
+    // Internal APIs.
+    self.__internal = {
+        defaultPath: '/rtc/v1/play/',
+        prepareUrl: function (webrtcUrl) {
+            var urlObject = self.__internal.parse(webrtcUrl);
+
+            // If user specifies the schema, use it as API schema.
+            var schema = urlObject.user_query.schema;
+            schema = schema ? schema + ':' : window.location.protocol;
+
+            var port = urlObject.port || 1985;
+            if (schema === 'https:') {
+                port = urlObject.port || 443;
+            }
+
+            // @see https://github.com/rtcdn/rtcdn-draft
+            var api = urlObject.user_query.play || self.__internal.defaultPath;
+            if (api.lastIndexOf('/') !== api.length - 1) {
+                api += '/';
+            }
+
+            apiUrl = schema + '//' + urlObject.server + ':' + port + api;
+            for (var key in urlObject.user_query) {
+                if (key !== 'api' && key !== 'play') {
+                    apiUrl += '&' + key + '=' + urlObject.user_query[key];
+                }
+            }
+            // Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
+            var apiUrl = apiUrl.replace(api + '&', api + '?');
+
+            var streamUrl = urlObject.url;
+
+            return {apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port};
+        },
+        parse: function (url) {
+            // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
+            var a = document.createElement("a");
+            a.href = url.replace("rtmp://", "http://")
+                .replace("webrtc://", "http://")
+                .replace("rtc://", "http://");
+
+            var vhost = a.hostname;
+            var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);
+            var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);
+
+            // parse the vhost in the params of app, that srs supports.
+            app = app.replace("...vhost...", "?vhost=");
+            if (app.indexOf("?") >= 0) {
+                var params = app.substr(app.indexOf("?"));
+                app = app.substr(0, app.indexOf("?"));
+
+                if (params.indexOf("vhost=") > 0) {
+                    vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
+                    if (vhost.indexOf("&") > 0) {
+                        vhost = vhost.substr(0, vhost.indexOf("&"));
+                    }
+                }
+            }
+
+            // when vhost equals to server, and server is ip,
+            // the vhost is __defaultVhost__
+            if (a.hostname === vhost) {
+                var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
+                if (re.test(a.hostname)) {
+                    vhost = "__defaultVhost__";
+                }
+            }
+
+            // parse the schema
+            var schema = "rtmp";
+            if (url.indexOf("://") > 0) {
+                schema = url.substr(0, url.indexOf("://"));
+            }
+
+            var port = a.port;
+            if (!port) {
+                if (schema === 'http') {
+                    port = 80;
+                } else if (schema === 'https') {
+                    port = 443;
+                } else if (schema === 'rtmp') {
+                    port = 1935;
+                }
+            }
+
+            var ret = {
+                url: url,
+                schema: schema,
+                server: a.hostname, port: port,
+                vhost: vhost, app: app, stream: stream
+            };
+            self.__internal.fill_query(a.search, ret);
+
+            // For webrtc API, we use 443 if page is https, or schema specified it.
+            if (!ret.port) {
+                if (schema === 'webrtc' || schema === 'rtc') {
+                    if (ret.user_query.schema === 'https') {
+                        ret.port = 443;
+                    } else if (window.location.href.indexOf('https://') === 0) {
+                        ret.port = 443;
+                    } else {
+                        // For WebRTC, SRS use 1985 as default API port.
+                        ret.port = 1985;
+                    }
+                }
+            }
+
+            return ret;
+        },
+        fill_query: function (query_string, obj) {
+            // pure user query object.
+            obj.user_query = {};
+
+            if (query_string.length === 0) {
+                return;
+            }
+
+            // split again for angularjs.
+            if (query_string.indexOf("?") >= 0) {
+                query_string = query_string.split("?")[1];
+            }
+
+            var queries = query_string.split("&");
+            for (var i = 0; i < queries.length; i++) {
+                var elem = queries[i];
+
+                var query = elem.split("=");
+                obj[query[0]] = query[1];
+                obj.user_query[query[0]] = query[1];
+            }
+
+            // alias domain for vhost.
+            if (obj.domain) {
+                obj.vhost = obj.domain;
+            }
+        }
+    };
+
+    self.pc = new RTCPeerConnection(null);
+    self.pc.onaddstream = function (event) {
+        if (self.onaddstream) {
+            self.onaddstream(event);
+        }
+    };
+
+    return self;
+}
+
diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html
index 1e7db005f..045bc8731 100644
--- a/trunk/research/players/rtc_player.html
+++ b/trunk/research/players/rtc_player.html
@@ -11,6 +11,7 @@
     
     
     
+    
     
     
 
@@ -64,222 +65,6 @@
 
 
     
+    
     
     
 
@@ -65,232 +66,6 @@