ovenlivekit
Version:
OvenLiveKit for Web is an open source JavaScript SDK suite for live streaming from web browsers to OvenMediaEngine.
2 lines • 13.2 kB
JavaScript
!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.OvenLiveKit=n():e.OvenLiveKit=n()}(self,(()=>(()=>{"use strict";var e={d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{default:()=>u});const o={},t="1.4.0",i="OvenLiveKit.js :",c="OvenLiveKit.js ====";function r(e,n){e&&e.send(JSON.stringify(n))}function a(e){let n,o="";return(n=e.match(/^(?:wss?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n\?\=]+)/im))&&(o=n[1]),o}function s(e){let n,o="";return(n=e.match(new RegExp("\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b","gi")))&&(o=n[0]),o}function l(e,n){const o=function(e,n){const o=e.split("\r\n");let t=-1;for(let e=0;e<o.length-1;e++)if(o[e]=o[e].toLowerCase(),0===o[e].indexOf("a=rtpmap")&&o[e].indexOf(n.toLowerCase())>-1){t=o[e].split(" ")[0].split(":")[1];break}return t}(e,n);if(-1===o)return e;let t=[];const i=e.split("\r\n");for(let e=0;e<i.length-1;e++){const n=i[e];if(0===n.indexOf("m=video")){const e=n.split(" ").slice(0,3),i=n.split(" ").slice(3);i.sort((function(e,n){return e==o?-1:n==o?1:0})),t.push(e.concat(i).join(" "))}else t.push(n)}return t.join("\r\n")+"\r\n"}async function d(e){const n={};return"both"===e?(n.audio=!0,n.video=!0):"audio"===e?n.audio=!0:"video"===e&&(n.video=!0),await navigator.mediaDevices.getUserMedia(n)}function f(e){function n(n){e.callbacks.error&&e.callbacks.error(n)}async function o(e,n){let o=await fetch(e,n);for(;o.redirected;)e=o.url,o=await fetch(e,n);return o}function t(e,n,o){let t=e.split("\r\n"),i=-1;for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m="+n)){i=e;break}if(-1===i)return e;for(i++;0===t[i].indexOf("i=")||0===t[i].indexOf("c=");)i++;if(0===t[i].indexOf("b"))return t[i]="b=AS:"+o,t.join("\r\n");let c=t.slice(0,i);return c.push("b=AS:"+o),c=c.concat(t.slice(i,t.length)),c.join("\r\n")}async function d(){if(!e.peerConnection)return console.error("No connection to close"),void n("No connection to close");if(u(),e.resourceUrl){const n={};e.connectionConfig.httpHeaders&&Object.assign(n,e.connectionConfig.httpHeaders),await o(e.resourceUrl,{method:"DELETE",headers:n})}}function f(n){const o=e.connectionConfig.sdp.appendFmtp,t=n.split("\r\n"),i=[];for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){let n=t[e].split(" ");for(let e=3;e<n.length;e++)i.push(n[e]);break}for(let e=0;e<i.length;e++){let n=!1;for(let c=0;c<t.length;c++)0===t[c].indexOf("a=fmtp:"+i[e])&&(n=!0,t[c]+=";"+o);if(!n)for(let n=0;n<t.length;n++)0===t[n].indexOf("a=rtpmap:"+i[e])&&(t[n]+="\r\na=fmtp:"+i[e]+" "+o)}return t.join("\r\n")}function u(){e.peerConnection&&(e.peerConnection.getSenders().forEach((function(n){e.peerConnection.removeTrack(n)})),e.peerConnection.close(),e.peerConnection=null,delete e.peerConnection)}function p(){e.webSocket&&(e.webSocket.close(),e.webSocket=null,delete e.webSocket)}e.attachMedia=function(n){e.videoElement=n},e.getUserMedia=function(o){return function(o){return o||(o={video:{deviceId:void 0},audio:{deviceId:void 0}}),console.info(i,"Request Stream To Input Devices With Constraints",o),navigator.mediaDevices.getUserMedia(o).then((function(n){console.info(i,"Received Media Stream From Input Device",n),e.inputStream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(i,"Can't Get Media Stream From Input Device",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.getDisplayMedia=function(o){return function(o){return o||(o={}),console.info(i,"Request Stream To Display With Constraints",o),navigator.mediaDevices.getDisplayMedia(o).then((function(n){console.info(i,"Received Media Stream From Display",n),e.inputStream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(i,"Can't Get Media Stream From Display",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.setMediaStream=function(o){return function(o){if(!(o&&o instanceof MediaStream)){const e=new Error("Invalid MediaStream provided");return console.error(i,"Invalid MediaStream",e),n(e),new Promise((function(n,o){o(e)}))}console.info(i,"Received Media Stream",o),e.inputStream=o;let t=e.videoElement;return t&&(t.srcObject=o,t.onloadedmetadata=function(e){t.play()}),new Promise((function(e){e(o)}))}(o)},e.startStreaming=function(d,p){if(console.info(c,`Start Streaming to ${d} with connectionConfig`,p),!d)return console.error("endpointUrl is required"),void n("endpointUrl is required");e.endpointUrl=d,p&&(e.connectionConfig=p);try{const c=new URL(d).protocol;"wss:"===c||"ws:"===c?(e.streamingMode="webrtc",function(o){if(!o)return void n("endpointUrl is required");let c=null;try{c=new WebSocket(o)}catch(e){n(e)}e.webSocket=c,c.onopen=function(){r(c,{command:"request_offer"})},c.onmessage=function(o){let c=JSON.parse(o.data);c.error&&(console.error("webSocket.onmessage",c.error),n(c.error)),"offer"===c.command&&function(o,c,d,u,p){let m={};if(e.connectionConfig.iceServers)m.iceServers=e.connectionConfig.iceServers,e.connectionConfig.iceTransportPolicy&&(m.iceTransportPolicy=e.connectionConfig.iceTransportPolicy);else if(p){m.iceServers=[];for(let n=0;n<p.length;n++){let o=p[n],t={};t.urls=o.urls;let i=!1,c=a(e.endpointUrl);for(let e=0;e<t.urls.length;e++)if(t.urls[e].indexOf(c)>-1){i=!0;break}if(!i&&t.urls.length>0){let e=t.urls[0],n=s(e);c&&n&&t.urls.push(e.replace(n,c))}t.username=o.user_name,t.credential=o.credential,m.iceServers.push(t)}e.connectionConfig.iceTransportPolicy?m.iceTransportPolicy=e.connectionConfig.iceTransportPolicy:m.iceTransportPolicy="relay"}else e.connectionConfig.iceTransportPolicy&&(m.iceTransportPolicy=e.connectionConfig.iceTransportPolicy);console.info(i,"Create Peer Connection With Config",m);let g=new RTCPeerConnection(m);e.peerConnection=g,e.inputStream.getTracks().forEach((function(n){console.info(i,"Add Track To Peer Connection",n),g.addTrack(n,e.inputStream)})),e.connectionConfig.maxVideoBitrate&&(d.sdp=t(d.sdp,"video",e.connectionConfig.maxVideoBitrate)),e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(d.sdp=f(d.sdp)),e.connectionConfig.preferredVideoFormat&&(d.sdp=l(d.sdp,e.connectionConfig.preferredVideoFormat)),console.info(i,"Modified offer sdp\n\n"+d.sdp),g.setRemoteDescription(new RTCSessionDescription(d)).then((function(){g.createAnswer().then((function(t){e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(t.sdp=f(t.sdp)),e.connectionConfig.preferredVideoFormat&&(t.sdp=l(t.sdp,e.connectionConfig.preferredVideoFormat)),console.info(i,"Modified answer sdp\n\n"+t.sdp),g.setLocalDescription(t).then((function(){r(e.webSocket,{id:o,peer_id:c,command:"answer",sdp:t})})).catch((function(e){console.error("peerConnection.setLocalDescription",e),n(e)}))})).catch((function(e){console.error("peerConnection.createAnswer",e),n(e)}))})).catch((function(e){console.error("peerConnection.setRemoteDescription",e),n(e)})),u&&function(e,o){for(let t=0;t<o.length;t++)if(o[t]&&o[t].candidate){let i=o[t];e.addIceCandidate(new RTCIceCandidate(i)).then((function(){})).catch((function(e){console.error("peerConnection.addIceCandidate",e),n(e)}))}}(g,u),g.onicecandidate=function(n){n.candidate&&n.candidate.candidate&&r(e.webSocket,{id:o,peer_id:c,command:"candidate",candidates:[n.candidate]})},g.oniceconnectionstatechange=function(n){let o=g.iceConnectionState;e.callbacks.iceStateChange&&(console.info(i,"ICE State","["+o+"]"),e.callbacks.iceStateChange(o)),"connected"===o&&e.callbacks.connected&&e.callbacks.connected(n),"failed"!==o&&"disconnected"!==o&&"closed"!==o||e.callbacks.connectionClosed&&(console.error(i,"Ice connection closed",n),e.callbacks.connectionClosed("ice",n))}}(c.id,c.peer_id,c.sdp,c.candidates,c.ice_servers)},c.onerror=function(e){console.error("webSocket.onerror",e),n(e)},c.onclose=function(n){e.webSocketClosedByUser||e.callbacks.connectionClosed&&e.callbacks.connectionClosed("websocket",n)}}(d)):"https:"===c||"http:"===c?(e.streamingMode="whip",async function(c){if(e.peerConnection)return console.error("Connection already established"),void n("Connection already established");const r={bundlePolicy:"max-bundle"};e.connectionConfig.iceServers?(r.iceServers=e.connectionConfig.iceServers,e.connectionConfig.iceTransportPolicy&&(r.iceTransportPolicy=e.connectionConfig.iceTransportPolicy)):e.connectionConfig.iceTransportPolicy&&(r.iceTransportPolicy=e.connectionConfig.iceTransportPolicy),console.info(i,"Create Peer Connection With Config",r);const a=new RTCPeerConnection(r);if(e.peerConnection=a,!e.inputStream)return console.error("No input stream in OvenLiveKit"),void n("No input stream in OvenLiveKit");for(const n of e.inputStream.getTracks()){console.log(i,"Adding track: ",n);const o={direction:"sendonly"},t=e.connectionConfig.simulcast;if("video"===n.kind&&t&&t.length>0){o.sendEncodings=[];for(let e=0;e<t.length;e++){const c={rid:e,active:!0,...t[e]};console.log(i,`Adding simulcast layer to: ${n.kind}`,c),o.sendEncodings.push(c)}}a.addTransceiver(n,o)}a.oniceconnectionstatechange=function(n){let o=a.iceConnectionState;e.callbacks.iceStateChange&&(console.info(i,"ICE State","["+o+"]"),e.callbacks.iceStateChange(o)),"connected"===o&&e.callbacks.connected&&e.callbacks.connected(n),"failed"===o&&e.callbacks.connectionClosed&&(console.error(i,"Ice connection failed",n),e.callbacks.errorHandler(n)),"disconnected"!==o&&"closed"!==o||e.callbacks.connectionClosed&&(console.error(i,"Ice connection disconnected or closed",n),e.callbacks.connectionClosed("ice",n))};const s=await a.createOffer();console.log(i,"Offer SDP: ",s.sdp),e.connectionConfig.maxVideoBitrate&&(s.sdp=t(s.sdp,"video",e.connectionConfig.maxVideoBitrate)),e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(s.sdp=f(s.sdp)),e.connectionConfig.preferredVideoFormat?s.sdp=l(s.sdp,e.connectionConfig.preferredVideoFormat):s.sdp=l(s.sdp,"H264");const d={"Content-Type":"application/sdp"};e.connectionConfig.httpHeaders&&Object.assign(d,e.connectionConfig.httpHeaders);const p=await o(c,{method:"POST",body:s.sdp,headers:d});if(!p.ok)return console.error("Failed to fetch",p.status),n(`Failed to fetch ${p.status}`),void u();if(!p.headers.get("location"))return console.error("No location header on answer response"),void n("No location header on answer response");e.endpointUrl=p.url,console.log(i,"Updated endpointUrl: ",e.endpointUrl);const m=new URL(c).origin;e.resourceUrl=m+p.headers.get("location");const g=await p.text();console.log(i,"Answer SDP: ",g);try{await a.setLocalDescription(s)}catch(e){console.error("peerConnection.setLocalDescription",e),n(e)}try{await a.setRemoteDescription({type:"answer",sdp:g})}catch(e){console.error("peerConnection.setRemoteDescription",e),n(e)}}(d)):(console.error("Invalid protocol",error),n(error))}catch(e){console.error("Cannot parse connection URL",e),n(e)}},e.stopStreaming=async function(){"webrtc"===e.streamingMode?(e.webSocketClosedByUser=!0,p(),u()):"whip"===e.streamingMode&&await d(),e.callbacks.connectionClosed&&(console.log(i,"Connection closed by user"),e.callbacks.connectionClosed("user","Connection closed by user"))},e.remove=function(){"webrtc"===e.streamingMode?(e.webSocketClosedByUser=!0,p(),u()):"whip"===e.streamingMode&&d(),e.inputStream&&(e.inputStream.getTracks().forEach((n=>{n.stop(),e.inputStream.removeTrack(n)})),e.videoElement&&(e.videoElement.srcObject=null),e.inputStream=null,delete e.inputStream),console.info(c,"Removed")}}o.getVersion=function(){return t},o.create=function(e){console.info(c,"Create WebRTC Input "+t);let n={webSocketClosedByUser:!1};return function(e,n){e.streamingMode=null,e.inputStream=null,e.webSocket=null,e.peerConnection=null,e.connectionConfig={},e.videoElement=null,e.endpointUrl=null,e.resourceUrl=null,n&&n.callbacks?e.callbacks=n.callbacks:e.callbacks={}}(n,e),f(n),n},o.getDevices=async function(){try{await d("both")}catch(e){console.warn(i,"Can not find Video and Audio devices",e);let n=null,o=null;try{n=await d("video")}catch(e){console.warn(i,"Can not find Video devices",e)}try{o=await d("audio")}catch(e){console.warn(i,"Can not find Audio devices",e)}if(!n&&!o)throw new Error("No input devices were found.")}return function(e){let n={audioinput:[],audiooutput:[],videoinput:[],other:[]};for(let o=0;o!==e.length;++o){const t=e[o];let i={};i.deviceId=t.deviceId,"audioinput"===t.kind?(i.label=t.label||`microphone ${n.audioinput.length+1}`,n.audioinput.push(i)):"audiooutput"===t.kind?(i.label=t.label||`speaker ${n.audiooutput.length+1}`,n.audiooutput.push(i)):"videoinput"===t.kind?(i.label=t.label||`camera ${n.videoinput.length+1}`,n.videoinput.push(i)):(i.label=t.label||`other ${n.other.length+1}`,n.other.push(i))}return n}(await async function(){return await navigator.mediaDevices.enumerateDevices()}())};const u=o;return n.default})()));
//# sourceMappingURL=OvenLiveKit.min.js.map