123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- var JSWebrtc = {
- Player: null,
- VideoElement: null,
- CreateVideoElements: function() {
- var elements = document.querySelectorAll(".jswebrtc");
- for (var i = 0; i < elements.length; i++) {
- new JSWebrtc.VideoElement(elements[i])
- }
- },
- FillQuery: function(query_string, obj) {
- obj.user_query = {};
- if (query_string.length == 0)
- return;
- 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 query = queries[i].split("=");
- obj[query[0]] = query[1];
- obj.user_query[query[0]] = query[1]
- }
- if (obj.domain)
- obj.vhost = obj.domain
- },
- ParseUrl: function(rtmp_url) {
- var a = document.createElement("a");
- a.href = rtmp_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);
- 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("&"))
- }
- }
- }
- if (a.hostname == vhost) {
- var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
- if (re.test(a.hostname))
- vhost = "__defaultVhost__"
- }
- var schema = "rtmp";
- if (rtmp_url.indexOf("://") > 0)
- schema = rtmp_url.substr(0, rtmp_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
- } else if (schema === "webrtc" || schema === "rtc") {
- port = 1985
- }
- }
- var ret = {
- url: rtmp_url,
- schema: schema,
- server: a.hostname,
- port: port,
- vhost: vhost,
- app: app,
- stream: stream
- };
- JSWebrtc.FillQuery(a.search, ret);
- return ret
- },
- HttpPost: function(url, data) {
- return new Promise(function(resolve, reject) {
- var xhr = new XMLHttpRequest;
- xhr.onreadystatechange = function() {
- if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)) {
- var respone = JSON.parse(xhr.responseText);
- xhr.onreadystatechange = new Function;
- xhr = null;
- resolve(respone)
- }
- }
- ;
- xhr.open("POST", url, true);
- xhr.timeout = 5e3;
- xhr.responseType = "text";
- xhr.setRequestHeader("Content-Type", "application/json");
- xhr.send(data)
- }
- )
- }
- };
- if (document.readyState === "complete") {
- JSWebrtc.CreateVideoElements()
- } else {
- document.addEventListener("DOMContentLoaded", JSWebrtc.CreateVideoElements)
- }
- JSWebrtc.VideoElement = function() {
- "use strict";
- var VideoElement = function(element) {
- var url = element.dataset.url;
- if (!url) {
- throw "VideoElement has no `data-url` attribute"
- }
- var addStyles = function(element, styles) {
- for (var name in styles) {
- element.style[name] = styles[name]
- }
- };
- this.container = element;
- addStyles(this.container, {
- display: "inline-block",
- position: "relative",
- minWidth: "80px",
- minHeight: "80px"
- });
- this.video = document.createElement("video");
- this.video.width = 960;
- this.video.height = 540;
- addStyles(this.video, {
- display: "block",
- width: "100%"
- });
- this.container.appendChild(this.video);
- this.playButton = document.createElement("div");
- this.playButton.innerHTML = VideoElement.PLAY_BUTTON;
- addStyles(this.playButton, {
- zIndex: 2,
- position: "absolute",
- top: "0",
- bottom: "0",
- left: "0",
- right: "0",
- maxWidth: "75px",
- maxHeight: "75px",
- margin: "auto",
- opacity: "0.7",
- cursor: "pointer"
- });
- this.container.appendChild(this.playButton);
- var options = {
- video: this.video
- };
- for (var option in element.dataset) {
- try {
- options[option] = JSON.parse(element.dataset[option])
- } catch (err) {
- options[option] = element.dataset[option]
- }
- }
- this.player = new JSWebrtc.Player(url,options);
- element.playerInstance = this.player;
- if (options.poster && !options.autoplay) {
- options.decodeFirstFrame = false;
- this.poster = new Image;
- this.poster.src = options.poster;
- this.poster.addEventListener("load", this.posterLoaded);
- addStyles(this.poster, {
- display: "block",
- zIndex: 1,
- position: "absolute",
- top: 0,
- left: 0,
- bottom: 0,
- right: 0
- });
- this.container.appendChild(this.poster)
- }
- if (!this.player.options.streaming) {
- this.container.addEventListener("click", this.onClick.bind(this))
- }
- if (options.autoplay) {
- this.playButton.style.display = "none"
- }
- if (this.player.audioOut && !this.player.audioOut.unlocked) {
- var unlockAudioElement = this.container;
- if (options.autoplay) {
- this.unmuteButton = document.createElement("div");
- this.unmuteButton.innerHTML = VideoElement.UNMUTE_BUTTON;
- addStyles(this.unmuteButton, {
- zIndex: 2,
- position: "absolute",
- bottom: "10px",
- right: "20px",
- width: "75px",
- height: "75px",
- margin: "auto",
- opacity: "0.7",
- cursor: "pointer"
- });
- this.container.appendChild(this.unmuteButton);
- unlockAudioElement = this.unmuteButton
- }
- this.unlockAudioBound = this.onUnlockAudio.bind(this, unlockAudioElement);
- unlockAudioElement.addEventListener("touchstart", this.unlockAudioBound, false);
- unlockAudioElement.addEventListener("click", this.unlockAudioBound, true)
- }
- };
- VideoElement.prototype.onUnlockAudio = function(element, ev) {
- if (this.unmuteButton) {
- ev.preventDefault();
- ev.stopPropagation()
- }
- this.player.audioOut.unlock(function() {
- if (this.unmuteButton) {
- this.unmuteButton.style.display = "none"
- }
- element.removeEventListener("touchstart", this.unlockAudioBound);
- element.removeEventListener("click", this.unlockAudioBound)
- }
- .bind(this))
- }
- ;
- VideoElement.prototype.onClick = function(ev) {
- if (this.player.isPlaying) {
- this.player.pause();
- this.playButton.style.display = "block"
- } else {
- this.player.play();
- this.playButton.style.display = "none";
- if (this.poster) {
- this.poster.style.display = "none"
- }
- }
- }
- ;
- VideoElement.PLAY_BUTTON = '<svg style="max-width: 75px; max-height: 75px;" ' + 'viewBox="0 0 200 200" alt="Play video">' + '<circle cx="100" cy="100" r="90" fill="none" ' + 'stroke-width="15" stroke="#fff"/>' + '<polygon points="70, 55 70, 145 145, 100" fill="#fff"/>' + "</svg>";
- VideoElement.UNMUTE_BUTTON = '<svg style="max-width: 75px; max-height: 75px;" viewBox="0 0 75 75">' + '<polygon class="audio-speaker" stroke="none" fill="#fff" ' + 'points="39,13 22,28 6,28 6,47 21,47 39,62 39,13"/>' + '<g stroke="#fff" stroke-width="5">' + '<path d="M 49,50 69,26"/>' + '<path d="M 69,50 49,26"/>' + "</g>" + "</svg>";
- return VideoElement
- }();
- JSWebrtc.Player = function() {
- "use strict";
- var Player = function(url, options) {
- this.options = options || {};
- if (!url.match(/^webrtc?:\/\//)) {
- throw "JSWebrtc just work with webrtc"
- }
- if (!this.options.video) {
- throw "VideoElement is null"
- }
- this.urlParams = JSWebrtc.ParseUrl(url);
- this.pc = null;
- this.autoplay = !!options.autoplay || false;
- this.paused = true;
- if (this.autoplay)
- this.options.video.muted = true;
- this.startLoading()
- };
- Player.prototype.startLoading = function() {
- var _self = this;
- if (_self.pc) {
- _self.pc.close()
- }
- _self.pc = new RTCPeerConnection(null);
- _self.pc.ontrack = function(event) {
- _self.options.video["srcObject"] = event.streams[0]
- }
- ;
- _self.pc.addTransceiver("audio", {
- direction: "recvonly"
- });
- _self.pc.addTransceiver("video", {
- direction: "recvonly"
- });
- _self.pc.createOffer().then(function(offer) {
- return _self.pc.setLocalDescription(offer).then(function() {
- return offer
- })
- }).then(function(offer) {
- return new Promise(function(resolve, reject) {
- var port = _self.urlParams.port || 1985;
- var api = _self.urlParams.user_query.play || "/rtc/v1/play/";
- if (api.lastIndexOf("/") != api.length - 1) {
- api += "/"
- }
- var url = "http://" + _self.urlParams.server + ":" + port + api;
- for (var key in _self.urlParams.user_query) {
- if (key != "api" && key != "play") {
- url += "&" + key + "=" + _self.urlParams.user_query[key]
- }
- }
- var data = {
- api: url,
- streamurl: _self.urlParams.url,
- clientip: null,
- sdp: offer.sdp
- };
- console.log("offer: " + JSON.stringify(data));
- JSWebrtc.HttpPost(url, JSON.stringify(data)).then(function(res) {
- console.log("answer: " + JSON.stringify(res));
- resolve(res.sdp)
- }, function(rej) {
- reject(rej)
- })
- }
- )
- }).then(function(answer) {
- return _self.pc.setRemoteDescription(new RTCSessionDescription({
- type: "answer",
- sdp: answer
- }))
- }).catch(function(reason) {
- throw reason
- });
- if (this.autoplay) {
- this.play()
- }
- }
- ;
- Player.prototype.play = function(ev) {
- if (this.animationId) {
- return
- }
- this.animationId = requestAnimationFrame(this.update.bind(this));
- this.paused = false
- }
- ;
- Player.prototype.pause = function(ev) {
- if (this.paused) {
- return
- }
- cancelAnimationFrame(this.animationId);
- this.animationId = null;
- this.isPlaying = false;
- this.paused = true;
- this.options.video.pause();
- if (this.options.onPause) {
- this.options.onPause(this)
- }
- }
- ;
- Player.prototype.stop = function(ev) {
- this.pause()
- }
- ;
- Player.prototype.destroy = function() {
- this.pause();
- this.pc && this.pc.close() && this.pc.destroy();
- this.audioOut && this.audioOut.destroy()
- }
- ;
- Player.prototype.update = function() {
- this.animationId = requestAnimationFrame(this.update.bind(this));
- if (this.options.video.readyState < 4) {
- return
- }
- if (!this.isPlaying) {
- this.isPlaying = true;
- this.options.video.play();
- if (this.options.onPlay) {
- this.options.onPlay(this)
- }
- }
- }
- ;
- return Player
- }();
|