JS 资源
https://ossrs.net/players/js/...
https://ossrs.net/players/js/...
https://ossrs.net/players/js/...html
<template> <div> <video id="rtc_media_player" autoplay></video> <!-- <video id="rtc_media_player" x-webkit-airplay='allow' webkit-playsinline playsinline controls x5-video-player-type='h5' x5-video-player-fullscreen x5-video-orientation='portrait' crossOrigin='Anonymous' allowsInlineMediaPlayback='true' autoplay></video> --> </div> </template>
提供一个Video的标签,注释里面有他的一些属性,srs播放须要一个video的ID rtc_media_player前端
$(function () { // Async-await-promise based SRS RTC Player. function SrsRtcPlayerAsync() { var self = {}; 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); }); }); console.log(session) await self.pc.setRemoteDescription( new RTCSessionDescription({ type: 'answer', sdp: session.sdp }) ); return session; }; // Close the publisher. self.close = function () { self.pc.close(); }; // 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; } var sdk = null; // Global handler to do cleanup when replaying. var startPlay = function () { $('#rtc_media_player').show(); // Close PC when user replay. if (sdk) { sdk.close(); } sdk = new SrsRtcPlayerAsync(); sdk.onaddstream = function (event) { console.log('Start play, event: ', event); console.log(event.stream) $('#rtc_media_player').prop('srcObject', event.stream); }; // For example: // webrtc://r.ossrs.net/live/livestream var url = $("#txt_url").val(); sdk.play(url).then(function (session) { $('#sessionid').html(session.sessionid); $('#simulator-drop').attr('href', session.simulator + '?drop=1&username=' + session.sessionid); }).catch(function (reason) { sdk.close(); $('#rtc_media_player').hide(); console.error(reason); }); }; $('#rtc_media_player').hide(); var query = parse_query_string(); srs_init_rtc("#txt_url", query); $("#txt_url").val('webrtc://47.115.33.66/live/livestream') $("#btn_play").click(function () { $('#rtc_media_player').prop('muted', false); startPlay(); setTimeout(() => { // vrVideoinit() }, 1000); }); if (query.autostart === 'true') { $('#rtc_media_player').prop('muted', true); console.warn('For autostart, we should mute it, see https://www.jianshu.com/p/c3c6944eed5a ' + 'or https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#audiovideo_elements'); startPlay(); } }); function vrVideoinit() { var scene, renderer; var container; //renderer = new THREE.WebGLRenderer(); AVR.debug = true; if (!AVR.Broswer.isIE() && AVR.Broswer.webglAvailable()) { renderer = new THREE.WebGLRenderer(); } else { renderer = new THREE.CanvasRenderer(); } renderer.setPixelRatio(window.devicePixelRatio); container = document.getElementById('example'); container.appendChild(renderer.domElement); scene = new THREE.Scene(); // fov 选项可调整初始视频远近 var vr = new VR(scene, renderer, container, { "fov": 90 }); //vr.playText="<img src='img/play90.png' width='40' height='40'/>"; vr.vrbox.radius = 600; if (AVR.isCrossScreen()) { // 调整vr视窗偏移量 vr.effect.separation = 1.2; } vr.loadProgressManager.onLoad = function () { // 视频静音 vr.video.muted = true; } //AVR.useGyroscope=false; vr.init(function () { }); var videoDom = document.getElementById('rtc_media_player') vr.play(videoDom, vr.resType.webrtcVideo); vr.video.addEventListener('canplay', function () { vr.video.play() }) vr.video.crossOrigin = "Anonymous"; vr.video.onended = function () { console.log('结束?') $("#example").hide() $(".shade").show() $("#iframeDoms").show() } }
SrsRtcPlayerAsync 里面是SRS 提供内置RTC方法,及RTC解析,划重点java
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); }); }); console.log(session) await self.pc.setRemoteDescription( new RTCSessionDescription({ type: 'answer', sdp: session.sdp }) ); return session; };
注意play方法中的 apiUrl,这个地址是须要后台提供支持的地址,也就是SRS服务中提供的WEBRTC 地址,会返回一些内置方法的参数git
$('#rtc_media_player').prop('srcObject', event.stream);
这个简单 给video 注入media 的Object,vrVideoinit方法是VR全景播放的方法,可忽略,部分代码提供angularjs