@ceeblue/webrtc-client
Advanced tools
Comparing version 2.0.0 to 3.0.0
@@ -105,3 +105,3 @@ import { EventEmitter, Connect, ILog } from '@ceeblue/web-utils'; | ||
* @example | ||
* const streamMetadata = new StreamMetadata(Connect.buildURL(host, streamName)); | ||
* const streamMetadata = new StreamMetadata(Connect.buildURL(endPoint, streamName)); | ||
* streamMetadata.onMetadata = metadata => { | ||
@@ -138,3 +138,3 @@ * console.log(metadata); | ||
/** | ||
* Returns the ConnectParams object containing the connection parameters | ||
* Returns the {@link Connect.Params} object containing the connection parameters | ||
*/ | ||
@@ -470,3 +470,3 @@ get connectParams(): Connect.Params; | ||
* You can use a controllable version using a `WSController` as connector, or change it to use a `HTTPConnector` (HTTP WHEP). | ||
* By default it uses a `WSController` excepting if on {@link Player.start} you use a {@link ConnectParams.host} prefixed with a `http://` protocol. | ||
* By default it uses a `WSController` excepting if on {@link Player.start} you use a {@link Connect.Params.endPoint} prefixed with a `http://` protocol. | ||
* With a controllable connector you can change track during the playback, what is not possible with a HTTP(WHEP) connector. | ||
@@ -494,3 +494,3 @@ * | ||
* player.start({ | ||
* host: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHEP) if Player is build without contructor argument | ||
* endPoint: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHEP) if Player is build without contructor argument | ||
* streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' | ||
@@ -615,3 +615,3 @@ * }); | ||
* By default if no connector is indicated it uses a {@link WSController} (WebSocket {@link IController}) | ||
* excepting if {@link ConnectParams.host} is prefixed with a `http://` protocol in such case it uses | ||
* excepting if {@link Connect.Params.endPoint} is prefixed with a `http://` protocol in such case it uses | ||
* instead a {@link HTTPConnector} (HTTP {@link IConnector}). To force a HTTPConnector build explicitly | ||
@@ -624,9 +624,9 @@ * with {@link HTTPConnector} as Connector argument. | ||
* player.start({ | ||
* host: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHIP), otherwise it uses a WSController (WebSocket) | ||
* endPoint: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHIP), otherwise it uses a WSController (WebSocket) | ||
* streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' | ||
* }); | ||
* // Force connector selection whatever the address used in host | ||
* // Force connector selection whatever the address used in endPoint | ||
* const player = new Player(isWHIP ? HTTPConnector : WSController); | ||
* player.start({ | ||
* host: address, // optional protocol prefix has no incidence on connector selection | ||
* endPoint: address, // optional protocol prefix has no incidence on connector selection | ||
* streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' | ||
@@ -645,5 +645,5 @@ * }) | ||
* Starts playing the stream | ||
* The connector is determined automatically from {@link ConnectParams.host} if not forced in the constructor. | ||
* The connector is determined automatically from {@link Connect.Params.endPoint} if not forced in the constructor. | ||
* | ||
* Instead to use a {@link ConnectParams} you can prefer use a already built {@link StreamMetadata} instance to | ||
* Instead to use a {@link Connect.Params} you can prefer use a already built {@link StreamMetadata} instance to | ||
* the same end-point, it allows to discover tracks in amount and initialize track selection to start playback. | ||
@@ -664,3 +664,3 @@ * | ||
* player.start({ | ||
* host: address, | ||
* endPoint: address, | ||
* streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' | ||
@@ -670,3 +670,3 @@ * }); | ||
* const streamMetadata = new StreamMetadata({ | ||
* host: address, | ||
* endPoint: address, | ||
* streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' | ||
@@ -829,3 +829,3 @@ * }); | ||
* You can use a controllable version using a `WSController` as connector, or change it to use a `HTTPConnector` (HTTP WHIP). | ||
* By default it uses a `WSController` excepting if on {@link Streamer.start} you use a {@link ConnectParams.host} prefixed with a `http://` protocol. | ||
* By default it uses a `WSController` excepting if on {@link Streamer.start} you use a {@link Connect.Params.endPoint} prefixed with a `http://` protocol. | ||
* With a controllable connector you can change video bitrate during the streaming, what is not possible with a HTTP(WHIP) connector. | ||
@@ -846,3 +846,3 @@ * | ||
* streamer.start(stream, { | ||
* host: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHIP) if Streamer is build without contructor argument | ||
* endPoint: address, // if address is prefixed by `http://` it uses a HTTPConnector (HTTP-WHIP) if Streamer is build without contructor argument | ||
* streamName: 'as+bc3f535f-37f3-458b-8171-b4c5e77a6137' | ||
@@ -964,3 +964,3 @@ * }); | ||
* Starts broadcasting the stream | ||
* The connector is determined automatically from {@link ConnectParams.host} if not forced in the constructor. | ||
* The connector is determined automatically from {@link Connect.Params.endPoint} if not forced in the constructor. | ||
* | ||
@@ -1038,3 +1038,3 @@ * The `adaptiveBitrate` option can take three different types of value: | ||
private _streamName; | ||
private _host; | ||
private _endPoint; | ||
private _stream?; | ||
@@ -1094,3 +1094,3 @@ private _peerConnection?; | ||
* // Listener channel (no initial 'stream' parameter), listen to a stream without sending data | ||
* const connection = new HTTPConnector({host, streamName}); | ||
* const connection = new HTTPConnector({endPoint, streamName}); | ||
* // we get the media stream from server | ||
@@ -1100,3 +1100,3 @@ * connection.onOpen = stream => videoElement.srcObject = stream; | ||
* // Streamer channel (with initial 'stream' parameter), sends and receives media streams | ||
* const connection = new HTTPConnector({host, streamName}, {stream: await navigator.mediaDevices.getUserMedia()}); | ||
* const connection = new HTTPConnector({endPoint, streamName}, {stream: await navigator.mediaDevices.getUserMedia()}); | ||
* // the media stream here is our local camera as passed in the above constructor | ||
@@ -1136,7 +1136,7 @@ * connection.onOpen = stream => {} | ||
* // Listener channel (no 'stream' parameter), listen to a stream without sending data | ||
* const connection = new WSController({host, streamName}); | ||
* const connection = new WSController({endPoint, streamName}); | ||
* connection.onOpen = stream => videoElement.srcObject = stream; | ||
* | ||
* // Streamer channel (with 'stream' parameter), sends and receives media streams | ||
* const connection = new WSController({host, streamName}, {stream: await navigator.mediaDevices.getUserMedia()}); | ||
* const connection = new WSController({endPoint, streamName}, {stream: await navigator.mediaDevices.getUserMedia()}); | ||
* connection.onOpen = stream => {} | ||
@@ -1484,3 +1484,3 @@ */ | ||
* @example | ||
* const streamData = new WSStreamData({host, streamName}); | ||
* const streamData = new WSStreamData({endPoint, streamName}); | ||
* streamData.tracks = [0, 1]; // subscribe to data tracks 0 and 1 | ||
@@ -1487,0 +1487,0 @@ * streamData.onData = time, track, data => { |
@@ -1,1 +0,1 @@ | ||
function t(t,e,i,s){return new(i||(i=Promise))((function(r,n){function o(t){try{h(s.next(t))}catch(t){n(t)}}function a(t){try{h(s.throw(t))}catch(t){n(t)}}function h(t){var e;t.done?r(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(o,a)}h((s=s.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class e{static fixProtocol(t,e){const i=e.indexOf("://");return i>=0&&(i>2&&"s"===e.charAt(i-1).toLowerCase()?(t.length<=2||!t.endsWith("s"))&&(t+="s"):t.length>2&&t.endsWith("s")&&(t=t.slice(0,-1)),e=e.substring(i+3)),t+"://"+e}get domain(){return this._domain}get port(){return this._port}toString(){return this._address}valueOf(){return this._address}constructor(t,e){this._address=t;let i=t.indexOf("/");if(i>=0&&(47===t.charCodeAt(i+1)?i>0?58===t.charCodeAt(i-1)&&(t=t.substring(i+2)):t=t.substring(2):i||(t=t.substring(1))),this._domain=t,this._port=e,i=t.lastIndexOf(":"),i>=0){const e=parseInt(t.substring(i+1));e&&e<=65535&&(this._port=e,this._domain=t.substring(0,i))}else i=t.indexOf("/"),i>=0&&(this._domain=t.substring(0,i))}}var i;!function(t){t.HESP="hesp",t.WEBRTS="webrts",t.WEBRTC="webrtc",t.META="meta",t.DATA="data"}(i||(i={}));var s=Object.freeze({__proto__:null,get Type(){return i},buildURL:function(t,s,r="wss"){const n=new URL(e.fixProtocol(r,s.host));if(n.pathname.length<=1)switch(t){case i.HESP:n.pathname="/hesp/"+s.streamName+"/index.json";break;case i.WEBRTC:n.pathname="/webrtc/"+s.streamName;break;case i.WEBRTS:n.pathname="/webrts/"+s.streamName;break;case i.META:n.pathname="/json_"+s.streamName+".js";break;case i.DATA:n.pathname="/"+s.streamName+".json";break;default:console.warn("Unknown url type "+t)}s.accessToken&&n.searchParams.set("id",s.accessToken);for(const t in s.query)n.searchParams.set(t,s.query[t]);return n}});class r{constructor(){this._events=new Map;let t=Object.getPrototypeOf(this);for(;t&&t!==Object.prototype;){for(const e of Object.getOwnPropertyNames(t))if(!(e.length<3)&&e.startsWith("on")&&t[e]instanceof Function){const i=new Set;this._events.set(e.substring(2).toLowerCase(),i);let s=t[e];Object.defineProperties(this,{[e]:{get:()=>(...t)=>{s&&s.call(this,...t);for(const e of i)e(...t)},set:t=>{s=t}}})}t=Object.getPrototypeOf(t)}}on(t,e,i){if(!e)throw Error("event to subscribe cannot be null");const s=this._event(t);s.add(e),i&&i.signal.addEventListener("abort",(()=>{s.delete(e)}))}once(t,e,i){if(!e)throw Error("event to subscribe cannot be null");const s=this._event(t);s.add((()=>{s.delete(e),e()})),i&&i.signal.addEventListener("abort",(()=>{s.delete(e)}))}off(t,e){if(!e)throw Error("event to unsubscribe cannot be null");this._event(t).delete(e)}_event(t){const e=this._events.get(t.toLowerCase());if(!e)throw Error("No event on"+t+" on class "+this.constructor.name);return e}}class n{get size(){return this._queue.length}get capacity(){return this._capacity}set capacity(t){this._capacity=t,null!=t&&this._queue.length>t&&this._queue.splice(0,this._queue.length-t)}get front(){return this._queue[0]}get back(){return this._queue[this._queue.length-1]}[Symbol.iterator](){return this._queue[Symbol.iterator]()}constructor(t){this._capacity=t,this._queue=new Array}push(t){return null!=this._capacity&&this._queue.push(t)>this._capacity&&this.pop(),this}pop(){return this._queue.shift()}clear(){return this._queue.length=0,this}}class o extends n{get minimum(){return this._min}get maximum(){return this._max}get average(){return null==this._average&&(this._average=this.size?this._sum/this.size:0),this._average}constructor(t){super(t),this._sum=0,this._min=0,this._max=0}push(t){return t>this._max?this._max=t:t<this._min&&(this._min=t),this._average=void 0,this._sum+=t,super.push(t),this}pop(){const t=super.pop();return t===this._max?this._max=Math.max(0,...this):t===this._min&&(this._min=Math.min(0,...this)),this._average=void 0,this._sum-=t||0,t}clear(){return this._min=this._max=this._sum=0,super.clear(),this}}const a={fromString(t){if(Array.isArray(t))return t;const e=new Array;let i,s=e;for(let r of t.toString().split("\n")){if(r=r.trim(),!r)continue;let t=r[0];const n=r.substring(r.indexOf("=")+1).trim();switch(t.toLowerCase()){case"a":if(!n)continue;t=this.addAttribute(s,n),e===s&&"fingerprint"===t.toLowerCase()&&(i=s.fingerprint);break;case"m":e.length&&i&&!e[e.length-1].fingerprint&&(s.fingerprint=i),e.push(s={m:n});break;default:s[t]=n}}return e.length&&i&&!e[e.length-1].fingerprint&&(s.fingerprint=i),e},toString(t){if("string"==typeof t)return t;const e=[];let i="v"in t?"v="+t.v+"\n":"";"o"in t&&(i+="o="+t.o+"\n"),"s"in t&&(i+="s="+t.s+"\n");const s=t;for(const r of Object.keys(t)){if("v"===r||"o"===r||"s"===r)continue;const t=s[r];if(null==t)continue;const n=parseInt(r);if(!isNaN(n)){e[n]=t;continue}const o=Array.isArray(t)&&t.length||1;for(let e=0;e<o;++e){const s=Array.isArray(t)&&t.length?t[e]:t;r.length>1?(i+="a="+r,s&&(i+=":")):i+=r+"=",i+=s+"\n"}}for(const t of e)i+=this.toString(t);return i},addAttribute(t,e){var i;const s=a.parseAttribute(e),r=null!==(i=s.value)&&void 0!==i?i:"",n=t,o=n[s.key];return o?Array.isArray(o)?o.push(r):r!==o&&(n[s.key]=[o,r]):n[s.key]=r,s.key},removeAttribute(t,e){const i=a.parseAttribute(e),s=t;if(void 0===i.value)return delete s[e],e;const r=s[e];if(Array.isArray(i.value)){const t=r.findIndex((t=>t===i.value));t>=0&&r.splice(t,1)}else r===i.value&&delete s[e];return i.key},parseAttribute(t){const e=t.indexOf(":");return{key:(e>=0?t.substring(0,e):t).trim(),value:e>=0?t.substring(e+1).trim():void 0}}};Object.freeze(a);const h=new TextDecoder,c=new TextEncoder,u=performance;function d(t,e){e=Object.assign({withType:!1,noEmptyString:!1},e);const i={};if(!t)return i;for(const[s,r]of _(t)){if(t=r,e.withType&&null!=t&&t.substring)if(t){const e=Number(t);if(isNaN(e))switch(t.toLowerCase()){case"true":t=!0;break;case"false":t=!1;break;case"null":t=null;break;case"undefined":t=void 0}else t=e}else e.noEmptyString&&(t=!0);i[s]?(Array.isArray(i[s])||(i[s]=new Array(i[s])),i[s].push(t)):i[s]=t}return i}function _(t){return t.entries?t.entries():Array.from({[Symbol.iterator]:function*(){for(const e in t)yield[e,t[e]]}})}var l=Object.freeze({__proto__:null,EMPTY_FUNCTION:()=>{},objectEntries:_,objectFrom:d,options:function(t=("undefined"==typeof location?void 0:location)){if(!t)return{};try{t=new URL(t).searchParams}catch(e){"string"==typeof t&&(t.startsWith("?")&&(t=t.substring(1)),t=new URLSearchParams(t))}return d(t,{withType:!0,noEmptyString:!0})},safePromise:function(t,e){let i;return Promise.race([e instanceof Promise?e:new Promise(e),new Promise(((e,s)=>i=setTimeout((()=>s("timed out in "+t+"ms")),t)))]).finally((()=>clearTimeout(i)))},stringify:function t(e,i={}){if(i=Object.assign({space:" ",decimal:2,recursive:1},i),null==e)return String(e);const s=e.error||e.message;if(s&&(e=s),e.toFixed)return e.toFixed(Number(i.decimal)||0);if(e.substring||!i.recursive)return String(e);const r=i.space||"";if(Array.isArray(e)){let s="";for(const n of e)s+=(s?",":"[")+r,s+=t(n,Object.assign(i,{recursive:i.recursive-1}));return s+=r+"]"}if(null!=e.byteLength&&(null==e?void 0:e[Symbol.iterator]))return h.decode(e);let n="";for(const s in e)n+=(n?",":"{")+r+s+":",n+=t(e[s],Object.assign(i,{recursive:i.recursive-1}));return n+(r+"}")},time:function(){return Math.floor(u.now())},timeOrigin:function(){return Math.floor(u.now()+u.timeOrigin)},toBin:function(t){return c.encode(t)}});class m extends r{onOpen(){}onMessage(t){}onClose(t){t&&console.error(t)}get binaryType(){return"arraybuffer"}get url(){var t,e;return null!==(e=null===(t=this._ws)||void 0===t?void 0:t.url)&&void 0!==e?e:""}get extensions(){var t,e;return null!==(e=null===(t=this._ws)||void 0===t?void 0:t.extensions)&&void 0!==e?e:""}get protocol(){var t,e;return null!==(e=null===(t=this._ws)||void 0===t?void 0:t.protocol)&&void 0!==e?e:""}get opened(){return this._opened}get readyState(){return this._ws?this._ws.readyState:3}get closed(){return this._closed}get bufferedAmount(){var t;return this._queueingBytes+((null===(t=this._ws)||void 0===t?void 0:t.bufferedAmount)||0)}get queueing(){return this._queueing}constructor(t,e){super(),this._queueing=[],this._queueingBytes=0,this._opened=!1,this._closed=!0,t&&this.open(t,e)}open(t,e){this._closed=!1;const i=this._ws=new WebSocket(t,e);return i.binaryType=this.binaryType,i.onmessage=t=>this.onMessage(t.data),i.onclose=e=>{this._opened?1e3===e.code||1005===e.code?this.close(t.toString()+" shutdown"):this.close(t.toString()+" disconnection ("+String(e.reason||e.code)+")"):this.close(t.toString()+" connection failed ("+String(e.reason||e.code)+")")},i.onopen=t=>{this._opened=!0,this.flush(),this.onOpen()},this}send(t,e=!1){if(!this._ws)throw Error("Open socket before to send data");return e||!this._opened?(this._queueing.push(t),this._queueingBytes+="string"==typeof t?t.length:t.byteLength):this._ws.send(t),this}flush(){if(this._ws)for(const t of this._queueing)this._ws.send(t);this._queueing.length=0,this._queueingBytes=0}close(t){this._ws&&!this._closed&&(this._closed=!0,this._ws.onopen=this._ws.onclose=this._ws.onmessage=null,this._ws.close(),this._opened=!1,this._queueing.length=0,this._queueingBytes=0,this.onClose(t))}}var p,g=Object.freeze({__proto__:null,BinaryReader:class{constructor(t){this._data="buffer"in t?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t),this._size=this._data.byteLength,this._position=0,this._view=new DataView(this._data.buffer,this._data.byteOffset,this._size)}data(){return this._data}size(){return this._size}available(){return this._size-this._position}value(t=this._position){return this._data[t]}position(){return this._position}reset(t=0){this._position=t>this._size?this._size:t}shrink(t){const e=this._size-this._position;return t>e?e:(this._size=this._position+t,t)}next(t=1){const e=this._size-this._position;return t>e&&(t=e),this._position+=t,t}read8(){return 1===this.next(1)?this._view.getUint8(this._position-1):0}read16(){return 2===this.next(2)?this._view.getUint16(this._position-2):0}read24(){return 3===this.next(3)?this._view.getUint16(this._position-3)<<8|255&this._view.getUint8(this._position-1):0}read32(){return 4===this.next(4)?this._view.getUint32(this._position-4):0}readFloat(){return 4===this.next(4)?this._view.getFloat32(this._position-4):0}readDouble(){return 8===this.next(8)?this._view.getFloat64(this._position-8):0}read7Bit(t=5){if(t>5)throw Error("BinaryReader in JS can't decode more than 32 usefull bits");if(!(t>0))throw Error("Have to indicate a positive number of bytes to decode");let e,i=0;do{if(e=this.read8(),! --t)return(i<<8|e)>>>0;i=i<<7|127&e}while(128&e);return i}readString(){return String.fromCharCode(...this.read(this.read7Bit()))}readHex(t){let e="";for(;t--;)e+=("0"+this.read8().toString(16)).slice(-2);return e}read(t=this.available()){if(this.available()<t)return new Uint8Array(t);const e=this._data.subarray(this._position,this._position+t);return this._position+=t,e}},BinaryWriter:class{get view(){return this._view||(this._view=new DataView(this._data.buffer,this._data.byteOffset,this._data.byteLength)),this._view}get capacity(){return this._data.byteLength}constructor(t=64,e=0,i){"number"==typeof t?(this._data=new Uint8Array(t),this._size=0):"buffer"in t?(this._data=new Uint8Array(t.buffer,t.byteOffset,t.byteLength),this._size=t.byteLength):(this._isConst=!0,null==i&&(i=t.byteLength),this._data=new Uint8Array(t,e,i),this._size=0)}data(){return new Uint8Array(this._data.buffer,this._data.byteOffset,this._size)}size(){return this._size||0}next(t=1){return this.reserve(this._size+=t)}clear(t=0){return this.reserve(this._size=t)}write(t){if(this.reserve(this._size+t.length),"string"==typeof t){for(let e=0;e<t.length;++e){const i=t.charCodeAt(e);this._data[this._size++]=i>255?32:i}return this}return this._data.set(t,this._size),this._size+=t.length,this}write8(t){return t>255&&(t=255),this.reserve(this._size+1),this._data[this._size++]=t,this}write16(t){return t>65535&&(t=65535),this.reserve(this._size+2),this.view.setUint16(this._size,t),this._size+=2,this}write24(t){return t>16777215&&(t=16777215),this.reserve(this._size+3),this.view.setUint16(this._size,t>>8),this.view.setUint8(this._size+=2,255&t),++this._size,this}write32(t){return t>4294967295&&(t=4294967295),this.reserve(this._size+4),this.view.setUint32(this._size,t),this._size+=4,this}writeFloat(t){return this.reserve(this._size+4),this.view.setFloat32(this._size,t),this._size+=4,this}writeDouble(t){return this.reserve(this._size+8),this.view.setFloat64(this._size,t),this._size+=8,this}write7Bit(t,e=5){if(e>5)throw Error("BinaryWriter in JS can't encode more than 32 usefull bits");if(!(e>0))throw Error("Have to indicate a positive number of bytes to encode");let i=7*--e;const s=t>4294967295?256:t>>>i;if(s)++i,s>255&&(t=4294967295);else for(;(i-=7)&&!(t>>>i););for(;i>1;)this.write8(128|t>>>i&255),i-=7;return this.write8(t&(i?255:127))}writeString(t){return this.write7Bit(t.length).write(t)}writeHex(t){for(let e=0;e<t.length;e+=2)this.write8(parseInt(t.substring(e,e+2),16));return this}reserve(t){if(!this._data)throw new Error("buffer not writable");if(t<=this._data.byteLength)return this;if(this._isConst)throw new Error("writing exceeds maximum "+this._data.byteLength+" bytes limit");--t,t|=t>>1,t|=t>>2,t|=t>>4,t|=t>>8,t|=t>>16,++t;const e=new Uint8Array(t);return e.set(this._data),this._data=e,this._view=void 0,this}},BitReader:class{constructor(t){this._data="buffer"in t?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t),this._size=this._data.byteLength,this._position=0,this._bit=0}data(){return this._data}size(){return this._size}available(){return 8*(this._size-this._position)-this._bit}next(t=1){let e=0;for(;this._position!==this._size&&t--;)++e,8==++this._bit&&(this._bit=0,++this._position);return e}read(t=1){let e=0;for(;this._position!==this._size&&t--;)e<<=1,this._data[this._position]&128>>this._bit++&&(e|=1),8===this._bit&&(this._bit=0,++this._position);return e}read8(){return this.read(8)}read16(){return this.read(16)}read24(){return this.read(24)}read32(){return this.read(32)}},Connect:s,EventEmitter:r,NetAddress:e,Numbers:o,Queue:n,SDP:a,Util:l,VERSION:"1.2.0",WebSocketReliable:m});function f(t,e,i){for(let s=0;s<e.length;++s){const r=e[s];i.has(r.codec.toLowerCase())||(t.delete(r.idx),e.splice(s--,1))}}!function(t){t.AUDIO="audio",t.VIDEO="video",t.DATA="data"}(p||(p={}));class v{constructor(){this.type="",this.width=0,this.height=0,this.sources=new Map,this.tracks=new Map,this.audios=[],this.videos=[],this.datas=[]}subset(t){const e=Object.assign({},this);if(t){f(e.tracks,e.audios,t),f(e.tracks,e.videos,t);for(const[,t]of e.tracks){for(;t.up&&!e.tracks.has(t.up.idx);)t.up=t.up.up;for(;t.down&&!e.tracks.has(t.down.idx);)t.down=t.down.down}}return e}}const y=(t,e)=>e.maxbps-t.maxbps;class b extends r{onLog(t){}onError(t="unknown"){console.error(t)}onClose(){this.onLog("onClose")}onMetadata(t){this.onLog(l.stringify(t))}get url(){return this._ws.url}get connectParams(){return this._connectParams}get metadata(){return this._metadata}get closed(){return this._ws.closed}constructor(t){super(),this._connectParams=t,this._ws=new m(s.buildURL(s.Type.META,t)),this._ws.onClose=t=>{this._metadata=new v,t&&this.onError(t),this.onClose()},this._ws.onMessage=t=>{try{const e=JSON.parse(t);if(e.error)throw e.error;this._metadata=new v,this._metadata.type=e.type,this._metadata.width=e.width,this._metadata.height=e.height,this._metadata.sources.clear();for(const t of e.source)this._metadata.sources.set(t.hrn,t);const i=[];this._metadata.tracks.clear();for(const[t,s]of l.objectEntries(e.meta.tracks)){switch(s.name=t,s.type=s.type.toLowerCase(),s.type){case"audio":this._metadata.audios.push(s);continue;case"video":this._metadata.videos.push(s);continue;case"meta":s.type=p.DATA,this._metadata.datas.push(s);break;default:this.onLog("Unknown track type"+s.type)}i.push(s)}this._addSortedTrack(this._metadata.audios,this._metadata.tracks),this._addSortedTrack(this._metadata.videos,this._metadata.tracks);for(const t of i)this._metadata.tracks.set(t.idx,t)}catch(t){return void this.onError(l.stringify(t))}this.onMetadata(this._metadata)}}close(t){this._ws.close(t)}_addSortedTrack(t,e){t.sort(y);for(let i=0;i<t.length;++i){const s=t[i];e.set(s.idx,s),i&&(s.up=t[i-1],t[i-1].down=s)}}}function w(t){return"send"in t}const T=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);class k extends r{onLog(t){}onError(t="unknown"){console.error(t)}onOpen(t){this.onLog("onOpen")}onClose(){this.onLog("onClose")}get opened(){return!(!this._peerConnection||this._peerConnection.ontrack!==l.EMPTY_FUNCTION)}get closed(){return this._closed}get stream(){return this._stream}get streamName(){return this._streamName}get codecs(){return this._codecs}constructor(t,e){super(),this._closed=!1,this._streamName=t.streamName,this._host=t.host,this._stream=e,this._connectionInfosTime=0,this._codecs=new Set}connectionInfos(e=1e3){return t(this,void 0,void 0,(function*(){if(!this._peerConnection)return Promise.reject("Not connected");if(!this._connectionInfos||l.time()-e>this._connectionInfosTime){const t=yield this._peerConnection.getStats(null);this._connectionInfos={inputs:{},outputs:{}};const e=new Map,i=new Map;for(const s of t.values())switch(s.type){case"track":e.set(s.id,s);break;case"outbound-rtp":i.set(s.trackId,s),this._connectionInfos.outputs["audio"===(s.kind||s.mediaType)?"audio":"video"]=s;break;case"inbound-rtp":i.set(s.trackId,s),this._connectionInfos.inputs["audio"===(s.kind||s.mediaType)?"audio":"video"]=s;break;case"candidate-pair":if(null!=s.selected){if(!s.selected)continue}else if(null!=s.nominated&&!s.nominated)continue;this._connectionInfos.candidate=s}for(const[t,s]of e){const e=i.get(t);e&&Object.assign(e,Object.assign(Object.assign({},s),e))}this._connectionInfosTime=l.time()}return this._connectionInfos}))}close(t){if(this._closed)return;this._closed=!0;const e=this._peerConnection;e&&(this._peerConnection=void 0,e.getReceivers().forEach((t=>t.track&&t.track.stop())),e.getSenders().forEach((t=>t.track&&t.track.stop())),e.close()),this._stream&&this._stream.getTracks().forEach((t=>t.stop())),t&&this.onError(t),this.onClose()}_open(t){if(!t){const i=new e(this._host,443).domain;t={urls:["turn:"+i+":3478?transport=tcp","turn:"+i+":3478"],username:"csc_demo",credential:"UtrAFClFFO"}}try{this._peerConnection=new RTCPeerConnection({iceServers:[t]})}catch(t){return void this.close("RTCPeerConnection failed, "+l.stringify(t))}if(this._stream)for(const t of this._stream.getTracks())this._peerConnection.addTrack(t);else this._peerConnection.ontrack=t=>{this._stream=t.streams[0],this._tryToOpen()};if(T)if(this._stream){const t=this._peerConnection.getTransceivers();for(const e of t)"audio"!==e.receiver.track.kind&&"video"!==e.receiver.track.kind||(e.direction="sendonly")}else this._peerConnection.addTransceiver("audio",{direction:"recvonly"}),this._peerConnection.addTransceiver("video",{direction:"recvonly"});let i;this._peerConnection.createOffer({offerToReceiveAudio:!this._stream,offerToReceiveVideo:!this._stream}).then((t=>{var e;if(this._peerConnection)return i=null!==(e=t.sdp)&&void 0!==e?e:"",this.onLog("Offer\r\n"+i),this._peerConnection.setLocalDescription(t)})).then((t=>{if(this._peerConnection)return i?this._sip(i):Promise.reject("invalid empty sdp offer")})).then((t=>{if(t&&this._peerConnection){this.onLog("Answer\r\n"+t);for(const e of a.fromString(t)){if(!e.rtpmap)continue;let t=e.rtpmap.indexOf(" ");if(t<0)continue;let i=e.rtpmap.substring(t+1);if(!i)return;t=i.indexOf("/"),i=t<0?i:i.substring(0,t),this._codecs.add(i.toLowerCase())}return this._peerConnection.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:t}))}})).then((()=>this._tryToOpen())).catch((t=>this.close("SIP failed, "+l.stringify(t))))}_tryToOpen(){this._stream&&this._peerConnection&&this._peerConnection.ontrack!==l.EMPTY_FUNCTION&&(this._peerConnection.ontrack=l.EMPTY_FUNCTION,this.onOpen(this._stream))}}class S extends k{onRTPProps(t){this.onLog("onRTPProps "+l.stringify(t))}onMediaReport(t){console.debug("onMediaReport "+l.stringify(t))}onVideoBitrate(t,e){this.onLog("onVideoBitrate "+l.stringify({video_bitrate:t,video_bitrate_constraint:e}))}onPlaying(t){console.debug("onPlaying "+l.stringify(t))}constructor(t,e){super(t,e),this._ws=new m(s.buildURL(s.Type.WEBRTC,t,"wss")),this._ws.onClose=t=>this.close(t),this._ws.onOpen=()=>{this._open(t.iceServer)},this._ws.onMessage=t=>{try{this._eventHandler(JSON.parse(t))}catch(t){this.onError("Invalid signaling message, "+l.stringify(t))}}}setRTPProps(t,e){this.send("rtp_props",{nack:t,drop:e})}setVideoBitrate(t){this.send("video_bitrate",{video_bitrate:t})}setTracks(t){this.send("tracks",t)}send(t,e){try{this.onLog("Command "+t+" "+l.stringify(e)),this._ws.send(JSON.stringify(Object.assign({type:t},e)))}catch(t){this.onError(l.stringify(t))}}close(t){this._ws.close(t),this._promise&&(this._promise(Error("closing")),this._promise=void 0),super.close(t)}_sip(t){return new Promise(((e,i)=>{this._promise=t=>{t instanceof Error?i(t):e(t)},this._ws.send(JSON.stringify({type:"offer_sdp",offer_sdp:t}))}))}_eventHandler(t){var e,i;switch(t.type){case"on_answer_sdp":this._promise&&this._promise(t.answer_sdp);break;case"on_error":this.opened?this.onError(l.stringify(t)):this.close(l.stringify(t));break;case"on_video_bitrate":this.onVideoBitrate(t.video_bitrate,t.video_bitrate_constraint);break;case"on_stop":this.onLog("on_stop"),this.close();break;case"on_track_drop":{const s=null!==(e=t.mediatype)&&void 0!==e?e:"?",r=null!==(i=t.track)&&void 0!==i?i:"?";this.onError(s+" track #"+r+"dropped");break}case"on_rtp_props":this.onRTPProps(t);break;case"on_media_receive":this.onMediaReport(t);break;case"on_seek":break;case"on_time":this.onPlaying(t);break;default:this.onError("Unhandled event: "+t.type)}}}class x extends k{constructor(t,e){super(t,e),this._url=s.buildURL(s.Type.WEBRTC,t,"https"),this._fetch=new AbortController,setTimeout((()=>{this._open(t.iceServer)}),0)}close(t){this._fetch.abort(),super.close(t)}_sip(e){return t(this,void 0,void 0,(function*(){const t=yield fetch(this._url,{method:"POST",body:e,headers:{"Content-Type":"application/sdp"},signal:this._fetch.signal});return t?t.text():Promise.reject("client rejected")}))}}class C extends r{onLog(t){}onError(t="unknown"){console.error(t)}onClose(){this.onLog("onClose")}onData(t,e,i){this.onLog(`Data received on track ${e} at ${t} : ${l.stringify(i)}`)}get url(){return this._url}get tracks(){return[...this._tracks]}set tracks(t){this._tracks=[...t],this._sendTracks()}get closed(){return!this._ws||this._ws.closed}constructor(t){super(),this._url=s.buildURL(s.Type.DATA,t).toString(),this._tracks=Array(),this._ws=new m,this._ws.onOpen=()=>this._sendTracks(),this._ws.onClose=t=>{t&&this.onError(t),this.onClose()},this._ws.onMessage=t=>{let e;try{e=JSON.parse(t)}catch(t){return this.onError("Invalid signaling message, "+l.stringify(t))}if(e.error)return this.onError(e.error);"time"in e&&"track"in e&&"data"in e?this.onData(e.track,e.time,e.data):"on_time"!==e.type&&console.debug("Internal JSON : ",l.stringify(e))}}close(t){this._ws.close(t)}_sendTracks(){this._tracks.length?this._ws.closed?this._ws.open(this._url):this._ws.opened&&this._ws.send(JSON.stringify({type:"tracks",tracks:this._tracks.join(",")})):this.close()}}class B{onLog(t){}onError(t="unknown"){console.error(t)}get upDelay(){return this._upDelay}get learningUpStep(){return this._learningUpStep}get maximumUpDelay(){return this._maximumUpDelay}constructor(t){const e=Object.assign({learningUpStep:1400,maximumUpDelay:28e3},t);this._learningUpStep=e.learningUpStep,this._maximumUpDelay=e.maximumUpDelay,this._upDelay=0,this._testTime=0}reset(){this._upDelay=0,this._mTrack=void 0}compute(t,e,i){var s;const r=null!==(s=e.video)&&void 0!==s?s:e.audio;if(null==r)return this._mTrack=void 0,!1;const n=l.time();if(!(this._mTrack&&this._mTrack.idx===r||(this._appreciationTime=void 0,this._testTime=n,this._mTrack=t.tracks.get(r),this._mTrack)))return this.onError("Can't find track "+r+" absent from metadata"),!1;const o=r===e.video?i.video:i.audio;if(!o)return this.onError("Can't compute "+this._mTrack.type+" track "+this._mTrack.idx+" without statistics"),!1;const a=this._downBitrate(n-this._testTime,this._mTrack,o);if(a)this._appreciationTime=void 0;else{this._appreciationTime||(this._appreciationTime=n);const t=n-this._appreciationTime;if(!this._upBitrate(t,this._mTrack,o)||t<this._upDelay)return!1}let h=this.updateTrack(e.audio,t,a);if(h)e.audio=h.idx;else{if(h=this.updateTrack(e.video,t,a),!h)return!1;e.video=h.idx}return a&&(this._upDelay=Math.min(this._upDelay+this._learningUpStep,this._maximumUpDelay)),this.onLog((a?"DOWN":"UP")+" from "+this._mTrack.type+" track "+this._mTrack.idx+" ("+this._mTrack.maxbps+"bps) to "+h.type+" track "+h.idx+" ("+h.maxbps+"bps)"),!0}updateTrack(t,e,i){if(null==t)return;const s=i?"down":"up",r=e.tracks.get(t);if(r)return r[s];this.onError("Can't find track "+t+" from metadata")}}class L extends B{constructor(t){super(t),this._keyFramesDecoded=0,this._lost=0,this._nackCount=0}_downBitrate(t,e,i){const s=i.packetsLost,r=i.nackCount;if(null==s)return this.onLog("No packetsLost information in "+l.stringify(i)),!1;const n=t>0&&s>this._lost&&(!r||r>this._nackCount);return this._lost=s,this._nackCount=r||0,n}_upBitrate(t,e,i){if(e.type===p.AUDIO)return!0;if(t>1e4)return!0;const s=i.keyFramesDecoded;if(null==s)return!1;if(t){if(s>this._keyFramesDecoded){if(!this._keyFramesDecoded)return!0;this._keyFramesDecoded=0}}else this._keyFramesDecoded=s;return!1}}const R=1e3;class E extends r{onLog(t){}onError(t="unknown"){console.error(t)}onStart(t){this.onLog("onStart")}onStop(){this.onLog("onStop")}onPlaying(t){console.debug("onPlaying "+l.stringify(t))}onMetadata(t){this.onLog(l.stringify(t))}onData(t,e,i){this.onLog(`Data received on track ${e} at ${t} : ${l.stringify(i)}`)}get streamName(){return this._connector?this._connector.streamName:""}get stream(){return this._connector&&this._connector.stream}get running(){return!!this._connector}get controller(){return this._controller}get connector(){return this._connector}get metadata(){return this._metadata}get playingInfos(){return this._playingInfos}get audioTrack(){return this._audioTrack}set audioTrack(t){if(this._audioTrackFixed=null!=t,this._audioTrackFixed&&this._audioTrack!==t&&(this._audioTrack=t,this._connector)){if(!this._controller)throw Error("Cannot set audioTrack without start a controllable session");this._controller.setTracks({audio:t})}}get videoTrack(){return this._videoTrack}set videoTrack(t){if(this._videoTrackFixed=null!=t,this._videoTrackFixed&&this._videoTrack!==t&&(this._videoTrack=t,this._connector)){if(!this._controller)throw Error("Cannot set videoTrack without start a controllable session");this._controller.setTracks({video:t})}}get dataTracks(){return[...this._dataTracks]}set dataTracks(t){this._dataTracks=[...t],this._streamData&&(this._streamData.tracks=t)}constructor(t){super(),this.Connector=t,this._dataTracks=new Array}connectionInfos(){return this._connector?this._connector.connectionInfos():Promise.reject("Start player before to request connection infos")}start(e,i={}){let s,r,n;this.stop(),"connectParams"in e?(this._initStreamMetadata(Object.assign({},e.connectParams),e),e=e.connectParams):this._initStreamMetadata(Object.assign({},e),new b(e)),null!=this._audioTrack&&(e.query=Object.assign({audio:this._audioTrack.toFixed()},e.query)),null!=this._videoTrack&&(e.query=Object.assign({video:this._videoTrack.toFixed()},e.query)),this._audioTrackFixed=!1,this._videoTrackFixed=!1,this._connector=new(this.Connector||(e.host.startsWith("http")?x:S))(e),this._connector.onLog=t=>this.onLog("Signaling: "+t),this._connector.onError=t=>this.onError("Signaling: "+t),this._connector.onOpen=t=>{var e,i;this.onStart(t),(null===(e=this._streamMetadata)||void 0===e?void 0:e.metadata)&&this._streamMetadata.onMetadata(null===(i=this._streamMetadata)||void 0===i?void 0:i.metadata),r&&this._controller&&this._controller.onPlaying(r)},this._connector.onClose=()=>{null==s||s.reset(),this.stop()},this._newStreamData(Object.assign({},e)),w(this._connector)?(i&&("compute"in i?s=i:(s=new L(i),s.onLog=t=>this.onLog("MultiBitrate: "+t))),this._controller=this._connector,this._controller.onPlaying=e=>t(this,void 0,void 0,(function*(){if(r=e,this._controller&&this._controller.opened&&(this._playingInfos=r,this._updateTracks(),this.onPlaying(r),s))if(this._audioTrackFixed&&this._videoTrackFixed)s.reset();else try{const t=yield this._controller.connectionInfos(1e3);if(t===n)return;const e={audio:this._audioTrackFixed?void 0:this._audioTrack,video:this._videoTrackFixed?void 0:this._videoTrack};this._controller&&this._metadata&&s.compute(this._metadata,e,(n=t).inputs)&&(this._audioTrack=e.audio,this._videoTrack=e.video,this._controller.setTracks(e))}catch(t){this.onError("Can't compute MBR, "+l.stringify(t))}}))):i&&this.onLog("Cannot use a multiple bitrate without a controller: Connector "+this._connector.constructor.name+" doesn't implements IController")}stop(){const t=this._connector;t&&(this._connector=void 0,this._streamMetadata&&(this._streamMetadata.close(),this._streamMetadata=void 0),this._streamData&&(this._streamData.close(),this._streamData=void 0),t.close(),this._audioTrack=void 0,this._videoTrack=void 0,this._dataTracks.length=0,this._playingInfos=void 0,this._metadata=void 0,this.onStop())}_updateTracks(){if(!this._playingInfos||!this._metadata)return;const t=new Array,e=new Array;for(const i of this._playingInfos.tracks){const s=this._metadata.tracks.get(i);s&&(s.type===p.AUDIO?t.push(i):s.type===p.VIDEO&&e.push(i))}1===t.length&&(this._audioTrack=t[0]),1===e.length&&(this._videoTrack=e[0])}_initStreamMetadata(t,e){this._streamMetadata=e,e.onLog=t=>this.onLog("StreamMetadata: "+t),e.onError=t=>this.onError("StreamMetadata: "+t),e.onMetadata=t=>{this._connector&&this._connector.opened&&(this._metadata=t.subset(this._connector.codecs),this._updateTracks(),this.onMetadata(this._metadata))},e.onClose=()=>{this.onLog("StreamMetadata closed, trying to reconnect in 1000ms"),setTimeout((()=>{this._streamMetadata===e&&this._initStreamMetadata(t,new b(t))}),R)}}_newStreamData(t){const e=this._streamData=new C(t);e.onLog=t=>this.onLog("Timed Metadatas: "+t),e.onError=t=>this.onError("Timed Metadatas: "+t),e.onData=(t,e,i)=>this.onData(e,t,i),e.tracks=this._dataTracks,e.onClose=()=>{this.onLog("Timed Metadatas closed, trying to reconnect in 1000ms"),setTimeout((()=>{this._streamData===e&&this._newStreamData(t)}),R)}}}class O extends r{onLog(t){}onError(t="unknown"){console.error(t)}get startup(){return this._startup}set startup(t){this._startup=Math.max(this._minimum,Math.min(Math.round(t),this._maximum))}get minimum(){return this._minimum}set minimum(t){t=Math.round(t),(this._minimum=t)>this._maximum?this._maximum=this._startup=t:this._startup<t&&(this._startup=t)}get maximum(){return this._maximum}set maximum(t){t=Math.round(t),(this._maximum=t)<this._minimum?this._minimum=this._startup=t:this._startup>t&&(this._startup=t)}get constraint(){return this._bitrateConstraint}get value(){return this._bitrate}valueOf(){return this.value}get stream(){return this._stream}constructor(t,e){super();const i=Object.assign({startup:2e6,maximum:3e6,minimum:2e5},t);this._startup=i.startup,this._minimum=i.minimum,this._maximum=i.maximum,this._stream=e}compute(t,e,i){if(null==t)return this._bitrate=t;const s=null==this._bitrate,r=s?this.startup:Math.max(this.minimum,Math.min(this._computeBitrate(t,e,i),this.maximum));return this._bitrate=t,this._bitrateConstraint=e,s?this.onLog("Set startup bitrate to "+r):r>t?this.onLog("Increase bitrate "+t+" => "+r):r<t&&this.onLog("Decrease bitrate "+t+" => "+r),r}reset(){this._bitrate=this._bitrateConstraint=void 0}_updateVideoConstraints(t){const e=this._stream;if(!e)return;const i=e.getVideoTracks()[0];if(!i)return;const s=i.getSettings();if(!s.width||!s.height)return;const r=s.width*s.height;t>=12e5?r<645120&&this._upgradeVideoConstraint(i,2):r>645120&&r<1198080&&this._upgradeVideoConstraint(i,.5)}_upgradeVideoConstraint(t,e){const i={},s=t.getSettings().width;null!=s&&(i.width=s*e);const r=t.getSettings().height;null!=r&&(i.height=r*e),this.onLog("Resolution change "+s+"X"+r+" => "+i.width+"X"+i.height),t.applyConstraints(i)}}let P=class{constructor(){this.stableTime=0,this.stableBitrate=0,this.attempts=1,this.lastLoss=Number.POSITIVE_INFINITY}};class M extends O{constructor(t,e){super(t,e),this._vars=new P}reset(){super.reset(),this._vars=new P}_computeBitrate(t,e,i){const s=i&&i.stats,r=this._vars;if(s&&s.loss_perc)s.loss_perc>=r.lastLoss&&(r.stableTime&&++r.attempts,r.stableTime=0,t=Math.round((1-s.loss_perc/100)*t)),r.lastLoss=s.loss_perc;else{r.lastLoss=Number.POSITIVE_INFINITY;const e=l.time();e>=r.stableTime&&(r.stableTime?(this._updateVideoConstraints(t),t+=Math.ceil((this.maximum-r.stableBitrate)/r.attempts)):r.stableBitrate=t,r.stableTime=e+11)}return t}}class A extends r{onLog(t){}onError(t="unknown"){console.error(t)}onStart(t){this.onLog("onStart")}onStop(){this.onLog("onStop")}onRTPProps(t){this.onLog("onRTPProps "+l.stringify(t))}onMediaReport(t){console.debug("onMediaReport "+l.stringify(t))}onVideoBitrate(t,e){this.onLog("onVideoBitrate "+l.stringify({videoBitrate:t,videoBitrateConstraint:e}))}get streamName(){return this._connector?this._connector.streamName:""}get stream(){return this._connector&&this._connector.stream}get running(){return!!this._connector}get controller(){return this._controller}get connector(){return this._connector}get mediaReport(){return this._mediaReport}get rtpProps(){return this._rtpProps}get videoBitrate(){return this._videoBitrate}set videoBitrate(t){if(!this._controller)throw Error("Cannot set videoBitrate without start a controllable session");this._videoBitrateFixed=null!=t,this._videoBitrateFixed&&t!==this._videoBitrate&&this._controller.setVideoBitrate(t)}get videoBitrateConstraint(){return this._videoBitrateConstraint}constructor(t){super(),this.Connector=t,this._videoBitrate=0,this._videoBitrateConstraint=0}setRTPProps(t,e){if(!this._controller)throw Error("Cannot set rtpProps without start a controllable session");this._controller.setRTPProps(t,e)}connectionInfos(){return this._connector?this._connector.connectionInfos():Promise.reject("Start streamer before to request connection infos")}start(e,i,s={}){let r;this.stop(),this._videoBitrateFixed=!1,this._connector=new(this.Connector||(i.host.startsWith("http")?x:S))(i,e),this._connector.onLog=t=>this.onLog("Signaling: "+t),this._connector.onError=t=>this.onError("Signaling: "+t),this._connector.onOpen=t=>this.onStart(t),this._connector.onClose=()=>{null==r||r.reset(),this.stop()},w(this._connector)?(s&&("compute"in s?r=s:(r=new M(s),r.onLog=t=>this.onLog("AdaptiveBitrate: "+t))),this._controller=this._connector,this._controller.onOpen=t=>{this._computeVideoBitrate(r),this.onStart(t)},this._controller.onRTPProps=t=>{this._rtpProps=t,this.onRTPProps(t)},this._controller.onMediaReport=e=>t(this,void 0,void 0,(function*(){this._mediaReport=e,this._computeVideoBitrate(r),this.onMediaReport(e)})),this._controller.onVideoBitrate=(t,e)=>{this._videoBitrate=t,this._videoBitrateConstraint=e,this.onVideoBitrate(t,e)}):s&&this.onLog("Cannot use an adaptive bitrate without a controller: Connector "+this._connector.constructor.name+" doesn't implements IController")}stop(){const t=this._connector;t&&(this._connector=void 0,t.close(),this._controller=void 0,this._mediaReport=void 0,this._videoBitrate=0,this._videoBitrateConstraint=0,this._rtpProps=void 0,this.onStop())}_computeVideoBitrate(t){var e;if(!this._controller||this._videoBitrateFixed)return;const i=null!==(e=t.compute(this._videoBitrate,this.videoBitrateConstraint,this.mediaReport))&&void 0!==e?e:this._videoBitrate;i!==this._videoBitrate&&this._controller.setVideoBitrate(i)}}class I{constructor(){this.lossPercents=new o(5),this.stableBitrates=new o(15),this.stableBitrateUpdateTime=0,this.bitrateRecoveryTimeout=1e4,this.bitrateRecoveryNextTime=0}}class D extends O{constructor(t,e){super(t,e),this._vars=new I}reset(){super.reset(),this._vars=new I}_computeBitrate(t,e,i){var s;const r=this._vars,n=i&&i.stats;n&&null!=n.loss_perc&&r.lossPercents.push(n.loss_perc);const o=l.time();o>=r.stableBitrateUpdateTime&&r.lossPercents.average<.2&&(r.stableBitrateUpdateTime=o+4e3,r.stableBitrates.push(Math.min(null!==(s=null!=e?e:this.constraint)&&void 0!==s?s:0,t,this.maximum)));const a=r.stableBitrates.average,h=r.stableBitrates.minimum,c=r.stableBitrates.maximum;if(h>=.8*a&&c<=1.2*a&&this._updateVideoConstraints(a),null!=e&&null!=this.constraint&&e<this.constraint){if(this.onLog(`onVideoBitrateConstraint: ${this._formatBitrate(e-this.constraint)}`),r.bitrateConstraintTime){if(r.bitrateRecoveryTime){(o-r.bitrateRecoveryTime<r.bitrateRecoveryTimeout||2500===r.bitrateRecoveryTimeout)&&(this._increaseRecoveryTimeout(),r.bitrateRecoveryTime=void 0)}}else r.bitrateRecoveryTime||(this.onLog("VideoBitrateConstraint: First constrain! Halve bitrate!"),t=Math.round(t/2));r.bitrateConstraintTime=o}if(e&&(e<this.minimum&&(t=this.minimum),this.maximum>e&&o>=r.bitrateRecoveryNextTime)){const i=r.bitrateRecoveryNextTime&&this._bitrateRecoveryHandler(e);i?(r.bitrateRecoveryTimeout=o,r.bitrateRecoveryNextTime=0,t=i):(r.bitrateRecoveryNextTime=o+r.bitrateRecoveryTimeout,this.onLog("startVideoBitrateRecoveryTimer "+r.bitrateRecoveryTimeout))}return t}_bitrateRecoveryHandler(t){const e=this._vars,i=e.lossPercents.average;if(this.onLog("videoBitrateRecoveryHandler loss: "+i.toFixed(2)),i<.2){let i=this._increaseTargetBitrate(t);return e.bitrateConstraintTime&&i>e.stableBitrates.average&&(i=this._increaseTargetBitrate(t,1.005)),this._decreaseRecoveryTimeout(),this.onLog("videoBitrateRecoveryHandler increase bitrate to "+this._formatBitrate(i)),i}if(i<5){this._increaseRecoveryTimeout();const e=this._decreaseTargetBitrate(t);return this.onLog("videoBitrateRecoveryHandler decrease bitrate to "+this._formatBitrate(e)),e}}_increaseTargetBitrate(t,e=1.05){let i=Math.round(t*e);return i>this.maximum&&(i=this.maximum),i}_decreaseTargetBitrate(t){let e=Math.round(.99*t);return e<this.minimum&&(e=this.minimum),e}_increaseRecoveryTimeout(){this._vars.bitrateRecoveryTimeout=Math.min(6e4,2*this._vars.bitrateRecoveryTimeout)}_decreaseRecoveryTimeout(){this._vars.bitrateRecoveryTimeout=Math.max(2500,Math.round(.75*this._vars.bitrateRecoveryTimeout))}_formatBitrate(t){return(t/1e6).toFixed(3)}}class N extends r{onLog(t){}onError(t="unknown"){console.error(t)}get url(){return this._url}get reporting(){return this._reporting}constructor(t){if(super(),(t=new URL(t)).protocol.startsWith("ws"))this._ws=new m;else if(!t.protocol.startsWith("http"))throw Error("Protocol "+t.protocol+" not supported");this._url=t.toString(),this._reporting=0}report(e,i){e.onError=t=>this.onError(e.constructor.name+" error, "+t),e.onLog=t=>this.onError(e.constructor.name+", "+t);let s=e.onRelease=()=>{s&&(s=void 0,clearInterval(r),this.onLog("Stop "+e.constructor.name+" reporting"),--this._reporting>0||(this._ws&&this._ws.close(),this._fetch&&this._fetch.abort()))};const r=(i?setInterval:setTimeout)((()=>t(this,void 0,void 0,(function*(){!i&&s&&s();try{yield this._send(e)}catch(t){this.onError(e.constructor.name+" error, "+l.stringify(t))}}))),1e3*i);++this._reporting,this.onLog("Start "+e.constructor.name+" reporting every "+i+" seconds")}_send(e){return t(this,void 0,void 0,(function*(){let t,i,s;try{t=yield e.serialize()}catch(t){if(!t)return;throw t}t instanceof ArrayBuffer?(s="application/octet-stream",i=t):"string"==typeof t?(s="text/plain",i=t):(s="application/json",i=JSON.stringify(t)),this._ws?(this._ws.closed&&this._ws.open(this._url),this._ws.queueing.length=0,this._ws.send(i)):(this._fetch&&this._fetch.abort(),this._fetch=new AbortController,fetch(this._url,{method:"POST",body:i,headers:{"Content-Type":s},signal:this._fetch.signal}))}))}}class U extends r{onLog(t){}onError(t="unknown"){console.error(t)}onRelease(){}constructor(t){super(),this._streamer=t,this._lastBytesSend=0,this._lastBytesSendTime=Date.now(),t.once("stop",(()=>this.onRelease()))}serialize(){return t(this,void 0,void 0,(function*(){if(!this._streamer.running)return Promise.reject();const t={streamId:this._streamer.streamName,vbt:this._streamer.videoBitrate,vbc:this._streamer.videoBitrateConstraint},e=this._streamer.mediaReport;let i;e&&(t.server={millis:e.millis,tracks:e.tracks},e.stats&&(t.server.jitterMs=e.stats.jitter_ms,t.server.lossNum=e.stats.loss_num,t.server.lossPerc=e.stats.loss_perc,t.server.nackNum=e.stats.nack_num));try{i=yield this._streamer.connectionInfos()}catch(e){return this.onLog("Report stats without connection infos, "+l.stringify(e)),t}const s=i.candidate;if(s){if(t.sessionId=s.id,t.timestamp=s.timestamp,t.currentRoundTripTime=s.currentRoundTripTime,t.totalRoundTripTime=s.totalRoundTripTime,t.requestsReceived=s.requestsReceived,t.requestsSent=s.requestsSent,t.responsesReceived=s.responsesReceived,t.responsesSent=s.responsesSent,t.bytesSent=s.bytesSent,t.bytesReceived=s.bytesReceived,null==s.availableOutgoingBitrate){const e=t.bytesSent-this._lastBytesSend;this._lastBytesSend=t.bytesSent;const i=Date.now(),r=(i-this._lastBytesSendTime)/1e3;this._lastBytesSendTime=i,s.availableOutgoingBitrate=8*e/r}t.availableOutgoingBitrate=s.availableOutgoingBitrate}const r=i.outputs.audio;r&&(t.audio={bytesSent:r.bytesSent,packetsSent:r.packetsSent,retransmittedBytesSent:r.retransmittedBytesSent,retransmittedPacketsSent:r.retransmittedPacketsSent});const n=i.outputs.audio;return n&&(t.video={bytesSent:n.bytesSent,packetsSent:n.packetsSent,retransmittedBytesSent:n.retransmittedBytesSent,retransmittedPacketsSent:n.retransmittedPacketsSent,firCount:n.firCount,framesEncoded:n.framesEncoded,nackCount:n.nackCount,totalEncodeTime:n.totalEncodeTime,hugeFramesSent:n.hugeFramesSent,framesSent:n.framesSent,frameHeight:n.frameHeight,frameWidth:n.frameWidth}),t}))}}const z="2.0.0";export{O as ABRAbstract,D as ABRGrade,M as ABRLinear,x as HTTPConnector,B as MBRAbstract,L as MBRLinear,p as MType,v as Metadata,E as Player,k as SIPConnector,b as StreamMetadata,A as Streamer,U as StreamerStats,N as Telemetry,z as VERSION,S as WSController,C as WSStreamData,g as utils};//# sourceMappingURL=webrtc-client.min.js.map | ||
function t(t,e,i,s){return new(i||(i=Promise))((function(r,n){function o(t){try{h(s.next(t))}catch(t){n(t)}}function a(t){try{h(s.throw(t))}catch(t){n(t)}}function h(t){var e;t.done?r(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(o,a)}h((s=s.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const e=new TextDecoder;const i=new TextEncoder;function s(t,e,i,s){return new(i||(i=Promise))((function(r,n){function o(t){try{h(s.next(t))}catch(t){n(t)}}function a(t){try{h(s.throw(t))}catch(t){n(t)}}function h(t){var e;t.done?r(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(o,a)}h((s=s.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const r=new TextDecoder,n=new TextEncoder,o=performance;function a(){return Math.floor(o.now())}function h(t,e){e=Object.assign({withType:!1,noEmptyString:!1},e);const i={};if(!t)return i;for(const[s,r]of c(t)){if(t=r,e.withType&&null!=t&&t.substring)if(t){const e=Number(t);if(isNaN(e))switch(t.toLowerCase()){case"true":t=!0;break;case"false":t=!1;break;case"null":t=null;break;case"undefined":t=void 0}else t=e}else e.noEmptyString&&(t=!0);i[s]?(Array.isArray(i[s])||(i[s]=new Array(i[s])),i[s].push(t)):i[s]=t}return i}function c(t){return t.entries?t.entries():Array.from({[Symbol.iterator]:function*(){for(const e in t)yield[e,t[e]]}})}function u(t){const e=t.lastIndexOf(".");return e>=0&&e>t.lastIndexOf("/")?t.substring(e):""}var d,_=Object.freeze({__proto__:null,EMPTY_FUNCTION:()=>{},equal:function(t,e){if(Object(t)!==t)return Object(e)!==e&&t===e;if(t[Symbol.iterator]){if(!e[Symbol.iterator])return!1;if(t.length!==e.length)return!1;for(let i=0;i!==t.length;++i)if(t[i]!==e[i])return!1;return!0}return t===e},fetch:function(t,e){return s(this,void 0,void 0,(function*(){const i=yield self.fetch(t,e);if(i.status>=300){if(i.body)throw(yield i.text())||i.statusText;throw i.statusText}return i}))},objectEntries:c,objectFrom:h,options:function(t=("undefined"==typeof location?void 0:location)){if(!t)return{};try{t=new URL(t).searchParams}catch(e){"string"==typeof t&&(t.startsWith("?")&&(t=t.substring(1)),t=new URLSearchParams(t))}return h(t,{withType:!0,noEmptyString:!0})},parseExtension:u,safePromise:function(t,e){let i;return Promise.race([e instanceof Promise?e:new Promise(e),new Promise(((e,s)=>i=setTimeout((()=>s("timed out in "+t+"ms")),t)))]).finally((()=>clearTimeout(i)))},sleep:function(t){return new Promise((e=>{setTimeout(e,t)}))},stringify:function t(e,i={}){if(i=Object.assign({space:" ",decimal:2,recursion:1,noBin:!1},i),null==e)return String(e);const s=e.error||e.message;if(s&&(e=s),e.toFixed)return e.toFixed(Number(i.decimal)||0);if(null!=e.byteLength&&(null==e?void 0:e[Symbol.iterator]))return i.noBin?"["+e.byteLength+"#bytes]":r.decode(e);if("boolean"==typeof e||e.substring||!i.recursion)return String(e);const n=i.space||"";if(Array.isArray(e)){let s="";for(const r of e)s+=(s?",":"[")+n,s+=t(r,Object.assign(Object.assign({},i),{recursion:i.recursion-1}));return s+=n+"]"}let o="";for(const s in e)o+=(o?",":"{")+n+s+":",o+=t(e[s],Object.assign(Object.assign({},i),{recursion:i.recursion-1}));return o+(n+"}")},time:a,timeOrigin:function(){return Math.floor(o.now()+o.timeOrigin)},toBin:function(t){return n.encode(t)}});class l{onBytes(t){}get delta(){return this._delta}constructor(t=1e3){this._time=a(),this._value=NaN,this._delta=t,this._bytes=0}value(){return Math.round(this.exact())}exact(){const t=a(),e=t-this._time;return(e>this._delta||isNaN(this._value))&&(this._value=1e3*this._bytes/e,this._bytes=0,this._time=t),this._value}addBytes(t){return this._bytes+=t,this.onBytes(t),this}}class m{static fixProtocol(t,e){const i=e.indexOf("://");return i>=0&&(i>2&&"s"===e.charAt(i-1).toLowerCase()?(t.length<=2||!t.endsWith("s"))&&(t+="s"):t.length>2&&t.endsWith("s")&&(t=t.slice(0,-1)),e=e.substring(i+3)),t+"://"+e}get domain(){return this._domain}get port(){return this._port}toString(){return this._address}valueOf(){return this._address}constructor(t,e){this._address=t;let i=t.indexOf("/");if(i>=0&&(47===t.charCodeAt(i+1)?i>0?58===t.charCodeAt(i-1)&&(t=t.substring(i+2)):t=t.substring(2):i||(t=t.substring(1))),this._domain=t,this._port=e,i=t.lastIndexOf(":"),i>=0){const e=parseInt(t.substring(i+1));e&&e<=65535&&(this._port=e,this._domain=t.substring(0,i))}else i=t.indexOf("/"),i>=0&&(this._domain=t.substring(0,i))}}!function(t){t.HESP="HESP",t.WRTS="WebRTS",t.WEBRTC="WebRTC",t.META="Meta",t.DATA="Data"}(d||(d={}));var p=Object.freeze({__proto__:null,get Type(){return d},buildURL:function(t,e,i="wss"){const s=new URL(m.fixProtocol(i,e.endPoint));if(s.pathname.length<=1)switch(t){case d.HESP:s.pathname="/hesp/"+e.streamName+"/index.json";break;case d.WEBRTC:s.pathname="/webrtc/"+e.streamName;break;case d.WRTS:s.pathname="/wrts/"+e.streamName;break;case d.META:s.pathname="/json_"+e.streamName+".js";break;case d.DATA:s.pathname="/"+e.streamName+".json";break;default:console.warn("Unknown url type "+t)}e.accessToken&&s.searchParams.set("id",e.accessToken);for(const t in e.query)s.searchParams.set(t,e.query[t]);return e.streamName.substring(0,e.streamName.length-u(e.streamName).length),s}});class g{constructor(){this._events=new Map;let t=Object.getPrototypeOf(this);for(;t&&t!==Object.prototype;){for(const e of Object.getOwnPropertyNames(t))if(!(e.length<3)&&e.startsWith("on")&&t[e]instanceof Function){const i=new Set;this._events.set(e.substring(2).toLowerCase(),i);let s=t[e];const r=(...t)=>{s&&s.call(this,...t);for(const e of i)e(...t)};Object.defineProperties(this,{[e]:{get:()=>r,set:t=>{s=t}}})}t=Object.getPrototypeOf(t)}}on(t,e,i){if(!e)throw Error("event to subscribe cannot be null");const s=this._event(t);s.add(e),i&&i.signal.addEventListener("abort",(()=>s.delete(e)),{once:!0})}once(t,e,i){if(!e)throw Error("event to subscribe cannot be null");const s=this._event(t);s.add(((...t)=>{s.delete(e),e(...t)})),i&&i.signal.addEventListener("abort",(()=>s.delete(e)),{once:!0})}off(t,e){if(!e)throw Error("event to unsubscribe cannot be null");this._event(t).delete(e)}_event(t){const e=this._events.get(t.toLowerCase());if(!e)throw Error("No event on"+t+" on class "+this.constructor.name);return e}}class f{[Symbol.iterator](){return this._map[Symbol.iterator]()}get size(){return this._map.size}constructor(t){this._initValue=t,this._map=new Map}get(t){let e=this.find(t);return void 0===e&&this._map.set(t,e=this._initValue()),e}find(t){return this._map.get(t)}has(t){return this._map.has(t)}clear(){this._map.clear()}delete(t){return this._map.delete(t)}set(t,e){return this._map.set(t,e),e}forEach(t,e){this._map.forEach(t,e)}}class v{get size(){return this._queue.length}get capacity(){return this._capacity}set capacity(t){this._capacity=t,null!=t&&this._queue.length>t&&this._queue.splice(0,this._queue.length-t)}get front(){return this._queue[0]}get back(){return this._queue[this._queue.length-1]}[Symbol.iterator](){return this._queue[Symbol.iterator]()}constructor(t){this._capacity=t,this._queue=new Array}push(t){return null!=this._capacity&&this._queue.push(t)>this._capacity&&this.pop(),this}pop(){return this._queue.shift()}clear(){return this._queue.length=0,this}}class y extends v{get minimum(){return this._min}get maximum(){return this._max}get average(){return null==this._average&&(this._average=this.size?this._sum/this.size:0),this._average}constructor(t){super(t),this._sum=0,this._min=0,this._max=0}push(t){return t>this._max?this._max=t:t<this._min&&(this._min=t),this._average=void 0,this._sum+=t,super.push(t),this}pop(){const t=super.pop();return t===this._max?this._max=Math.max(0,...this):t===this._min&&(this._min=Math.min(0,...this)),this._average=void 0,this._sum-=t||0,t}clear(){return this._min=this._max=this._sum=0,super.clear(),this}}const b={fromString(t){if(Array.isArray(t))return t;const e=new Array;let i,s=e;for(let r of t.toString().split("\n")){if(r=r.trim(),!r)continue;let t=r[0];const n=r.substring(r.indexOf("=")+1).trim();switch(t.toLowerCase()){case"a":if(!n)continue;t=this.addAttribute(s,n),e===s&&"fingerprint"===t.toLowerCase()&&(i=s.fingerprint);break;case"m":e.length&&i&&!e[e.length-1].fingerprint&&(s.fingerprint=i),e.push(s={m:n});break;default:s[t]=n}}return e.length&&i&&!e[e.length-1].fingerprint&&(s.fingerprint=i),e},toString(t){if("string"==typeof t)return t;const e=[];let i="v"in t?"v="+t.v+"\n":"";"o"in t&&(i+="o="+t.o+"\n"),"s"in t&&(i+="s="+t.s+"\n");const s=t;for(const r of Object.keys(t)){if("v"===r||"o"===r||"s"===r)continue;const t=s[r];if(null==t)continue;const n=parseInt(r);if(!isNaN(n)){e[n]=t;continue}const o=Array.isArray(t)&&t.length||1;for(let e=0;e<o;++e){const s=Array.isArray(t)&&t.length?t[e]:t;r.length>1?(i+="a="+r,s&&(i+=":")):i+=r+"=",i+=s+"\n"}}for(const t of e)i+=this.toString(t);return i},addAttribute(t,e){var i;const s=b.parseAttribute(e),r=null!==(i=s.value)&&void 0!==i?i:"",n=t,o=n[s.key];return o?Array.isArray(o)?o.push(r):r!==o&&(n[s.key]=[o,r]):n[s.key]=r,s.key},removeAttribute(t,e){const i=b.parseAttribute(e),s=t;if(void 0===i.value)return delete s[e],e;const r=s[e];if(Array.isArray(i.value)){const t=r.findIndex((t=>t===i.value));t>=0&&r.splice(t,1)}else r===i.value&&delete s[e];return i.key},parseAttribute(t){const e=t.indexOf(":");return{key:(e>=0?t.substring(0,e):t).trim(),value:e>=0?t.substring(e+1).trim():void 0}}};Object.freeze(b);class w extends g{onOpen(){}onMessage(t){}onClose(t){t&&console.error(t)}get binaryType(){return"arraybuffer"}get recvByteRate(){return this._recvByteRate.value()}get sendByteRate(){return this._sendByteRate.value()}get url(){var t,e;return null!==(e=null===(t=this._ws)||void 0===t?void 0:t.url)&&void 0!==e?e:""}get extensions(){var t,e;return null!==(e=null===(t=this._ws)||void 0===t?void 0:t.extensions)&&void 0!==e?e:""}get protocol(){var t,e;return null!==(e=null===(t=this._ws)||void 0===t?void 0:t.protocol)&&void 0!==e?e:""}get opened(){return this._opened}get readyState(){return this._ws?this._ws.readyState:3}get closed(){return this._closed}get bufferedAmount(){var t;return this._queueingBytes+((null===(t=this._ws)||void 0===t?void 0:t.bufferedAmount)||0)}get queueing(){return this._queueing}constructor(t,e){super(),this._queueing=[],this._queueingBytes=0,this._opened=!1,this._closed=!0,this._recvByteRate=new l,this._sendByteRate=new l,t&&this.open(t,e)}open(t,e){this._closed=!1;const i=this._ws=new WebSocket(t,e);return i.binaryType=this.binaryType,i.onmessage=t=>{var e;this._recvByteRate.addBytes(null!==(e=t.data.byteLength)&&void 0!==e?e:t.data.length),this.onMessage(t.data)},i.onclose=e=>{this._opened?1e3===e.code||1005===e.code?this.close(t.toString()+" shutdown"):this.close(t.toString()+" disconnection, "+String(e.reason||e.code)):this.close(t.toString()+" connection failed, "+String(e.reason||e.code))},i.onopen=t=>{this._opened=!0,this.flush(),this.onOpen()},this}send(t,e=!1){if(this._closed)throw Error("Open socket before to send data");return e||!this._opened?(this._queueing.push(t),this._queueingBytes+="string"==typeof t?t.length:t.byteLength):this._send(t),this}flush(){if(this._ws)for(const t of this._queueing)this._send(t);this._queueing.length=0,this._queueingBytes=0}close(t){this._ws&&!this._closed&&(this._closed=!0,this._ws.onopen=this._ws.onclose=this._ws.onmessage=null,this._ws.close(),this._queueing.length=0,this._queueingBytes=0,this.onClose(t),this._opened=!1)}_send(t){this._ws&&(this._sendByteRate.addBytes("string"==typeof t?t.length:t.byteLength),this._ws.send(t))}}var T,k=Object.freeze({__proto__:null,BinaryReader:class{constructor(t){this._data="buffer"in t?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t),this._size=this._data.byteLength,this._position=0,this._view=new DataView(this._data.buffer,this._data.byteOffset,this._size)}data(){return this._data}size(){return this._size}available(){return this._size-this._position}value(t=this._position){return this._data[t]}position(){return this._position}reset(t=0){this._position=Math.max(0,t>this._size?this._size:t)}shrink(t){const e=this._size-this._position;return t>e?e:(this._size=this._position+t,t)}next(t=1){const e=this._size-this._position;return t>e&&(t=e),this._position=Math.max(0,this._position+t),t}read8(){return 1===this.next(1)?this._view.getUint8(this._position-1):0}read16(){return 2===this.next(2)?this._view.getUint16(this._position-2):0}read24(){return 3===this.next(3)?this._view.getUint16(this._position-3)<<8|255&this._view.getUint8(this._position-1):0}read32(){return 4===this.next(4)?this._view.getUint32(this._position-4):0}read64(){return 8!==this.next(8)?0:4294967296*this._view.getUint32(this._position-8)+this._view.getUint32(this._position-4)}readFloat(){return 4===this.next(4)?this._view.getFloat32(this._position-4):0}readDouble(){return 8===this.next(8)?this._view.getFloat64(this._position-8):0}read7Bit(t=5){let e=0,i=1;for(;this.available();){const t=this.read8();if(e+=(127&t)*i,!(128&t))break;i*=128}return e}readString(){let t=this._position;for(;t<this._size&&this._data[t];)++t;const i=this.read(t-this._position);return this.next(),e.decode(i)}readHex(t){let e="";for(;t-- >0;)e+=("0"+this.read8().toString(16)).slice(-2);return e}read(t=this.available()){if(this.available()<t)return new Uint8Array(t);const e=this._position;return this._data.subarray(e,Math.max(e,this._position+=t))}},BinaryWriter:class{get view(){return this._view||(this._view=new DataView(this._data.buffer,this._data.byteOffset,this._data.byteLength)),this._view}get capacity(){return this._data.byteLength}constructor(t=64,e=0,i){"number"==typeof t?(this._data=new Uint8Array(t),this._size=0):"buffer"in t?(this._data=new Uint8Array(t.buffer,t.byteOffset,t.byteLength),this._size=t.byteLength):(this._isConst=!0,null==i&&(i=t.byteLength),this._data=new Uint8Array(t,e,i),this._size=0)}data(){return new Uint8Array(this._data.buffer,this._data.byteOffset,this._size)}size(){return this._size||0}next(t=1){return this.reserve(this._size+=t)}clear(t=0){return this.reserve(this._size=t)}write(t){return this.reserve(this._size+t.length),this._data.set(t,this._size),this._size+=t.length,this}write8(t){return t>255&&(t=255),this.reserve(this._size+1),this._data[this._size++]=t,this}write16(t){return t>65535&&(t=65535),this.reserve(this._size+2),this.view.setUint16(this._size,t),this._size+=2,this}write24(t){return t>16777215&&(t=16777215),this.reserve(this._size+3),this.view.setUint16(this._size,t>>8),this.view.setUint8(this._size+=2,255&t),++this._size,this}write32(t){return t>4294967295&&(t=4294967295),this.reserve(this._size+4),this.view.setUint32(this._size,t),this._size+=4,this}write64(t){return this.write32(t/4294967296),this.write32(4294967295&t)}writeFloat(t){return this.reserve(this._size+4),this.view.setFloat32(this._size,t),this._size+=4,this}writeDouble(t){return this.reserve(this._size+8),this.view.setFloat64(this._size,t),this._size+=8,this}write7Bit(t){let e=127&t;for(;t=Math.floor(t/128);)this.write8(128|e),e=127&t;return this.write8(e)}writeString(t){return this.write(i.encode(t)).write8(0)}writeHex(t){for(let e=0;e<t.length;e+=2)this.write8(parseInt(t.substring(e,e+2),16));return this}reserve(t){if(!this._data)throw Error("buffer not writable");if(t<=this._data.byteLength)return this;if(this._isConst)throw Error("writing exceeds maximum "+this._data.byteLength+" bytes limit");--t,t|=t>>1,t|=t>>2,t|=t>>4,t|=t>>8,t|=t>>16,++t;const e=new Uint8Array(t);return e.set(this._data),this._data=e,this._view=void 0,this}},BitReader:class{constructor(t){this._data="buffer"in t?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t),this._size=this._data.byteLength,this._position=0,this._bit=0}data(){return this._data}size(){return this._size}available(){return 8*(this._size-this._position)-this._bit}next(t=1){let e=0;for(;this._position!==this._size&&t--;)++e,8==++this._bit&&(this._bit=0,++this._position);return e}read(t=1){let e=0;for(;this._position!==this._size&&t--;)e<<=1,this._data[this._position]&128>>this._bit++&&(e|=1),8===this._bit&&(this._bit=0,++this._position);return e}read8(){return this.read(8)}read16(){return this.read(16)}read24(){return this.read(24)}read32(){return this.read(32)}readExpGolomb(){let t=0;for(;!this.read();){if(!this.available())return 0;++t}const e=this.read(t);return t>15?(console.warn("Exponential-Golomb code exceeding unsigned 16 bits"),0):e+(1<<t)-1}},ByteRate:l,Connect:p,EventEmitter:g,FixMap:f,NetAddress:m,Numbers:y,Queue:v,SDP:b,Util:_,VERSION:"2.2.0",WebSocketReliable:w});function x(t,e,i){for(let s=0;s<e.length;++s){const r=e[s];i.has(r.codec.toLowerCase())||(t.delete(r.idx),e.splice(s--,1))}}!function(t){t.AUDIO="audio",t.VIDEO="video",t.DATA="data"}(T||(T={}));class S{constructor(){this.type="",this.width=0,this.height=0,this.sources=new Map,this.tracks=new Map,this.audios=[],this.videos=[],this.datas=[]}subset(t){const e=Object.assign({},this);if(t){x(e.tracks,e.audios,t),x(e.tracks,e.videos,t);for(const[,t]of e.tracks){for(;t.up&&!e.tracks.has(t.up.idx);)t.up=t.up.up;for(;t.down&&!e.tracks.has(t.down.idx);)t.down=t.down.down}}return e}}const C=(t,e)=>e.maxbps-t.maxbps;class B extends g{onLog(t){}onError(t="unknown"){console.error(t)}onClose(){this.onLog("onClose")}onMetadata(t){this.onLog(_.stringify(t))}get url(){return this._ws.url}get connectParams(){return this._connectParams}get metadata(){return this._metadata}get closed(){return this._ws.closed}constructor(t){super(),this._connectParams=t,this._ws=new w(p.buildURL(p.Type.META,t)),this._ws.onClose=t=>{this._metadata=new S,t&&this.onError(t),this.onClose()},this._ws.onMessage=t=>{try{const e=JSON.parse(t);if(e.error)throw e.error;this._metadata=new S,this._metadata.type=e.type,this._metadata.width=e.width,this._metadata.height=e.height,this._metadata.sources.clear();for(const t of e.source)this._metadata.sources.set(t.hrn,t);const i=[];this._metadata.tracks.clear();for(const[t,s]of _.objectEntries(e.meta.tracks)){switch(s.name=t,s.type=s.type.toLowerCase(),s.type){case"audio":this._metadata.audios.push(s);continue;case"video":this._metadata.videos.push(s);continue;case"meta":s.type=T.DATA,this._metadata.datas.push(s);break;default:this.onLog("Unknown track type"+s.type)}i.push(s)}this._addSortedTrack(this._metadata.audios,this._metadata.tracks),this._addSortedTrack(this._metadata.videos,this._metadata.tracks);for(const t of i)this._metadata.tracks.set(t.idx,t)}catch(t){return void this.onError(_.stringify(t))}this.onMetadata(this._metadata)}}close(t){this._ws.close(t)}_addSortedTrack(t,e){t.sort(C);for(let i=0;i<t.length;++i){const s=t[i];e.set(s.idx,s),i&&(s.up=t[i-1],t[i-1].down=s)}}}function R(t){return"send"in t}const L=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);class O extends g{onLog(t){}onError(t="unknown"){console.error(t)}onOpen(t){this.onLog("onOpen")}onClose(){this.onLog("onClose")}get opened(){return!(!this._peerConnection||this._peerConnection.ontrack!==_.EMPTY_FUNCTION)}get closed(){return this._closed}get stream(){return this._stream}get streamName(){return this._streamName}get codecs(){return this._codecs}constructor(t,e){super(),this._closed=!1,this._streamName=t.streamName,this._endPoint=t.endPoint,this._stream=e,this._connectionInfosTime=0,this._codecs=new Set}connectionInfos(e=1e3){return t(this,void 0,void 0,(function*(){if(!this._peerConnection)return Promise.reject("Not connected");if(!this._connectionInfos||_.time()-e>this._connectionInfosTime){const t=yield this._peerConnection.getStats(null);this._connectionInfos={inputs:{},outputs:{}};const e=new Map,i=new Map;for(const s of t.values())switch(s.type){case"track":e.set(s.id,s);break;case"outbound-rtp":i.set(s.trackId,s),this._connectionInfos.outputs["audio"===(s.kind||s.mediaType)?"audio":"video"]=s;break;case"inbound-rtp":i.set(s.trackId,s),this._connectionInfos.inputs["audio"===(s.kind||s.mediaType)?"audio":"video"]=s;break;case"candidate-pair":if(null!=s.selected){if(!s.selected)continue}else if(null!=s.nominated&&!s.nominated)continue;this._connectionInfos.candidate=s}for(const[t,s]of e){const e=i.get(t);e&&Object.assign(e,Object.assign(Object.assign({},s),e))}this._connectionInfosTime=_.time()}return this._connectionInfos}))}close(t){if(this._closed)return;this._closed=!0;const e=this._peerConnection;e&&(this._peerConnection=void 0,e.getReceivers().forEach((t=>t.track&&t.track.stop())),e.getSenders().forEach((t=>t.track&&t.track.stop())),e.close()),this._stream&&this._stream.getTracks().forEach((t=>t.stop())),t&&this.onError(t),this.onClose()}_open(t){if(!t){const e=new m(this._endPoint,443).domain;t={urls:["turn:"+e+":3478?transport=tcp","turn:"+e+":3478"],username:"csc_demo",credential:"UtrAFClFFO"}}try{this._peerConnection=new RTCPeerConnection({iceServers:[t]})}catch(t){return void this.close("RTCPeerConnection failed, "+_.stringify(t))}if(this._stream)for(const t of this._stream.getTracks())this._peerConnection.addTrack(t);else this._peerConnection.ontrack=t=>{this._stream=t.streams[0],this._tryToOpen()};if(L)if(this._stream){const t=this._peerConnection.getTransceivers();for(const e of t)"audio"!==e.receiver.track.kind&&"video"!==e.receiver.track.kind||(e.direction="sendonly")}else this._peerConnection.addTransceiver("audio",{direction:"recvonly"}),this._peerConnection.addTransceiver("video",{direction:"recvonly"});let e;this._peerConnection.createOffer({offerToReceiveAudio:!this._stream,offerToReceiveVideo:!this._stream}).then((t=>{var i;if(this._peerConnection)return e=null!==(i=t.sdp)&&void 0!==i?i:"",this.onLog("Offer\r\n"+e),this._peerConnection.setLocalDescription(t)})).then((t=>{if(this._peerConnection)return e?this._sip(e):Promise.reject("invalid empty sdp offer")})).then((t=>{if(t&&this._peerConnection){this.onLog("Answer\r\n"+t);for(const e of b.fromString(t)){if(!e.rtpmap)continue;let t=e.rtpmap.indexOf(" ");if(t<0)continue;let i=e.rtpmap.substring(t+1);if(!i)return;t=i.indexOf("/"),i=t<0?i:i.substring(0,t),this._codecs.add(i.toLowerCase())}return this._peerConnection.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:t}))}})).then((()=>this._tryToOpen())).catch((t=>this.close("SIP failed, "+_.stringify(t))))}_tryToOpen(){this._stream&&this._peerConnection&&this._peerConnection.ontrack!==_.EMPTY_FUNCTION&&(this._peerConnection.ontrack=_.EMPTY_FUNCTION,this.onOpen(this._stream))}}class E extends O{onRTPProps(t){this.onLog("onRTPProps "+_.stringify(t))}onMediaReport(t){console.debug("onMediaReport "+_.stringify(t))}onVideoBitrate(t,e){this.onLog("onVideoBitrate "+_.stringify({video_bitrate:t,video_bitrate_constraint:e}))}onPlaying(t){console.debug("onPlaying "+_.stringify(t))}constructor(t,e){super(t,e),this._ws=new w(p.buildURL(p.Type.WEBRTC,t,"wss")),this._ws.onClose=t=>this.close(t),this._ws.onOpen=()=>{this._open(t.iceServer)},this._ws.onMessage=t=>{try{this._eventHandler(JSON.parse(t))}catch(t){this.onError("Invalid signaling message, "+_.stringify(t))}}}setRTPProps(t,e){this.send("rtp_props",{nack:t,drop:e})}setVideoBitrate(t){this.send("video_bitrate",{video_bitrate:t})}setTracks(t){this.send("tracks",t)}send(t,e){try{this.onLog("Command "+t+" "+_.stringify(e)),this._ws.send(JSON.stringify(Object.assign({type:t},e)))}catch(t){this.onError(_.stringify(t))}}close(t){this._ws.close(t),this._promise&&(this._promise(Error("closing")),this._promise=void 0),super.close(t)}_sip(t){return new Promise(((e,i)=>{this._promise=t=>{t instanceof Error?i(t):e(t)},this._ws.send(JSON.stringify({type:"offer_sdp",offer_sdp:t}))}))}_eventHandler(t){var e,i;switch(t.type){case"on_answer_sdp":this._promise&&this._promise(t.answer_sdp);break;case"on_error":this.opened?this.onError(_.stringify(t)):this.close(_.stringify(t));break;case"on_video_bitrate":this.onVideoBitrate(t.video_bitrate,t.video_bitrate_constraint);break;case"on_stop":this.onLog("on_stop"),this.close();break;case"on_track_drop":{const s=null!==(e=t.mediatype)&&void 0!==e?e:"?",r=null!==(i=t.track)&&void 0!==i?i:"?";this.onError(s+" track #"+r+"dropped");break}case"on_rtp_props":this.onRTPProps(t);break;case"on_media_receive":this.onMediaReport(t);break;case"on_seek":break;case"on_time":this.onPlaying(t);break;default:this.onError("Unhandled event: "+t.type)}}}class P extends O{constructor(t,e){super(t,e),this._url=p.buildURL(p.Type.WEBRTC,t,"https"),this._fetch=new AbortController,setTimeout((()=>{this._open(t.iceServer)}),0)}close(t){this._fetch.abort(),super.close(t)}_sip(e){return t(this,void 0,void 0,(function*(){const t=yield fetch(this._url,{method:"POST",body:e,headers:{"Content-Type":"application/sdp"},signal:this._fetch.signal});return t?t.text():Promise.reject("client rejected")}))}}class M extends g{onLog(t){}onError(t="unknown"){console.error(t)}onClose(){this.onLog("onClose")}onData(t,e,i){this.onLog(`Data received on track ${e} at ${t} : ${_.stringify(i)}`)}get url(){return this._url}get tracks(){return[...this._tracks]}set tracks(t){this._tracks=[...t],this._sendTracks()}get closed(){return!this._ws||this._ws.closed}constructor(t){super(),this._url=p.buildURL(p.Type.DATA,t).toString(),this._tracks=Array(),this._ws=new w,this._ws.onOpen=()=>this._sendTracks(),this._ws.onClose=t=>{t&&this.onError(t),this.onClose()},this._ws.onMessage=t=>{let e;try{e=JSON.parse(t)}catch(t){return this.onError("Invalid signaling message, "+_.stringify(t))}if(e.error)return this.onError(e.error);"time"in e&&"track"in e&&"data"in e?this.onData(e.track,e.time,e.data):"on_time"!==e.type&&console.debug("Internal JSON : ",_.stringify(e))}}close(t){this._ws.close(t)}_sendTracks(){this._tracks.length?this._ws.closed?this._ws.open(this._url):this._ws.opened&&this._ws.send(JSON.stringify({type:"tracks",tracks:this._tracks.join(",")})):this.close()}}class A{onLog(t){}onError(t="unknown"){console.error(t)}get upDelay(){return this._upDelay}get learningUpStep(){return this._learningUpStep}get maximumUpDelay(){return this._maximumUpDelay}constructor(t){const e=Object.assign({learningUpStep:1400,maximumUpDelay:28e3},t);this._learningUpStep=e.learningUpStep,this._maximumUpDelay=e.maximumUpDelay,this._upDelay=0,this._testTime=0}reset(){this._upDelay=0,this._mTrack=void 0}compute(t,e,i){var s;const r=null!==(s=e.video)&&void 0!==s?s:e.audio;if(null==r)return this._mTrack=void 0,!1;const n=_.time();if(!(this._mTrack&&this._mTrack.idx===r||(this._appreciationTime=void 0,this._testTime=n,this._mTrack=t.tracks.get(r),this._mTrack)))return this.onError("Can't find track "+r+" absent from metadata"),!1;const o=r===e.video?i.video:i.audio;if(!o)return this.onError("Can't compute "+this._mTrack.type+" track "+this._mTrack.idx+" without statistics"),!1;const a=this._downBitrate(n-this._testTime,this._mTrack,o);if(a)this._appreciationTime=void 0;else{this._appreciationTime||(this._appreciationTime=n);const t=n-this._appreciationTime;if(!this._upBitrate(t,this._mTrack,o)||t<this._upDelay)return!1}let h=this.updateTrack(e.audio,t,a);if(h)e.audio=h.idx;else{if(h=this.updateTrack(e.video,t,a),!h)return!1;e.video=h.idx}return a&&(this._upDelay=Math.min(this._upDelay+this._learningUpStep,this._maximumUpDelay)),this.onLog((a?"DOWN":"UP")+" from "+this._mTrack.type+" track "+this._mTrack.idx+" ("+this._mTrack.maxbps+"bps) to "+h.type+" track "+h.idx+" ("+h.maxbps+"bps)"),!0}updateTrack(t,e,i){if(null==t)return;const s=i?"down":"up",r=e.tracks.get(t);if(r)return r[s];this.onError("Can't find track "+t+" from metadata")}}class N extends A{constructor(t){super(t),this._keyFramesDecoded=0,this._lost=0,this._nackCount=0}_downBitrate(t,e,i){const s=i.packetsLost,r=i.nackCount;if(null==s)return this.onLog("No packetsLost information in "+_.stringify(i)),!1;const n=t>0&&s>this._lost&&(!r||r>this._nackCount);return this._lost=s,this._nackCount=r||0,n}_upBitrate(t,e,i){if(e.type===T.AUDIO)return!0;if(t>1e4)return!0;const s=i.keyFramesDecoded;if(null==s)return!1;if(t){if(s>this._keyFramesDecoded){if(!this._keyFramesDecoded)return!0;this._keyFramesDecoded=0}}else this._keyFramesDecoded=s;return!1}}const I=1e3;class D extends g{onLog(t){}onError(t="unknown"){console.error(t)}onStart(t){this.onLog("onStart")}onStop(){this.onLog("onStop")}onPlaying(t){console.debug("onPlaying "+_.stringify(t))}onMetadata(t){this.onLog(_.stringify(t))}onData(t,e,i){this.onLog(`Data received on track ${e} at ${t} : ${_.stringify(i)}`)}get streamName(){return this._connector?this._connector.streamName:""}get stream(){return this._connector&&this._connector.stream}get running(){return!!this._connector}get controller(){return this._controller}get connector(){return this._connector}get metadata(){return this._metadata}get playingInfos(){return this._playingInfos}get audioTrack(){return this._audioTrack}set audioTrack(t){if(this._audioTrackFixed=null!=t,this._audioTrackFixed&&this._audioTrack!==t&&(this._audioTrack=t,this._connector)){if(!this._controller)throw Error("Cannot set audioTrack without start a controllable session");this._controller.setTracks({audio:t})}}get videoTrack(){return this._videoTrack}set videoTrack(t){if(this._videoTrackFixed=null!=t,this._videoTrackFixed&&this._videoTrack!==t&&(this._videoTrack=t,this._connector)){if(!this._controller)throw Error("Cannot set videoTrack without start a controllable session");this._controller.setTracks({video:t})}}get dataTracks(){return[...this._dataTracks]}set dataTracks(t){this._dataTracks=[...t],this._streamData&&(this._streamData.tracks=t)}constructor(t){super(),this.Connector=t,this._dataTracks=new Array}connectionInfos(){return this._connector?this._connector.connectionInfos():Promise.reject("Start player before to request connection infos")}start(e,i={}){let s,r,n;this.stop(),"connectParams"in e?(this._initStreamMetadata(Object.assign({},e.connectParams),e),e=e.connectParams):this._initStreamMetadata(Object.assign({},e),new B(e)),null!=this._audioTrack&&(e.query=Object.assign({audio:this._audioTrack.toFixed()},e.query)),null!=this._videoTrack&&(e.query=Object.assign({video:this._videoTrack.toFixed()},e.query)),this._audioTrackFixed=!1,this._videoTrackFixed=!1,this._connector=new(this.Connector||(e.endPoint.startsWith("http")?P:E))(e),this._connector.onLog=t=>this.onLog("Signaling: "+t),this._connector.onError=t=>this.onError("Signaling: "+t),this._connector.onOpen=t=>{var e,i;this.onStart(t),(null===(e=this._streamMetadata)||void 0===e?void 0:e.metadata)&&this._streamMetadata.onMetadata(null===(i=this._streamMetadata)||void 0===i?void 0:i.metadata),r&&this._controller&&this._controller.onPlaying(r)},this._connector.onClose=()=>{null==s||s.reset(),this.stop()},this._newStreamData(Object.assign({},e)),R(this._connector)?(i&&("compute"in i?s=i:(s=new N(i),s.onLog=t=>this.onLog("MultiBitrate: "+t))),this._controller=this._connector,this._controller.onPlaying=e=>t(this,void 0,void 0,(function*(){if(r=e,this._controller&&this._controller.opened&&(this._playingInfos=r,this._updateTracks(),this.onPlaying(r),s))if(this._audioTrackFixed&&this._videoTrackFixed)s.reset();else try{const t=yield this._controller.connectionInfos(1e3);if(t===n)return;const e={audio:this._audioTrackFixed?void 0:this._audioTrack,video:this._videoTrackFixed?void 0:this._videoTrack};this._controller&&this._metadata&&s.compute(this._metadata,e,(n=t).inputs)&&(this._audioTrack=e.audio,this._videoTrack=e.video,this._controller.setTracks(e))}catch(t){this.onError("Can't compute MBR, "+_.stringify(t))}}))):i&&this.onLog("Cannot use a multiple bitrate without a controller: Connector "+this._connector.constructor.name+" doesn't implements IController")}stop(){const t=this._connector;t&&(this._connector=void 0,this._streamMetadata&&(this._streamMetadata.close(),this._streamMetadata=void 0),this._streamData&&(this._streamData.close(),this._streamData=void 0),t.close(),this._audioTrack=void 0,this._videoTrack=void 0,this._dataTracks.length=0,this._playingInfos=void 0,this._metadata=void 0,this.onStop())}_updateTracks(){if(!this._playingInfos||!this._metadata)return;const t=new Array,e=new Array;for(const i of this._playingInfos.tracks){const s=this._metadata.tracks.get(i);s&&(s.type===T.AUDIO?t.push(i):s.type===T.VIDEO&&e.push(i))}1===t.length&&(this._audioTrack=t[0]),1===e.length&&(this._videoTrack=e[0])}_initStreamMetadata(t,e){this._streamMetadata=e,e.onLog=t=>this.onLog("StreamMetadata: "+t),e.onError=t=>this.onError("StreamMetadata: "+t),e.onMetadata=t=>{this._connector&&this._connector.opened&&(this._metadata=t.subset(this._connector.codecs),this._updateTracks(),this.onMetadata(this._metadata))},e.onClose=()=>{this.onLog("StreamMetadata closed, trying to reconnect in 1000ms"),setTimeout((()=>{this._streamMetadata===e&&this._initStreamMetadata(t,new B(t))}),I)}}_newStreamData(t){const e=this._streamData=new M(t);e.onLog=t=>this.onLog("Timed Metadatas: "+t),e.onError=t=>this.onError("Timed Metadatas: "+t),e.onData=(t,e,i)=>this.onData(e,t,i),e.tracks=this._dataTracks,e.onClose=()=>{this.onLog("Timed Metadatas closed, trying to reconnect in 1000ms"),setTimeout((()=>{this._streamData===e&&this._newStreamData(t)}),I)}}}class U extends g{onLog(t){}onError(t="unknown"){console.error(t)}get startup(){return this._startup}set startup(t){this._startup=Math.max(this._minimum,Math.min(Math.round(t),this._maximum))}get minimum(){return this._minimum}set minimum(t){t=Math.round(t),(this._minimum=t)>this._maximum?this._maximum=this._startup=t:this._startup<t&&(this._startup=t)}get maximum(){return this._maximum}set maximum(t){t=Math.round(t),(this._maximum=t)<this._minimum?this._minimum=this._startup=t:this._startup>t&&(this._startup=t)}get constraint(){return this._bitrateConstraint}get value(){return this._bitrate}valueOf(){return this.value}get stream(){return this._stream}constructor(t,e){super();const i=Object.assign({startup:2e6,maximum:3e6,minimum:2e5},t);this._startup=i.startup,this._minimum=i.minimum,this._maximum=i.maximum,this._stream=e}compute(t,e,i){if(null==t)return this._bitrate=t;const s=null==this._bitrate,r=s?this.startup:Math.max(this.minimum,Math.min(this._computeBitrate(t,e,i),this.maximum));return this._bitrate=t,this._bitrateConstraint=e,s?this.onLog("Set startup bitrate to "+r):r>t?this.onLog("Increase bitrate "+t+" => "+r):r<t&&this.onLog("Decrease bitrate "+t+" => "+r),r}reset(){this._bitrate=this._bitrateConstraint=void 0}_updateVideoConstraints(t){const e=this._stream;if(!e)return;const i=e.getVideoTracks()[0];if(!i)return;const s=i.getSettings();if(!s.width||!s.height)return;const r=s.width*s.height;t>=12e5?r<645120&&this._upgradeVideoConstraint(i,2):r>645120&&r<1198080&&this._upgradeVideoConstraint(i,.5)}_upgradeVideoConstraint(t,e){const i={},s=t.getSettings().width;null!=s&&(i.width=s*e);const r=t.getSettings().height;null!=r&&(i.height=r*e),this.onLog("Resolution change "+s+"X"+r+" => "+i.width+"X"+i.height),t.applyConstraints(i)}}let z=class{constructor(){this.stableTime=0,this.stableBitrate=0,this.attempts=1,this.lastLoss=Number.POSITIVE_INFINITY}};class j extends U{constructor(t,e){super(t,e),this._vars=new z}reset(){super.reset(),this._vars=new z}_computeBitrate(t,e,i){const s=i&&i.stats,r=this._vars;if(s&&s.loss_perc)s.loss_perc>=r.lastLoss&&(r.stableTime&&++r.attempts,r.stableTime=0,t=Math.round((1-s.loss_perc/100)*t)),r.lastLoss=s.loss_perc;else{r.lastLoss=Number.POSITIVE_INFINITY;const e=_.time();e>=r.stableTime&&(r.stableTime?(this._updateVideoConstraints(t),t+=Math.ceil((this.maximum-r.stableBitrate)/r.attempts)):r.stableBitrate=t,r.stableTime=e+11)}return t}}class F extends g{onLog(t){}onError(t="unknown"){console.error(t)}onStart(t){this.onLog("onStart")}onStop(){this.onLog("onStop")}onRTPProps(t){this.onLog("onRTPProps "+_.stringify(t))}onMediaReport(t){console.debug("onMediaReport "+_.stringify(t))}onVideoBitrate(t,e){this.onLog("onVideoBitrate "+_.stringify({videoBitrate:t,videoBitrateConstraint:e}))}get streamName(){return this._connector?this._connector.streamName:""}get stream(){return this._connector&&this._connector.stream}get running(){return!!this._connector}get controller(){return this._controller}get connector(){return this._connector}get mediaReport(){return this._mediaReport}get rtpProps(){return this._rtpProps}get videoBitrate(){return this._videoBitrate}set videoBitrate(t){if(!this._controller)throw Error("Cannot set videoBitrate without start a controllable session");this._videoBitrateFixed=null!=t,this._videoBitrateFixed&&t!==this._videoBitrate&&this._controller.setVideoBitrate(t)}get videoBitrateConstraint(){return this._videoBitrateConstraint}constructor(t){super(),this.Connector=t,this._videoBitrate=0,this._videoBitrateConstraint=0}setRTPProps(t,e){if(!this._controller)throw Error("Cannot set rtpProps without start a controllable session");this._controller.setRTPProps(t,e)}connectionInfos(){return this._connector?this._connector.connectionInfos():Promise.reject("Start streamer before to request connection infos")}start(e,i,s={}){let r;this.stop(),this._videoBitrateFixed=!1,this._connector=new(this.Connector||(i.endPoint.startsWith("http")?P:E))(i,e),this._connector.onLog=t=>this.onLog("Signaling: "+t),this._connector.onError=t=>this.onError("Signaling: "+t),this._connector.onOpen=t=>this.onStart(t),this._connector.onClose=()=>{null==r||r.reset(),this.stop()},R(this._connector)?(s&&("compute"in s?r=s:(r=new j(s),r.onLog=t=>this.onLog("AdaptiveBitrate: "+t))),this._controller=this._connector,this._controller.onOpen=t=>{this._computeVideoBitrate(r),this.onStart(t)},this._controller.onRTPProps=t=>{this._rtpProps=t,this.onRTPProps(t)},this._controller.onMediaReport=e=>t(this,void 0,void 0,(function*(){this._mediaReport=e,this._computeVideoBitrate(r),this.onMediaReport(e)})),this._controller.onVideoBitrate=(t,e)=>{this._videoBitrate=t,this._videoBitrateConstraint=e,this.onVideoBitrate(t,e)}):s&&this.onLog("Cannot use an adaptive bitrate without a controller: Connector "+this._connector.constructor.name+" doesn't implements IController")}stop(){const t=this._connector;t&&(this._connector=void 0,t.close(),this._controller=void 0,this._mediaReport=void 0,this._videoBitrate=0,this._videoBitrateConstraint=0,this._rtpProps=void 0,this.onStop())}_computeVideoBitrate(t){var e;if(!this._controller||this._videoBitrateFixed)return;const i=null!==(e=t.compute(this._videoBitrate,this.videoBitrateConstraint,this.mediaReport))&&void 0!==e?e:this._videoBitrate;i!==this._videoBitrate&&this._controller.setVideoBitrate(i)}}class q{constructor(){this.lossPercents=new y(5),this.stableBitrates=new y(15),this.stableBitrateUpdateTime=0,this.bitrateRecoveryTimeout=1e4,this.bitrateRecoveryNextTime=0}}class V extends U{constructor(t,e){super(t,e),this._vars=new q}reset(){super.reset(),this._vars=new q}_computeBitrate(t,e,i){var s;const r=this._vars,n=i&&i.stats;n&&null!=n.loss_perc&&r.lossPercents.push(n.loss_perc);const o=_.time();o>=r.stableBitrateUpdateTime&&r.lossPercents.average<.2&&(r.stableBitrateUpdateTime=o+4e3,r.stableBitrates.push(Math.min(null!==(s=null!=e?e:this.constraint)&&void 0!==s?s:0,t,this.maximum)));const a=r.stableBitrates.average,h=r.stableBitrates.minimum,c=r.stableBitrates.maximum;if(h>=.8*a&&c<=1.2*a&&this._updateVideoConstraints(a),null!=e&&null!=this.constraint&&e<this.constraint){if(this.onLog(`onVideoBitrateConstraint: ${this._formatBitrate(e-this.constraint)}`),r.bitrateConstraintTime){if(r.bitrateRecoveryTime){(o-r.bitrateRecoveryTime<r.bitrateRecoveryTimeout||2500===r.bitrateRecoveryTimeout)&&(this._increaseRecoveryTimeout(),r.bitrateRecoveryTime=void 0)}}else r.bitrateRecoveryTime||(this.onLog("VideoBitrateConstraint: First constrain! Halve bitrate!"),t=Math.round(t/2));r.bitrateConstraintTime=o}if(e&&(e<this.minimum&&(t=this.minimum),this.maximum>e&&o>=r.bitrateRecoveryNextTime)){const i=r.bitrateRecoveryNextTime&&this._bitrateRecoveryHandler(e);i?(r.bitrateRecoveryTimeout=o,r.bitrateRecoveryNextTime=0,t=i):(r.bitrateRecoveryNextTime=o+r.bitrateRecoveryTimeout,this.onLog("startVideoBitrateRecoveryTimer "+r.bitrateRecoveryTimeout))}return t}_bitrateRecoveryHandler(t){const e=this._vars,i=e.lossPercents.average;if(this.onLog("videoBitrateRecoveryHandler loss: "+i.toFixed(2)),i<.2){let i=this._increaseTargetBitrate(t);return e.bitrateConstraintTime&&i>e.stableBitrates.average&&(i=this._increaseTargetBitrate(t,1.005)),this._decreaseRecoveryTimeout(),this.onLog("videoBitrateRecoveryHandler increase bitrate to "+this._formatBitrate(i)),i}if(i<5){this._increaseRecoveryTimeout();const e=this._decreaseTargetBitrate(t);return this.onLog("videoBitrateRecoveryHandler decrease bitrate to "+this._formatBitrate(e)),e}}_increaseTargetBitrate(t,e=1.05){let i=Math.round(t*e);return i>this.maximum&&(i=this.maximum),i}_decreaseTargetBitrate(t){let e=Math.round(.99*t);return e<this.minimum&&(e=this.minimum),e}_increaseRecoveryTimeout(){this._vars.bitrateRecoveryTimeout=Math.min(6e4,2*this._vars.bitrateRecoveryTimeout)}_decreaseRecoveryTimeout(){this._vars.bitrateRecoveryTimeout=Math.max(2500,Math.round(.75*this._vars.bitrateRecoveryTimeout))}_formatBitrate(t){return(t/1e6).toFixed(3)}}class W extends g{onLog(t){}onError(t="unknown"){console.error(t)}get url(){return this._url}get reporting(){return this._reporting}constructor(t){if(super(),(t=new URL(t)).protocol.startsWith("ws"))this._ws=new w;else if(!t.protocol.startsWith("http"))throw Error("Protocol "+t.protocol+" not supported");this._url=t.toString(),this._reporting=0}report(e,i){e.onError=t=>this.onError(e.constructor.name+" error, "+t),e.onLog=t=>this.onError(e.constructor.name+", "+t);let s=e.onRelease=()=>{s&&(s=void 0,clearInterval(r),this.onLog("Stop "+e.constructor.name+" reporting"),--this._reporting>0||(this._ws&&this._ws.close(),this._fetch&&this._fetch.abort()))};const r=(i?setInterval:setTimeout)((()=>t(this,void 0,void 0,(function*(){!i&&s&&s();try{yield this._send(e)}catch(t){this.onError(e.constructor.name+" error, "+_.stringify(t))}}))),1e3*i);++this._reporting,this.onLog("Start "+e.constructor.name+" reporting every "+i+" seconds")}_send(e){return t(this,void 0,void 0,(function*(){let t,i,s;try{t=yield e.serialize()}catch(t){if(!t)return;throw t}t instanceof ArrayBuffer?(s="application/octet-stream",i=t):"string"==typeof t?(s="text/plain",i=t):(s="application/json",i=JSON.stringify(t)),this._ws?(this._ws.closed&&this._ws.open(this._url),this._ws.queueing.length=0,this._ws.send(i)):(this._fetch&&this._fetch.abort(),this._fetch=new AbortController,fetch(this._url,{method:"POST",body:i,headers:{"Content-Type":s},signal:this._fetch.signal}))}))}}class H extends g{onLog(t){}onError(t="unknown"){console.error(t)}onRelease(){}constructor(t){super(),this._streamer=t,this._lastBytesSend=0,this._lastBytesSendTime=Date.now(),t.once("stop",(()=>this.onRelease()))}serialize(){return t(this,void 0,void 0,(function*(){if(!this._streamer.running)return Promise.reject();const t={streamId:this._streamer.streamName,vbt:this._streamer.videoBitrate,vbc:this._streamer.videoBitrateConstraint},e=this._streamer.mediaReport;let i;e&&(t.server={millis:e.millis,tracks:e.tracks},e.stats&&(t.server.jitterMs=e.stats.jitter_ms,t.server.lossNum=e.stats.loss_num,t.server.lossPerc=e.stats.loss_perc,t.server.nackNum=e.stats.nack_num));try{i=yield this._streamer.connectionInfos()}catch(e){return this.onLog("Report stats without connection infos, "+_.stringify(e)),t}const s=i.candidate;if(s){if(t.sessionId=s.id,t.timestamp=s.timestamp,t.currentRoundTripTime=s.currentRoundTripTime,t.totalRoundTripTime=s.totalRoundTripTime,t.requestsReceived=s.requestsReceived,t.requestsSent=s.requestsSent,t.responsesReceived=s.responsesReceived,t.responsesSent=s.responsesSent,t.bytesSent=s.bytesSent,t.bytesReceived=s.bytesReceived,null==s.availableOutgoingBitrate){const e=t.bytesSent-this._lastBytesSend;this._lastBytesSend=t.bytesSent;const i=Date.now(),r=(i-this._lastBytesSendTime)/1e3;this._lastBytesSendTime=i,s.availableOutgoingBitrate=8*e/r}t.availableOutgoingBitrate=s.availableOutgoingBitrate}const r=i.outputs.audio;r&&(t.audio={bytesSent:r.bytesSent,packetsSent:r.packetsSent,retransmittedBytesSent:r.retransmittedBytesSent,retransmittedPacketsSent:r.retransmittedPacketsSent});const n=i.outputs.audio;return n&&(t.video={bytesSent:n.bytesSent,packetsSent:n.packetsSent,retransmittedBytesSent:n.retransmittedBytesSent,retransmittedPacketsSent:n.retransmittedPacketsSent,firCount:n.firCount,framesEncoded:n.framesEncoded,nackCount:n.nackCount,totalEncodeTime:n.totalEncodeTime,hugeFramesSent:n.hugeFramesSent,framesSent:n.framesSent,frameHeight:n.frameHeight,frameWidth:n.frameWidth}),t}))}}const J="3.0.0";export{U as ABRAbstract,V as ABRGrade,j as ABRLinear,P as HTTPConnector,A as MBRAbstract,N as MBRLinear,T as MType,S as Metadata,D as Player,O as SIPConnector,B as StreamMetadata,F as Streamer,H as StreamerStats,W as Telemetry,J as VERSION,E as WSController,M as WSStreamData,k as utils};//# sourceMappingURL=webrtc-client.min.js.map |
{ | ||
"name": "@ceeblue/webrtc-client", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "Ceeblue WebRTC Client", | ||
@@ -44,5 +44,2 @@ "keywords": [ | ||
}, | ||
"dependencies": { | ||
"@ceeblue/web-utils": "^1.2.0" | ||
}, | ||
"devDependencies": { | ||
@@ -83,3 +80,6 @@ "@html-eslint/eslint-plugin": "~0.22.0", | ||
"access": "public" | ||
}, | ||
"dependencies": { | ||
"@ceeblue/web-utils": "^2.2.0" | ||
} | ||
} |
@@ -37,4 +37,5 @@ [Requirements](#requirements) | [Usage](#usage) | [Examples](#examples) | [Building locally](#building-locally) | [Documentation](#documentation) | [Contribution](#contribution) | [License](#license) | ||
> 💡 **TIP** | ||
> - If your project uses [TypeScript](https://www.typescriptlang.org/), it is recommended to set `"target": "ES6"` in your configuration. This setting aligns with our usage of ES6 features and ensures that your build will succeed. For those requiring a backwards-compatible UMD (Universal Module Definition) version, a [local build](#development) is advised. | ||
> Defining the compiler option `"moduleResolution": "Node"` in **tsconfig.json** helps with import errors by ensuring that TypeScript uses the correct strategy for resolving imports based on the targeted Node.js version. | ||
> | ||
> If your project uses [TypeScript](https://www.typescriptlang.org/), it is recommended to set `"target": "ES6"` in your configuration to align with our usage of ES6 features and ensures that your build will succeed (for those requiring a backwards-compatible [UMD](https://github.com/umdjs/umd) version, a [local build](#building-locally) is advised). | ||
> Then defining the compiler option `"moduleResolution": "Node"` in **tsconfig.json** helps with import errors by ensuring that TypeScript uses the correct strategy for resolving imports based on the targeted Node.js version. | ||
> ```json | ||
@@ -51,6 +52,6 @@ > { | ||
To publish the stream `<streamName>` to `<endpoint>`, use the [Streamer](./src/Streamer.ts) class and the variables you saved while setting up the stream in the dashboard [Requirements](#requirements). For a full example, see push.html in [Examples](#examples). | ||
To publish the stream `<streamName>` to `<endPoint>`, use the [Streamer](./src/Streamer.ts) class and the variables you saved while setting up the stream in the dashboard [Requirements](#requirements). For a full example, see push.html in [Examples](#examples). | ||
```javascript | ||
import Streamer as WebRTC from '@ceeblue/webrtc-client'; | ||
import { Streamer } from '@ceeblue/webrtc-client'; | ||
@@ -64,12 +65,9 @@ const streamer = new Streamer(); | ||
} | ||
navigator.mediaDevices | ||
.getUserMedia({ audio: true, video: true }) | ||
.then(stream => { | ||
streamer.start(stream, { | ||
host: <endpoint>, | ||
streamName: <streamName>, | ||
iceServer: { | ||
urls: ['turn:' + <endPoint> + ':3478?transport=tcp', 'turn:' + <endPoint> + ':3478'], | ||
username: 'csc_demo', credential: 'UtrAFClFFO' | ||
} | ||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); | ||
streamer.start(stream, { | ||
endPoint: <endPoint>, | ||
streamName: <streamName>, | ||
iceServer: { | ||
urls: ['turn:' + <endPoint> + ':3478?transport=tcp', 'turn:' + <endPoint> + ':3478'], | ||
username: 'csc_demo', credential: 'UtrAFClFFO' | ||
} | ||
@@ -84,3 +82,3 @@ }); | ||
```javascript | ||
import Player as WebRTC from '@ceeblue/webrtc-client'; | ||
import { Player } from '@ceeblue/webrtc-client'; | ||
@@ -96,10 +94,10 @@ const player = new Player(); | ||
} | ||
streamer.start(stream, { | ||
host: <endPoint>, | ||
streamName: <streamName>, | ||
iceServer: { | ||
player.start({ | ||
endPoint: <endPoint>, | ||
streamName: <streamName>, | ||
iceServer: { | ||
urls: ['turn:' + <endPoint> + ':3478?transport=tcp', 'turn:' + <endPoint> + ':3478'], | ||
username: 'csc_demo', credential: 'UtrAFClFFO' | ||
} | ||
} | ||
}); | ||
``` | ||
@@ -115,3 +113,3 @@ | ||
1. In your project directory, [if you have installed the simple-http package](/#requirements), execute the following command from the Terminal prompt by navigating to: | ||
1. In your project directory, if you have installed the [http-server service](#requirements), execute the following command from the Terminal prompt by navigating to: | ||
@@ -122,6 +120,6 @@ ```shell | ||
2. Navigate to the specified address in your browser, making sure to replace any placeholders in the URL with the variables you have copied during the [stream setup](/#requirements) in the dashboard. | ||
2. Navigate to the specified address in your browser, making sure to replace any placeholders in the URL with the variables you have copied during the [stream setup](#requirements) in the dashboard. | ||
```html | ||
http://localhost:8081/examples/streamer.html?host=<endpoint>&stream=<streamName> | ||
http://localhost:8081/examples/streamer.html?host=<endPoint>&stream=<streamName> | ||
``` | ||
@@ -131,6 +129,6 @@ | ||
4. In the address bar of a separate browser window, enter the following address, making sure to replace the placeholders in the URL with the variables you have copied while configuring the [stream setup](/#requirements) in the dashboard. | ||
4. In the address bar of a separate browser window, enter the following address, making sure to replace the placeholders in the URL with the variables you have copied while configuring the [stream setup](#requirements) in the dashboard. | ||
```html | ||
http://localhost:8081/examples/player.html?host=<endpoint>&stream=<streamName> | ||
http://localhost:8081/examples/player.html?host=<endPoint>&stream=<streamName> | ||
``` | ||
@@ -180,3 +178,3 @@ | ||
``` | ||
You can access the documentation by opening the index.html file in the docs folder with your browser (`./docs/index.html`), or, if you have [installed and started the http-server](/#requirements), by navigating to: | ||
You can access the documentation by opening the index.html file in the docs folder with your browser (`./docs/index.html`), or if you have installed and started the [http-server service](#requirements) by navigating to: | ||
``` | ||
@@ -183,0 +181,0 @@ http://localhost:8081/docs/ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
827305
6000
182
+ Added@ceeblue/web-utils@2.6.1(transitive)
- Removed@ceeblue/web-utils@1.4.1(transitive)
Updated@ceeblue/web-utils@^2.2.0