livekit-client
Advanced tools
Comparing version 2.0.3 to 2.0.4
@@ -1,2 +0,2 @@ | ||
!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e,t,n,r){return new(n||(n=Promise))((function(i,o){function s(e){try{c(r.next(e))}catch(e){o(e)}}function a(e){try{c(r.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}c((r=r.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;var t,n,r,i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},o={exports:{}};n=i,r=function(){var e=function(){},t="undefined",n=typeof window!==t&&typeof window.navigator!==t&&/Trident\/|MSIE /.test(window.navigator.userAgent),r=["trace","debug","info","warn","error"];function i(e,t){var n=e[t];if("function"==typeof n.bind)return n.bind(e);try{return Function.prototype.bind.call(n,e)}catch(t){return function(){return Function.prototype.apply.apply(n,[e,arguments])}}}function o(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function s(t,n){for(var i=0;i<r.length;i++){var o=r[i];this[o]=i<t?e:this.methodFactory(o,t,n)}this.log=this.debug}function a(e,n,r){return function(){typeof console!==t&&(s.call(this,n,r),this[e].apply(this,arguments))}}function c(r,s,c){return function(r){return"debug"===r&&(r="log"),typeof console!==t&&("trace"===r&&n?o:void 0!==console[r]?i(console,r):void 0!==console.log?i(console,"log"):e)}(r)||a.apply(this,arguments)}function d(e,n,i){var o,a=this;n=null==n?"WARN":n;var d="loglevel";function u(){var e;if(typeof window!==t&&d){try{e=window.localStorage[d]}catch(e){}if(typeof e===t)try{var n=window.document.cookie,r=n.indexOf(encodeURIComponent(d)+"=");-1!==r&&(e=/^([^;]+)/.exec(n.slice(r))[1])}catch(e){}return void 0===a.levels[e]&&(e=void 0),e}}"string"==typeof e?d+=":"+e:"symbol"==typeof e&&(d=void 0),a.name=e,a.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},a.methodFactory=i||c,a.getLevel=function(){return o},a.setLevel=function(n,i){if("string"==typeof n&&void 0!==a.levels[n.toUpperCase()]&&(n=a.levels[n.toUpperCase()]),!("number"==typeof n&&n>=0&&n<=a.levels.SILENT))throw"log.setLevel() called with invalid level: "+n;if(o=n,!1!==i&&function(e){var n=(r[e]||"silent").toUpperCase();if(typeof window!==t&&d){try{return void(window.localStorage[d]=n)}catch(e){}try{window.document.cookie=encodeURIComponent(d)+"="+n+";"}catch(e){}}}(n),s.call(a,n,e),typeof console===t&&n<a.levels.SILENT)return"No console available for logging"},a.setDefaultLevel=function(e){n=e,u()||a.setLevel(e,!1)},a.resetLevel=function(){a.setLevel(n,!1),function(){if(typeof window!==t&&d){try{return void window.localStorage.removeItem(d)}catch(e){}try{window.document.cookie=encodeURIComponent(d)+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC"}catch(e){}}}()},a.enableAll=function(e){a.setLevel(a.levels.TRACE,e)},a.disableAll=function(e){a.setLevel(a.levels.SILENT,e)};var y=u();null==y&&(y=n),a.setLevel(y,!1)}var u=new d,y={};u.getLogger=function(e){if("symbol"!=typeof e&&"string"!=typeof e||""===e)throw new TypeError("You must supply a name when creating a logger.");var t=y[e];return t||(t=y[e]=new d(e,u.getLevel(),u.methodFactory)),t};var l=typeof window!==t?window.log:void 0;return u.noConflict=function(){return typeof window!==t&&window.log===u&&(window.log=l),u},u.getLoggers=function(){return y},u.default=u,u},(t=o).exports?t.exports=r():n.log=r();var s,a,c=o.exports;!function(e){e[e.trace=0]="trace",e[e.debug=1]="debug",e[e.info=2]="info",e[e.warn=3]="warn",e[e.error=4]="error",e[e.silent=5]="silent"}(s||(s={})),function(e){e.Default="livekit",e.Room="livekit-room",e.Participant="livekit-participant",e.Track="livekit-track",e.Publication="livekit-track-publication",e.Engine="livekit-engine",e.Signal="livekit-signal",e.PCManager="livekit-pc-manager",e.PCTransport="livekit-pc-transport",e.E2EE="lk-e2ee"}(a||(a={})),c.getLogger("livekit").setDefaultLevel(s.info);const d=c.getLogger("lk-e2ee"),u="AES-GCM",y={key:10,delta:3,audio:1,empty:0},l={sharedKey:!1,ratchetSalt:"LKFrameEncryptionKey",ratchetWindowSize:8,failureTolerance:10};class h extends Error{constructor(e,t){super(t||"an error has occured"),this.code=e}}var p,f,v,g,m,w;!function(e){e.PermissionDenied="PermissionDenied",e.NotFound="NotFound",e.DeviceInUse="DeviceInUse",e.Other="Other"}(p||(p={})),function(e){e.getFailure=function(t){if(t&&"name"in t)return"NotFoundError"===t.name||"DevicesNotFoundError"===t.name?e.NotFound:"NotAllowedError"===t.name||"PermissionDeniedError"===t.name?e.PermissionDenied:"NotReadableError"===t.name||"TrackStartError"===t.name?e.DeviceInUse:e.Other}}(p||(p={})),function(e){e[e.InvalidKey=0]="InvalidKey",e[e.MissingKey=1]="MissingKey",e[e.InternalError=2]="InternalError"}(f||(f={}));class I extends h{constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:f.InternalError;super(40,e),this.reason=t}}!function(e){e.SetKey="setKey",e.RatchetRequest="ratchetRequest",e.KeyRatcheted="keyRatcheted"}(v||(v={})),function(e){e.KeyRatcheted="keyRatcheted"}(g||(g={})),function(e){e.ParticipantEncryptionStatusChanged="participantEncryptionStatusChanged",e.EncryptionError="encryptionError"}(m||(m={})),function(e){e.Error="cryptorError"}(w||(w={}));var b,S={exports:{}},L="object"==typeof Reflect?Reflect:null,k=L&&"function"==typeof L.apply?L.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};b=L&&"function"==typeof L.ownKeys?L.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var E=Number.isNaN||function(e){return e!=e};function C(){C.init.call(this)}S.exports=C,S.exports.once=function(e,t){return new Promise((function(n,r){function i(n){e.removeListener(t,o),r(n)}function o(){"function"==typeof e.removeListener&&e.removeListener("error",i),n([].slice.call(arguments))}U(e,t,o,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&U(e,"error",t,n)}(e,i,{once:!0})}))},C.EventEmitter=C,C.prototype._events=void 0,C.prototype._eventsCount=0,C.prototype._maxListeners=void 0;var K=10;function _(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function A(e){return void 0===e._maxListeners?C.defaultMaxListeners:e._maxListeners}function T(e,t,n,r){var i,o,s,a;if(_(n),void 0===(o=e._events)?(o=e._events=Object.create(null),e._eventsCount=0):(void 0!==o.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),o=e._events),s=o[t]),void 0===s)s=o[t]=n,++e._eventsCount;else if("function"==typeof s?s=o[t]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),(i=A(e))>0&&s.length>i&&!s.warned){s.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=s.length,a=c,console&&console.warn&&console.warn(a)}return e}function x(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function P(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=x.bind(r);return i.listener=n,r.wrapFn=i,i}function R(e,t,n){var r=e._events;if(void 0===r)return[];var i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(e){for(var t=new Array(e.length),n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}(i):F(i,i.length)}function O(e){var t=this._events;if(void 0!==t){var n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function F(e,t){for(var n=new Array(t),r=0;r<t;++r)n[r]=e[r];return n}function U(e,t,n,r){if("function"==typeof e.on)r.once?e.once(t,n):e.on(t,n);else{if("function"!=typeof e.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof e);e.addEventListener(t,(function i(o){r.once&&e.removeEventListener(t,i),n(o)}))}}Object.defineProperty(C,"defaultMaxListeners",{enumerable:!0,get:function(){return K},set:function(e){if("number"!=typeof e||e<0||E(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");K=e}}),C.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},C.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||E(e))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+e+".");return this._maxListeners=e,this},C.prototype.getMaxListeners=function(){return A(this)},C.prototype.emit=function(e){for(var t=[],n=1;n<arguments.length;n++)t.push(arguments[n]);var r="error"===e,i=this._events;if(void 0!==i)r=r&&void 0===i.error;else if(!r)return!1;if(r){var o;if(t.length>0&&(o=t[0]),o instanceof Error)throw o;var s=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw s.context=o,s}var a=i[e];if(void 0===a)return!1;if("function"==typeof a)k(a,this,t);else{var c=a.length,d=F(a,c);for(n=0;n<c;++n)k(d[n],this,t)}return!0},C.prototype.addListener=function(e,t){return T(this,e,t,!1)},C.prototype.on=C.prototype.addListener,C.prototype.prependListener=function(e,t){return T(this,e,t,!0)},C.prototype.once=function(e,t){return _(t),this.on(e,P(this,e,t)),this},C.prototype.prependOnceListener=function(e,t){return _(t),this.prependListener(e,P(this,e,t)),this},C.prototype.removeListener=function(e,t){var n,r,i,o,s;if(_(t),void 0===(r=this._events))return this;if(void 0===(n=r[e]))return this;if(n===t||n.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit("removeListener",e,n.listener||t));else if("function"!=typeof n){for(i=-1,o=n.length-1;o>=0;o--)if(n[o]===t||n[o].listener===t){s=n[o].listener,i=o;break}if(i<0)return this;0===i?n.shift():function(e,t){for(;t+1<e.length;t++)e[t]=e[t+1];e.pop()}(n,i),1===n.length&&(r[e]=n[0]),void 0!==r.removeListener&&this.emit("removeListener",e,s||t)}return this},C.prototype.off=C.prototype.removeListener,C.prototype.removeAllListeners=function(e){var t,n,r;if(void 0===(n=this._events))return this;if(void 0===n.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==n[e]&&(0==--this._eventsCount?this._events=Object.create(null):delete n[e]),this;if(0===arguments.length){var i,o=Object.keys(n);for(r=0;r<o.length;++r)"removeListener"!==(i=o[r])&&this.removeAllListeners(i);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if("function"==typeof(t=n[e]))this.removeListener(e,t);else if(void 0!==t)for(r=t.length-1;r>=0;r--)this.removeListener(e,t[r]);return this},C.prototype.listeners=function(e){return R(this,e,!0)},C.prototype.rawListeners=function(e){return R(this,e,!1)},C.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):O.call(e,t)},C.prototype.listenerCount=O,C.prototype.eventNames=function(){return this._eventsCount>0?b(this._events):[]};var M=S.exports;function D(e,t){const n=(new TextEncoder).encode(t);switch(e){case"HKDF":return{name:"HKDF",salt:n,hash:"SHA-256",info:new ArrayBuffer(128)};case"PBKDF2":return{name:"PBKDF2",salt:n,hash:"SHA-256",iterations:1e5};default:throw new Error("algorithm ".concat(e," is currently unsupported"))}}function N(t,n){return e(this,void 0,void 0,(function*(){const e=D(t.algorithm.name,n),r=yield crypto.subtle.deriveKey(e,t,{name:u,length:128},!1,["encrypt","decrypt"]);return{material:t,encryptionKey:r}}))}class B{constructor(){this.consecutiveSifCount=0,this.lastSifReceivedAt=0,this.userFramesSinceSif=0}recordSif(){var e;this.consecutiveSifCount+=1,null!==(e=this.sifSequenceStartedAt)&&void 0!==e||(this.sifSequenceStartedAt=Date.now()),this.lastSifReceivedAt=Date.now()}recordUserFrame(){void 0!==this.sifSequenceStartedAt&&(this.userFramesSinceSif+=1,(this.userFramesSinceSif>this.consecutiveSifCount||Date.now()-this.lastSifReceivedAt>2e3)&&this.reset())}isSifAllowed(){return this.consecutiveSifCount<100&&(void 0===this.sifSequenceStartedAt||Date.now()-this.sifSequenceStartedAt<2e3)}reset(){this.userFramesSinceSif=0,this.consecutiveSifCount=0,this.sifSequenceStartedAt=void 0}}const j=new Map;class q extends M.EventEmitter{encodeFunction(e,t){throw Error("not implemented for subclass")}decodeFunction(e,t){throw Error("not implemented for subclass")}}class V extends q{constructor(e){var t;super(),this.sendCounts=new Map,this.keys=e.keys,this.participantIdentity=e.participantIdentity,this.rtpMap=new Map,this.keyProviderOptions=e.keyProviderOptions,this.sifTrailer=null!==(t=e.sifTrailer)&&void 0!==t?t:Uint8Array.from([]),this.sifGuard=new B}get logContext(){return{identity:this.participantIdentity,trackId:this.trackId,fallbackCodec:this.videoCodec}}setParticipant(e,t){this.participantIdentity=e,this.keys=t,this.sifGuard.reset()}unsetParticipant(){d.debug("unsetting participant",this.logContext),this.participantIdentity=void 0}isEnabled(){return this.participantIdentity?j.get(this.participantIdentity):void 0}getParticipantIdentity(){return this.participantIdentity}getTrackId(){return this.trackId}setVideoCodec(e){this.videoCodec=e}setRtpMap(e){this.rtpMap=e}setupTransform(e,t,n,r,i){i&&(d.info("setting codec on cryptor to",{codec:i}),this.videoCodec=i),d.debug("Setting up frame cryptor transform",Object.assign({operation:e,passedTrackId:r,codec:i},this.logContext));const o="encode"===e?this.encodeFunction:this.decodeFunction,s=new TransformStream({transform:o.bind(this)});t.pipeThrough(s).pipeTo(n).catch((e=>{d.warn(e),this.emit(w.Error,e instanceof I?e:new I(e.message))})),this.trackId=r}setSifTrailer(e){d.debug("setting SIF trailer",Object.assign(Object.assign({},this.logContext),{trailer:e})),this.sifTrailer=e}encodeFunction(t,n){var r;return e(this,void 0,void 0,(function*(){if(!this.isEnabled()||0===t.data.byteLength)return n.enqueue(t);const e=this.keys.getKeySet();if(!e)throw new TypeError("key set not found for ".concat(this.participantIdentity," at index ").concat(this.keys.getCurrentKeyIndex()));const{encryptionKey:i}=e,o=this.keys.getCurrentKeyIndex();if(i){const e=this.makeIV(null!==(r=t.getMetadata().synchronizationSource)&&void 0!==r?r:-1,t.timestamp);let a=this.getUnencryptedBytes(t);d.debug("frameInfo for encoded frame",Object.assign(Object.assign({},a),this.logContext));const c=new Uint8Array(t.data,0,a.unencryptedBytes),y=new Uint8Array(2);y[0]=12,y[1]=o;try{const r=yield crypto.subtle.encrypt({name:u,iv:e,additionalData:new Uint8Array(t.data,0,c.byteLength)},i,new Uint8Array(t.data,a.unencryptedBytes));let o=new Uint8Array(r.byteLength+e.byteLength+y.byteLength);o.set(new Uint8Array(r)),o.set(new Uint8Array(e),r.byteLength),o.set(y,r.byteLength+e.byteLength),a.isH264&&(o=function(e){const t=[];for(var n=0,r=0;r<e.length;++r){var i=e[r];i<=3&&n>=2&&(t.push(3),n=0),t.push(i),0==i?++n:n=0}return new Uint8Array(t)}(o));var s=new Uint8Array(c.byteLength+o.byteLength);return s.set(c),s.set(o,c.byteLength),t.data=s.buffer,n.enqueue(t)}catch(e){d.error(e)}}else d.debug("failed to decrypt, emitting error",this.logContext),this.emit(w.Error,new I("encryption key missing for encoding",f.MissingKey))}))}decodeFunction(t,n){return e(this,void 0,void 0,(function*(){if(!this.isEnabled()||0===t.data.byteLength)return d.debug("skipping empty frame",this.logContext),this.sifGuard.recordUserFrame(),n.enqueue(t);if(function(e,t){if(0===t.byteLength)return!1;const n=new Uint8Array(e.slice(e.byteLength-t.byteLength));return t.every(((e,t)=>e===n[t]))}(t.data,this.sifTrailer))return d.debug("enqueue SIF",this.logContext),this.sifGuard.recordSif(),this.sifGuard.isSifAllowed()?(t.data=t.data.slice(0,t.data.byteLength-this.sifTrailer.byteLength),n.enqueue(t)):void d.warn("SIF limit reached, dropping frame");this.sifGuard.recordUserFrame();const e=new Uint8Array(t.data)[t.data.byteLength-1];if(this.keys.getKeySet(e)&&this.keys.hasValidKey)try{const r=yield this.decryptFrame(t,e);if(this.keys.decryptionSuccess(),r)return d.debug("enqueue decrypted frame",this.logContext),n.enqueue(r)}catch(e){e instanceof I&&e.reason===f.InvalidKey?this.keys.hasValidKey&&(this.emit(w.Error,e),this.keys.decryptionFailure()):d.warn("decoding frame failed",{error:e})}else!this.keys.getKeySet(e)&&this.keys.hasValidKey&&(d.warn("skipping decryption due to missing key at index ".concat(e)),this.emit(w.Error,new I("missing key at index ".concat(e," for participant ").concat(this.participantIdentity),f.MissingKey)))}))}decryptFrame(t,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{ratchetCount:0};var o;return e(this,void 0,void 0,(function*(){const e=this.keys.getKeySet(n);if(!i.encryptionKey&&!e)throw new TypeError("no encryption key found for decryption of ".concat(this.participantIdentity));let s=this.getUnencryptedBytes(t);d.debug("frameInfo for decoded frame",Object.assign(Object.assign({},s),this.logContext));try{const n=new Uint8Array(t.data,0,s.unencryptedBytes);var a=new Uint8Array(t.data,n.length,t.data.byteLength-n.length);if(s.isH264&&function(e){for(var t=0;t<e.length-3;t++)if(0==e[t]&&0==e[t+1]&&3==e[t+2])return!0;return!1}(a)){a=function(e){const t=[];for(var n=e.length,r=0;r<e.length;)n-r>=3&&!e[r]&&!e[r+1]&&3==e[r+2]?(t.push(e[r++]),t.push(e[r++]),r++):t.push(e[r++]);return new Uint8Array(t)}(a);const e=new Uint8Array(n.byteLength+a.byteLength);e.set(n),e.set(a,n.byteLength),t.data=e.buffer}const r=new Uint8Array(t.data,t.data.byteLength-2,2),c=r[0],d=new Uint8Array(t.data,t.data.byteLength-c-r.byteLength,c),y=n.byteLength,l=t.data.byteLength-(n.byteLength+c+r.byteLength),h=yield crypto.subtle.decrypt({name:u,iv:d,additionalData:new Uint8Array(t.data,0,n.byteLength)},null!==(o=i.encryptionKey)&&void 0!==o?o:e.encryptionKey,new Uint8Array(t.data,y,l)),p=new ArrayBuffer(n.byteLength+h.byteLength),f=new Uint8Array(p);return f.set(new Uint8Array(t.data,0,n.byteLength)),f.set(new Uint8Array(h),n.byteLength),t.data=p,t}catch(o){if(this.keyProviderOptions.ratchetWindowSize>0){if(i.ratchetCount<this.keyProviderOptions.ratchetWindowSize){let o;if(d.debug("ratcheting key attempt ".concat(i.ratchetCount," of ").concat(this.keyProviderOptions.ratchetWindowSize,", for kind ").concat(t instanceof RTCEncodedAudioFrame?"audio":"video")),(null!=r?r:e)===this.keys.getKeySet(n)){const e=yield this.keys.ratchetKey(n,!1);o=yield N(e,this.keyProviderOptions.ratchetSalt)}const s=yield this.decryptFrame(t,n,r||e,{ratchetCount:i.ratchetCount+1,encryptionKey:null==o?void 0:o.encryptionKey});return s&&o&&(null!=r?r:e)===this.keys.getKeySet(n)&&(this.keys.setKeySet(o,n,!0),this.keys.setCurrentKeyIndex(n)),s}throw d.warn("maximum ratchet attempts exceeded"),new I("valid key missing for participant ".concat(this.participantIdentity),f.InvalidKey)}throw new I("Decryption failed: ".concat(o.message),f.InvalidKey)}}))}makeIV(e,t){var n;const r=new ArrayBuffer(12),i=new DataView(r);this.sendCounts.has(e)||this.sendCounts.set(e,Math.floor(65535*Math.random()));const o=null!==(n=this.sendCounts.get(e))&&void 0!==n?n:0;return i.setUint32(0,e),i.setUint32(4,t),i.setUint32(8,t-o%65535),this.sendCounts.set(e,o+1),r}getUnencryptedBytes(e){var t,n={unencryptedBytes:0,isH264:!1};if(function(e){return"type"in e}(e)){let r=null!==(t=this.getVideoCodec(e))&&void 0!==t?t:this.videoCodec;if("av1"===r||"vp9"===r)throw new Error("".concat(r," is not yet supported for end to end encryption"));if("vp8"===r)return n.unencryptedBytes=y[e.type],n;const i=new Uint8Array(e.data);try{const e=function(e){const t=[];let n=0,r=0,i=e.length-2;for(;r<i;){for(;r<i&&(0!==e[r]||0!==e[r+1]||1!==e[r+2]);)r++;r>=i&&(r=e.length);let o=r;for(;o>n&&0===e[o-1];)o--;if(0===n){if(o!==n)throw TypeError("byte stream contains leading data")}else t.push(n);n=r+=3}return t}(i);if(n.isH264="h264"===r||e.some((e=>[G.SLICE_IDR,G.SLICE_NON_IDR].includes(X(i[e])))),n.isH264){for(const t of e){switch(X(i[t])){case G.SLICE_IDR:case G.SLICE_NON_IDR:return n.unencryptedBytes=t+2,n}}throw new TypeError("Could not find NALU")}}catch(e){}return n.unencryptedBytes=y[e.type],n}return n.unencryptedBytes=y.audio,n}getVideoCodec(e){if(0===this.rtpMap.size)return;const t=e.getMetadata().payloadType,n=t?this.rtpMap.get(t):void 0;return d.debug("reading codec from frame",Object.assign({codec:n},this.logContext)),n}}function X(e){return e&H}const H=31;var G;!function(e){e[e.SLICE_NON_IDR=1]="SLICE_NON_IDR",e[e.SLICE_PARTITION_A=2]="SLICE_PARTITION_A",e[e.SLICE_PARTITION_B=3]="SLICE_PARTITION_B",e[e.SLICE_PARTITION_C=4]="SLICE_PARTITION_C",e[e.SLICE_IDR=5]="SLICE_IDR",e[e.SEI=6]="SEI",e[e.SPS=7]="SPS",e[e.PPS=8]="PPS",e[e.AUD=9]="AUD",e[e.END_SEQ=10]="END_SEQ",e[e.END_STREAM=11]="END_STREAM",e[e.FILLER_DATA=12]="FILLER_DATA",e[e.SPS_EXT=13]="SPS_EXT",e[e.PREFIX_NALU=14]="PREFIX_NALU",e[e.SUBSET_SPS=15]="SUBSET_SPS",e[e.DPS=16]="DPS",e[e.SLICE_AUX=19]="SLICE_AUX",e[e.SLICE_EXT=20]="SLICE_EXT",e[e.SLICE_LAYER_EXT=21]="SLICE_LAYER_EXT"}(G||(G={}));class z extends M.EventEmitter{get hasValidKey(){return this._hasValidKey}constructor(e,t){super(),this.decryptionFailureCount=0,this._hasValidKey=!0,this.currentKeyIndex=0,this.cryptoKeyRing=new Array(16).fill(void 0),this.keyProviderOptions=t,this.ratchetPromiseMap=new Map,this.participantIdentity=e,this.resetKeyStatus()}decryptionFailure(){this.keyProviderOptions.failureTolerance<0||(this.decryptionFailureCount+=1,this.decryptionFailureCount>this.keyProviderOptions.failureTolerance&&(d.warn("key for ".concat(this.participantIdentity," is being marked as invalid")),this._hasValidKey=!1))}decryptionSuccess(){this.resetKeyStatus()}resetKeyStatus(){this.decryptionFailureCount=0,this._hasValidKey=!0}ratchetKey(t){let n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];const r=null!=t?t:this.getCurrentKeyIndex(),i=this.ratchetPromiseMap.get(r);if(void 0!==i)return i;const o=new Promise(((t,i)=>e(this,void 0,void 0,(function*(){try{const i=this.getKeySet(r);if(!i)throw new TypeError("Cannot ratchet key without a valid keyset of participant ".concat(this.participantIdentity));const o=i.material,s=yield function(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{name:u},r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"encrypt";return e(this,void 0,void 0,(function*(){return crypto.subtle.importKey("raw",t,n,!1,"derive"===r?["deriveBits","deriveKey"]:["encrypt","decrypt"])}))}(yield function(t,n){return e(this,void 0,void 0,(function*(){const e=D(t.algorithm.name,n);return crypto.subtle.deriveBits(e,t,256)}))}(o,this.keyProviderOptions.ratchetSalt),o.algorithm.name,"derive");n&&(this.setKeyFromMaterial(s,r,!0),this.emit(g.KeyRatcheted,s,this.participantIdentity,r)),t(s)}catch(e){i(e)}finally{this.ratchetPromiseMap.delete(r)}}))));return this.ratchetPromiseMap.set(r,o),o}setKey(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e(this,void 0,void 0,(function*(){yield this.setKeyFromMaterial(t,n),this.resetKeyStatus()}))}setKeyFromMaterial(t,n){let r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return e(this,void 0,void 0,(function*(){const e=yield N(t,this.keyProviderOptions.ratchetSalt),i=n>=0?n%this.cryptoKeyRing.length:this.currentKeyIndex;d.debug("setting new key with index ".concat(n),{usage:t.usages,algorithm:t.algorithm,ratchetSalt:this.keyProviderOptions.ratchetSalt}),this.setKeySet(e,i,r),i>=0&&(this.currentKeyIndex=i)}))}setKeySet(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];this.cryptoKeyRing[t%this.cryptoKeyRing.length]=e,n&&this.emit(g.KeyRatcheted,e.material,this.participantIdentity,t)}setCurrentKeyIndex(t){return e(this,void 0,void 0,(function*(){this.currentKeyIndex=t%this.cryptoKeyRing.length,this.resetKeyStatus()}))}getCurrentKeyIndex(){return this.currentKeyIndex}getKeySet(e){return this.cryptoKeyRing[null!=e?e:this.currentKeyIndex]}}const W=[],Y=new Map;let Q,J,Z=!1,$=l;function ee(e,t){let n=W.find((e=>e.getTrackId()===t));if(n)e!==n.getParticipantIdentity()&&n.setParticipant(e,te(e));else{if(d.info("creating new cryptor for",{participantIdentity:e}),!$)throw Error("Missing keyProvider options");n=new V({participantIdentity:e,keys:te(e),keyProviderOptions:$,sifTrailer:J}),function(e){e.on(w.Error,(e=>{const t={kind:"error",data:{error:new Error("".concat(f[e.reason],": ").concat(e.message))}};postMessage(t)}))}(n),W.push(n)}return n}function te(e){if(Z)return ne();let t=Y.get(e);return t||(t=new z(e,$),t.on(g.KeyRatcheted,re),Y.set(e,t)),t}function ne(){return Q||(d.debug("creating new shared key handler"),Q=new z("shared-key",$)),Q}function re(e,t,n){postMessage({kind:"ratchetKey",data:{participantIdentity:t,keyIndex:n,material:e}})}d.setDefaultLevel("info"),onmessage=t=>{const{kind:n,data:r}=t.data;switch(n){case"init":d.info("worker initialized"),$=r.keyProviderOptions,Z=!!r.keyProviderOptions.sharedKey;postMessage({kind:"initAck",data:{enabled:false}});break;case"enable":a=r.enabled,c=r.participantIdentity,d.debug("setting encryption enabled for all tracks of ".concat(c),{enable:a}),j.set(c,a),d.info("updated e2ee enabled status"),postMessage(t.data);break;case"decode":ee(r.participantIdentity,r.trackId).setupTransform(n,r.readableStream,r.writableStream,r.trackId,r.codec);break;case"encode":ee(r.participantIdentity,r.trackId).setupTransform(n,r.readableStream,r.writableStream,r.trackId,r.codec);break;case"setKey":Z?(o=r.key,s=r.keyIndex,d.info("set shared key",{index:s}),ne().setKey(o,s)):r.participantIdentity?(d.info("set participant sender key ".concat(r.participantIdentity," index ").concat(r.keyIndex)),te(r.participantIdentity).setKey(r.key,r.keyIndex)):d.error("no participant Id was provided and shared key usage is disabled");break;case"removeTransform":!function(e,t){const n=W.find((n=>n.getParticipantIdentity()===t&&n.getTrackId()===e));n?n.unsetParticipant():d.warn("Could not unset participant on cryptor",{trackId:e,participantIdentity:t})}(r.trackId,r.participantIdentity);break;case"updateCodec":ee(r.participantIdentity,r.trackId).setVideoCodec(r.codec);break;case"setRTPMap":W.forEach((e=>{e.getParticipantIdentity()===r.participantIdentity&&e.setRtpMap(r.map)}));break;case"ratchetRequest":!function(t){e(this,void 0,void 0,(function*(){if(Z){const e=ne();yield e.ratchetKey(t.keyIndex),e.resetKeyStatus()}else if(t.participantIdentity){const e=te(t.participantIdentity);yield e.ratchetKey(t.keyIndex),e.resetKeyStatus()}else d.error("no participant Id was provided for ratchet request and shared key usage is disabled")}))}(r);break;case"setSifTrailer":i=r.trailer,J=i,W.forEach((e=>{e.setSifTrailer(i)}))}var i,o,s,a,c},self.RTCTransformEvent&&(d.debug("setup transform event"),self.onrtctransform=e=>{const t=e.transformer;d.debug("transformer",t),t.handled=!0;const{kind:n,participantIdentity:r,trackId:i,codec:o}=t.options,s=ee(r,i);d.debug("transform",{codec:o}),s.setupTransform(n,t.readable,t.writable,i,o)})})); | ||
!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e,t,n,r){return new(n||(n=Promise))((function(i,o){function s(e){try{c(r.next(e))}catch(e){o(e)}}function a(e){try{c(r.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,a)}c((r=r.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;var t,n,r,i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},o={exports:{}};n=i,r=function(){var e=function(){},t="undefined",n=typeof window!==t&&typeof window.navigator!==t&&/Trident\/|MSIE /.test(window.navigator.userAgent),r=["trace","debug","info","warn","error"];function i(e,t){var n=e[t];if("function"==typeof n.bind)return n.bind(e);try{return Function.prototype.bind.call(n,e)}catch(t){return function(){return Function.prototype.apply.apply(n,[e,arguments])}}}function o(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function s(t,n){for(var i=0;i<r.length;i++){var o=r[i];this[o]=i<t?e:this.methodFactory(o,t,n)}this.log=this.debug}function a(e,n,r){return function(){typeof console!==t&&(s.call(this,n,r),this[e].apply(this,arguments))}}function c(r,s,c){return function(r){return"debug"===r&&(r="log"),typeof console!==t&&("trace"===r&&n?o:void 0!==console[r]?i(console,r):void 0!==console.log?i(console,"log"):e)}(r)||a.apply(this,arguments)}function d(e,n,i){var o,a=this;n=null==n?"WARN":n;var d="loglevel";function u(){var e;if(typeof window!==t&&d){try{e=window.localStorage[d]}catch(e){}if(typeof e===t)try{var n=window.document.cookie,r=n.indexOf(encodeURIComponent(d)+"=");-1!==r&&(e=/^([^;]+)/.exec(n.slice(r))[1])}catch(e){}return void 0===a.levels[e]&&(e=void 0),e}}"string"==typeof e?d+=":"+e:"symbol"==typeof e&&(d=void 0),a.name=e,a.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},a.methodFactory=i||c,a.getLevel=function(){return o},a.setLevel=function(n,i){if("string"==typeof n&&void 0!==a.levels[n.toUpperCase()]&&(n=a.levels[n.toUpperCase()]),!("number"==typeof n&&n>=0&&n<=a.levels.SILENT))throw"log.setLevel() called with invalid level: "+n;if(o=n,!1!==i&&function(e){var n=(r[e]||"silent").toUpperCase();if(typeof window!==t&&d){try{return void(window.localStorage[d]=n)}catch(e){}try{window.document.cookie=encodeURIComponent(d)+"="+n+";"}catch(e){}}}(n),s.call(a,n,e),typeof console===t&&n<a.levels.SILENT)return"No console available for logging"},a.setDefaultLevel=function(e){n=e,u()||a.setLevel(e,!1)},a.resetLevel=function(){a.setLevel(n,!1),function(){if(typeof window!==t&&d){try{return void window.localStorage.removeItem(d)}catch(e){}try{window.document.cookie=encodeURIComponent(d)+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC"}catch(e){}}}()},a.enableAll=function(e){a.setLevel(a.levels.TRACE,e)},a.disableAll=function(e){a.setLevel(a.levels.SILENT,e)};var y=u();null==y&&(y=n),a.setLevel(y,!1)}var u=new d,y={};u.getLogger=function(e){if("symbol"!=typeof e&&"string"!=typeof e||""===e)throw new TypeError("You must supply a name when creating a logger.");var t=y[e];return t||(t=y[e]=new d(e,u.getLevel(),u.methodFactory)),t};var l=typeof window!==t?window.log:void 0;return u.noConflict=function(){return typeof window!==t&&window.log===u&&(window.log=l),u},u.getLoggers=function(){return y},u.default=u,u},(t=o).exports?t.exports=r():n.log=r();var s,a,c=o.exports;!function(e){e[e.trace=0]="trace",e[e.debug=1]="debug",e[e.info=2]="info",e[e.warn=3]="warn",e[e.error=4]="error",e[e.silent=5]="silent"}(s||(s={})),function(e){e.Default="livekit",e.Room="livekit-room",e.Participant="livekit-participant",e.Track="livekit-track",e.Publication="livekit-track-publication",e.Engine="livekit-engine",e.Signal="livekit-signal",e.PCManager="livekit-pc-manager",e.PCTransport="livekit-pc-transport",e.E2EE="lk-e2ee"}(a||(a={})),c.getLogger("livekit").setDefaultLevel(s.info);const d=c.getLogger("lk-e2ee"),u="AES-GCM",y={key:10,delta:3,audio:1,empty:0},l={sharedKey:!1,ratchetSalt:"LKFrameEncryptionKey",ratchetWindowSize:8,failureTolerance:10};class h extends Error{constructor(e,t){super(t||"an error has occured"),this.code=e}}var p,f,v,g,m,w;!function(e){e.PermissionDenied="PermissionDenied",e.NotFound="NotFound",e.DeviceInUse="DeviceInUse",e.Other="Other"}(p||(p={})),function(e){e.getFailure=function(t){if(t&&"name"in t)return"NotFoundError"===t.name||"DevicesNotFoundError"===t.name?e.NotFound:"NotAllowedError"===t.name||"PermissionDeniedError"===t.name?e.PermissionDenied:"NotReadableError"===t.name||"TrackStartError"===t.name?e.DeviceInUse:e.Other}}(p||(p={})),function(e){e[e.InvalidKey=0]="InvalidKey",e[e.MissingKey=1]="MissingKey",e[e.InternalError=2]="InternalError"}(f||(f={}));class I extends h{constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:f.InternalError;super(40,e),this.reason=t}}!function(e){e.SetKey="setKey",e.RatchetRequest="ratchetRequest",e.KeyRatcheted="keyRatcheted"}(v||(v={})),function(e){e.KeyRatcheted="keyRatcheted"}(g||(g={})),function(e){e.ParticipantEncryptionStatusChanged="participantEncryptionStatusChanged",e.EncryptionError="encryptionError"}(m||(m={})),function(e){e.Error="cryptorError"}(w||(w={}));var b,S={exports:{}},L="object"==typeof Reflect?Reflect:null,k=L&&"function"==typeof L.apply?L.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};b=L&&"function"==typeof L.ownKeys?L.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var E=Number.isNaN||function(e){return e!=e};function C(){C.init.call(this)}S.exports=C,S.exports.once=function(e,t){return new Promise((function(n,r){function i(n){e.removeListener(t,o),r(n)}function o(){"function"==typeof e.removeListener&&e.removeListener("error",i),n([].slice.call(arguments))}U(e,t,o,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&U(e,"error",t,n)}(e,i,{once:!0})}))},C.EventEmitter=C,C.prototype._events=void 0,C.prototype._eventsCount=0,C.prototype._maxListeners=void 0;var K=10;function _(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function A(e){return void 0===e._maxListeners?C.defaultMaxListeners:e._maxListeners}function T(e,t,n,r){var i,o,s,a;if(_(n),void 0===(o=e._events)?(o=e._events=Object.create(null),e._eventsCount=0):(void 0!==o.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),o=e._events),s=o[t]),void 0===s)s=o[t]=n,++e._eventsCount;else if("function"==typeof s?s=o[t]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),(i=A(e))>0&&s.length>i&&!s.warned){s.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=s.length,a=c,console&&console.warn&&console.warn(a)}return e}function x(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function P(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=x.bind(r);return i.listener=n,r.wrapFn=i,i}function R(e,t,n){var r=e._events;if(void 0===r)return[];var i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(e){for(var t=new Array(e.length),n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}(i):F(i,i.length)}function O(e){var t=this._events;if(void 0!==t){var n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function F(e,t){for(var n=new Array(t),r=0;r<t;++r)n[r]=e[r];return n}function U(e,t,n,r){if("function"==typeof e.on)r.once?e.once(t,n):e.on(t,n);else{if("function"!=typeof e.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof e);e.addEventListener(t,(function i(o){r.once&&e.removeEventListener(t,i),n(o)}))}}Object.defineProperty(C,"defaultMaxListeners",{enumerable:!0,get:function(){return K},set:function(e){if("number"!=typeof e||e<0||E(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");K=e}}),C.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},C.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||E(e))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+e+".");return this._maxListeners=e,this},C.prototype.getMaxListeners=function(){return A(this)},C.prototype.emit=function(e){for(var t=[],n=1;n<arguments.length;n++)t.push(arguments[n]);var r="error"===e,i=this._events;if(void 0!==i)r=r&&void 0===i.error;else if(!r)return!1;if(r){var o;if(t.length>0&&(o=t[0]),o instanceof Error)throw o;var s=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw s.context=o,s}var a=i[e];if(void 0===a)return!1;if("function"==typeof a)k(a,this,t);else{var c=a.length,d=F(a,c);for(n=0;n<c;++n)k(d[n],this,t)}return!0},C.prototype.addListener=function(e,t){return T(this,e,t,!1)},C.prototype.on=C.prototype.addListener,C.prototype.prependListener=function(e,t){return T(this,e,t,!0)},C.prototype.once=function(e,t){return _(t),this.on(e,P(this,e,t)),this},C.prototype.prependOnceListener=function(e,t){return _(t),this.prependListener(e,P(this,e,t)),this},C.prototype.removeListener=function(e,t){var n,r,i,o,s;if(_(t),void 0===(r=this._events))return this;if(void 0===(n=r[e]))return this;if(n===t||n.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit("removeListener",e,n.listener||t));else if("function"!=typeof n){for(i=-1,o=n.length-1;o>=0;o--)if(n[o]===t||n[o].listener===t){s=n[o].listener,i=o;break}if(i<0)return this;0===i?n.shift():function(e,t){for(;t+1<e.length;t++)e[t]=e[t+1];e.pop()}(n,i),1===n.length&&(r[e]=n[0]),void 0!==r.removeListener&&this.emit("removeListener",e,s||t)}return this},C.prototype.off=C.prototype.removeListener,C.prototype.removeAllListeners=function(e){var t,n,r;if(void 0===(n=this._events))return this;if(void 0===n.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==n[e]&&(0==--this._eventsCount?this._events=Object.create(null):delete n[e]),this;if(0===arguments.length){var i,o=Object.keys(n);for(r=0;r<o.length;++r)"removeListener"!==(i=o[r])&&this.removeAllListeners(i);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if("function"==typeof(t=n[e]))this.removeListener(e,t);else if(void 0!==t)for(r=t.length-1;r>=0;r--)this.removeListener(e,t[r]);return this},C.prototype.listeners=function(e){return R(this,e,!0)},C.prototype.rawListeners=function(e){return R(this,e,!1)},C.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):O.call(e,t)},C.prototype.listenerCount=O,C.prototype.eventNames=function(){return this._eventsCount>0?b(this._events):[]};var M=S.exports;function D(e,t){const n=(new TextEncoder).encode(t);switch(e){case"HKDF":return{name:"HKDF",salt:n,hash:"SHA-256",info:new ArrayBuffer(128)};case"PBKDF2":return{name:"PBKDF2",salt:n,hash:"SHA-256",iterations:1e5};default:throw new Error("algorithm ".concat(e," is currently unsupported"))}}function N(t,n){return e(this,void 0,void 0,(function*(){const e=D(t.algorithm.name,n),r=yield crypto.subtle.deriveKey(e,t,{name:u,length:128},!1,["encrypt","decrypt"]);return{material:t,encryptionKey:r}}))}class B{constructor(){this.consecutiveSifCount=0,this.lastSifReceivedAt=0,this.userFramesSinceSif=0}recordSif(){var e;this.consecutiveSifCount+=1,null!==(e=this.sifSequenceStartedAt)&&void 0!==e||(this.sifSequenceStartedAt=Date.now()),this.lastSifReceivedAt=Date.now()}recordUserFrame(){void 0!==this.sifSequenceStartedAt&&(this.userFramesSinceSif+=1,(this.userFramesSinceSif>this.consecutiveSifCount||Date.now()-this.lastSifReceivedAt>2e3)&&this.reset())}isSifAllowed(){return this.consecutiveSifCount<100&&(void 0===this.sifSequenceStartedAt||Date.now()-this.sifSequenceStartedAt<2e3)}reset(){this.userFramesSinceSif=0,this.consecutiveSifCount=0,this.sifSequenceStartedAt=void 0}}const j=new Map;class q extends M.EventEmitter{encodeFunction(e,t){throw Error("not implemented for subclass")}decodeFunction(e,t){throw Error("not implemented for subclass")}}class V extends q{constructor(e){var t;super(),this.sendCounts=new Map,this.keys=e.keys,this.participantIdentity=e.participantIdentity,this.rtpMap=new Map,this.keyProviderOptions=e.keyProviderOptions,this.sifTrailer=null!==(t=e.sifTrailer)&&void 0!==t?t:Uint8Array.from([]),this.sifGuard=new B}get logContext(){return{identity:this.participantIdentity,trackId:this.trackId,fallbackCodec:this.videoCodec}}setParticipant(e,t){this.participantIdentity=e,this.keys=t,this.sifGuard.reset()}unsetParticipant(){d.debug("unsetting participant",this.logContext),this.participantIdentity=void 0}isEnabled(){return this.participantIdentity?j.get(this.participantIdentity):void 0}getParticipantIdentity(){return this.participantIdentity}getTrackId(){return this.trackId}setVideoCodec(e){this.videoCodec=e}setRtpMap(e){this.rtpMap=e}setupTransform(e,t,n,r,i){i&&(d.info("setting codec on cryptor to",{codec:i}),this.videoCodec=i),d.debug("Setting up frame cryptor transform",Object.assign({operation:e,passedTrackId:r,codec:i},this.logContext));const o="encode"===e?this.encodeFunction:this.decodeFunction,s=new TransformStream({transform:o.bind(this)});t.pipeThrough(s).pipeTo(n).catch((e=>{d.warn(e),this.emit(w.Error,e instanceof I?e:new I(e.message))})),this.trackId=r}setSifTrailer(e){d.debug("setting SIF trailer",Object.assign(Object.assign({},this.logContext),{trailer:e})),this.sifTrailer=e}encodeFunction(t,n){var r;return e(this,void 0,void 0,(function*(){if(!this.isEnabled()||0===t.data.byteLength)return n.enqueue(t);const e=this.keys.getKeySet();if(!e)throw new TypeError("key set not found for ".concat(this.participantIdentity," at index ").concat(this.keys.getCurrentKeyIndex()));const{encryptionKey:i}=e,o=this.keys.getCurrentKeyIndex();if(i){const e=this.makeIV(null!==(r=t.getMetadata().synchronizationSource)&&void 0!==r?r:-1,t.timestamp);let a=this.getUnencryptedBytes(t);d.debug("frameInfo for encoded frame",Object.assign(Object.assign({},a),this.logContext));const c=new Uint8Array(t.data,0,a.unencryptedBytes),y=new Uint8Array(2);y[0]=12,y[1]=o;try{const r=yield crypto.subtle.encrypt({name:u,iv:e,additionalData:new Uint8Array(t.data,0,c.byteLength)},i,new Uint8Array(t.data,a.unencryptedBytes));let o=new Uint8Array(r.byteLength+e.byteLength+y.byteLength);o.set(new Uint8Array(r)),o.set(new Uint8Array(e),r.byteLength),o.set(y,r.byteLength+e.byteLength),a.isH264&&(o=function(e){const t=[];for(var n=0,r=0;r<e.length;++r){var i=e[r];i<=3&&n>=2&&(t.push(3),n=0),t.push(i),0==i?++n:n=0}return new Uint8Array(t)}(o));var s=new Uint8Array(c.byteLength+o.byteLength);return s.set(c),s.set(o,c.byteLength),t.data=s.buffer,n.enqueue(t)}catch(e){d.error(e)}}else d.debug("failed to decrypt, emitting error",this.logContext),this.emit(w.Error,new I("encryption key missing for encoding",f.MissingKey))}))}decodeFunction(t,n){return e(this,void 0,void 0,(function*(){if(!this.isEnabled()||0===t.data.byteLength)return d.debug("skipping empty frame",this.logContext),this.sifGuard.recordUserFrame(),n.enqueue(t);if(function(e,t){if(0===t.byteLength)return!1;const n=new Uint8Array(e.slice(e.byteLength-t.byteLength));return t.every(((e,t)=>e===n[t]))}(t.data,this.sifTrailer))return d.debug("enqueue SIF",this.logContext),this.sifGuard.recordSif(),this.sifGuard.isSifAllowed()?(t.data=t.data.slice(0,t.data.byteLength-this.sifTrailer.byteLength),n.enqueue(t)):void d.warn("SIF limit reached, dropping frame");this.sifGuard.recordUserFrame();const e=new Uint8Array(t.data)[t.data.byteLength-1];if(this.keys.getKeySet(e)&&this.keys.hasValidKey)try{const r=yield this.decryptFrame(t,e);if(this.keys.decryptionSuccess(),r)return d.debug("enqueue decrypted frame",this.logContext),n.enqueue(r)}catch(e){e instanceof I&&e.reason===f.InvalidKey?this.keys.hasValidKey&&(this.emit(w.Error,e),this.keys.decryptionFailure()):d.warn("decoding frame failed",{error:e})}else!this.keys.getKeySet(e)&&this.keys.hasValidKey&&(d.warn("skipping decryption due to missing key at index ".concat(e)),this.emit(w.Error,new I("missing key at index ".concat(e," for participant ").concat(this.participantIdentity),f.MissingKey)))}))}decryptFrame(t,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{ratchetCount:0};var o;return e(this,void 0,void 0,(function*(){const e=this.keys.getKeySet(n);if(!i.encryptionKey&&!e)throw new TypeError("no encryption key found for decryption of ".concat(this.participantIdentity));let s=this.getUnencryptedBytes(t);d.debug("frameInfo for decoded frame",Object.assign(Object.assign({},s),this.logContext));try{const n=new Uint8Array(t.data,0,s.unencryptedBytes);var a=new Uint8Array(t.data,n.length,t.data.byteLength-n.length);if(s.isH264&&function(e){for(var t=0;t<e.length-3;t++)if(0==e[t]&&0==e[t+1]&&3==e[t+2])return!0;return!1}(a)){a=function(e){const t=[];for(var n=e.length,r=0;r<e.length;)n-r>=3&&!e[r]&&!e[r+1]&&3==e[r+2]?(t.push(e[r++]),t.push(e[r++]),r++):t.push(e[r++]);return new Uint8Array(t)}(a);const e=new Uint8Array(n.byteLength+a.byteLength);e.set(n),e.set(a,n.byteLength),t.data=e.buffer}const r=new Uint8Array(t.data,t.data.byteLength-2,2),c=r[0],d=new Uint8Array(t.data,t.data.byteLength-c-r.byteLength,c),y=n.byteLength,l=t.data.byteLength-(n.byteLength+c+r.byteLength),h=yield crypto.subtle.decrypt({name:u,iv:d,additionalData:new Uint8Array(t.data,0,n.byteLength)},null!==(o=i.encryptionKey)&&void 0!==o?o:e.encryptionKey,new Uint8Array(t.data,y,l)),p=new ArrayBuffer(n.byteLength+h.byteLength),f=new Uint8Array(p);return f.set(new Uint8Array(t.data,0,n.byteLength)),f.set(new Uint8Array(h),n.byteLength),t.data=p,t}catch(o){if(this.keyProviderOptions.ratchetWindowSize>0){if(i.ratchetCount<this.keyProviderOptions.ratchetWindowSize){let o;if(d.debug("ratcheting key attempt ".concat(i.ratchetCount," of ").concat(this.keyProviderOptions.ratchetWindowSize,", for kind ").concat(t instanceof RTCEncodedAudioFrame?"audio":"video")),(null!=r?r:e)===this.keys.getKeySet(n)){const e=yield this.keys.ratchetKey(n,!1);o=yield N(e,this.keyProviderOptions.ratchetSalt)}const s=yield this.decryptFrame(t,n,r||e,{ratchetCount:i.ratchetCount+1,encryptionKey:null==o?void 0:o.encryptionKey});return s&&o&&(null!=r?r:e)===this.keys.getKeySet(n)&&(this.keys.setKeySet(o,n,!0),this.keys.setCurrentKeyIndex(n)),s}throw d.warn("maximum ratchet attempts exceeded"),new I("valid key missing for participant ".concat(this.participantIdentity),f.InvalidKey)}throw new I("Decryption failed: ".concat(o.message),f.InvalidKey)}}))}makeIV(e,t){var n;const r=new ArrayBuffer(12),i=new DataView(r);this.sendCounts.has(e)||this.sendCounts.set(e,Math.floor(65535*Math.random()));const o=null!==(n=this.sendCounts.get(e))&&void 0!==n?n:0;return i.setUint32(0,e),i.setUint32(4,t),i.setUint32(8,t-o%65535),this.sendCounts.set(e,o+1),r}getUnencryptedBytes(e){var t,n={unencryptedBytes:0,isH264:!1};if(function(e){return"type"in e}(e)){let r=null!==(t=this.getVideoCodec(e))&&void 0!==t?t:this.videoCodec;if("av1"===r||"vp9"===r)throw new Error("".concat(r," is not yet supported for end to end encryption"));if("vp8"===r)return n.unencryptedBytes=y[e.type],n;const i=new Uint8Array(e.data);try{const e=function(e){const t=[];let n=0,r=0,i=e.length-2;for(;r<i;){for(;r<i&&(0!==e[r]||0!==e[r+1]||1!==e[r+2]);)r++;r>=i&&(r=e.length);let o=r;for(;o>n&&0===e[o-1];)o--;if(0===n){if(o!==n)throw TypeError("byte stream contains leading data")}else t.push(n);n=r+=3}return t}(i);if(n.isH264="h264"===r||e.some((e=>[G.SLICE_IDR,G.SLICE_NON_IDR].includes(X(i[e])))),n.isH264){for(const t of e){switch(X(i[t])){case G.SLICE_IDR:case G.SLICE_NON_IDR:return n.unencryptedBytes=t+2,n}}throw new TypeError("Could not find NALU")}}catch(e){}return n.unencryptedBytes=y[e.type],n}return n.unencryptedBytes=y.audio,n}getVideoCodec(e){if(0===this.rtpMap.size)return;const t=e.getMetadata().payloadType,n=t?this.rtpMap.get(t):void 0;return d.debug("reading codec from frame",Object.assign({codec:n},this.logContext)),n}}function X(e){return e&H}const H=31;var G;!function(e){e[e.SLICE_NON_IDR=1]="SLICE_NON_IDR",e[e.SLICE_PARTITION_A=2]="SLICE_PARTITION_A",e[e.SLICE_PARTITION_B=3]="SLICE_PARTITION_B",e[e.SLICE_PARTITION_C=4]="SLICE_PARTITION_C",e[e.SLICE_IDR=5]="SLICE_IDR",e[e.SEI=6]="SEI",e[e.SPS=7]="SPS",e[e.PPS=8]="PPS",e[e.AUD=9]="AUD",e[e.END_SEQ=10]="END_SEQ",e[e.END_STREAM=11]="END_STREAM",e[e.FILLER_DATA=12]="FILLER_DATA",e[e.SPS_EXT=13]="SPS_EXT",e[e.PREFIX_NALU=14]="PREFIX_NALU",e[e.SUBSET_SPS=15]="SUBSET_SPS",e[e.DPS=16]="DPS",e[e.SLICE_AUX=19]="SLICE_AUX",e[e.SLICE_EXT=20]="SLICE_EXT",e[e.SLICE_LAYER_EXT=21]="SLICE_LAYER_EXT"}(G||(G={}));class z extends M.EventEmitter{get hasValidKey(){return this._hasValidKey}constructor(e,t){super(),this.decryptionFailureCount=0,this._hasValidKey=!0,this.currentKeyIndex=0,this.cryptoKeyRing=new Array(16).fill(void 0),this.keyProviderOptions=t,this.ratchetPromiseMap=new Map,this.participantIdentity=e,this.resetKeyStatus()}decryptionFailure(){this.keyProviderOptions.failureTolerance<0||(this.decryptionFailureCount+=1,this.decryptionFailureCount>this.keyProviderOptions.failureTolerance&&(d.warn("key for ".concat(this.participantIdentity," is being marked as invalid")),this._hasValidKey=!1))}decryptionSuccess(){this.resetKeyStatus()}resetKeyStatus(){this.decryptionFailureCount=0,this._hasValidKey=!0}ratchetKey(t){let n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];const r=null!=t?t:this.getCurrentKeyIndex(),i=this.ratchetPromiseMap.get(r);if(void 0!==i)return i;const o=new Promise(((t,i)=>e(this,void 0,void 0,(function*(){try{const i=this.getKeySet(r);if(!i)throw new TypeError("Cannot ratchet key without a valid keyset of participant ".concat(this.participantIdentity));const o=i.material,s=yield function(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{name:u},r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"encrypt";return e(this,void 0,void 0,(function*(){return crypto.subtle.importKey("raw",t,n,!1,"derive"===r?["deriveBits","deriveKey"]:["encrypt","decrypt"])}))}(yield function(t,n){return e(this,void 0,void 0,(function*(){const e=D(t.algorithm.name,n);return crypto.subtle.deriveBits(e,t,256)}))}(o,this.keyProviderOptions.ratchetSalt),o.algorithm.name,"derive");n&&(this.setKeyFromMaterial(s,r,!0),this.emit(g.KeyRatcheted,s,this.participantIdentity,r)),t(s)}catch(e){i(e)}finally{this.ratchetPromiseMap.delete(r)}}))));return this.ratchetPromiseMap.set(r,o),o}setKey(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e(this,void 0,void 0,(function*(){yield this.setKeyFromMaterial(t,n),this.resetKeyStatus()}))}setKeyFromMaterial(t,n){let r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return e(this,void 0,void 0,(function*(){const e=yield N(t,this.keyProviderOptions.ratchetSalt),i=n>=0?n%this.cryptoKeyRing.length:this.currentKeyIndex;d.debug("setting new key with index ".concat(n),{usage:t.usages,algorithm:t.algorithm,ratchetSalt:this.keyProviderOptions.ratchetSalt}),this.setKeySet(e,i,r),i>=0&&(this.currentKeyIndex=i)}))}setKeySet(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];this.cryptoKeyRing[t%this.cryptoKeyRing.length]=e,n&&this.emit(g.KeyRatcheted,e.material,this.participantIdentity,t)}setCurrentKeyIndex(t){return e(this,void 0,void 0,(function*(){this.currentKeyIndex=t%this.cryptoKeyRing.length,this.resetKeyStatus()}))}getCurrentKeyIndex(){return this.currentKeyIndex}getKeySet(e){return this.cryptoKeyRing[null!=e?e:this.currentKeyIndex]}}const W=[],Y=new Map;let Q,J,Z=!1,$=l;function ee(e,t){let n=W.find((e=>e.getTrackId()===t));if(n)e!==n.getParticipantIdentity()&&n.setParticipant(e,te(e));else{if(d.info("creating new cryptor for",{participantIdentity:e}),!$)throw Error("Missing keyProvider options");n=new V({participantIdentity:e,keys:te(e),keyProviderOptions:$,sifTrailer:J}),function(e){e.on(w.Error,(e=>{const t={kind:"error",data:{error:new Error("".concat(f[e.reason],": ").concat(e.message))}};postMessage(t)}))}(n),W.push(n)}return n}function te(e){if(Z)return ne();let t=Y.get(e);return t||(t=new z(e,$),t.on(g.KeyRatcheted,re),Y.set(e,t)),t}function ne(){return Q||(d.debug("creating new shared key handler"),Q=new z("shared-key",$)),Q}function re(e,t,n){postMessage({kind:"ratchetKey",data:{participantIdentity:t,keyIndex:n,material:e}})}d.setDefaultLevel("info"),onmessage=t=>{const{kind:n,data:r}=t.data;switch(n){case"init":d.setLevel(r.loglevel),d.info("worker initialized"),$=r.keyProviderOptions,Z=!!r.keyProviderOptions.sharedKey;postMessage({kind:"initAck",data:{enabled:false}});break;case"enable":a=r.enabled,c=r.participantIdentity,d.debug("setting encryption enabled for all tracks of ".concat(c),{enable:a}),j.set(c,a),d.info("updated e2ee enabled status"),postMessage(t.data);break;case"decode":ee(r.participantIdentity,r.trackId).setupTransform(n,r.readableStream,r.writableStream,r.trackId,r.codec);break;case"encode":ee(r.participantIdentity,r.trackId).setupTransform(n,r.readableStream,r.writableStream,r.trackId,r.codec);break;case"setKey":Z?(o=r.key,s=r.keyIndex,d.info("set shared key",{index:s}),ne().setKey(o,s)):r.participantIdentity?(d.info("set participant sender key ".concat(r.participantIdentity," index ").concat(r.keyIndex)),te(r.participantIdentity).setKey(r.key,r.keyIndex)):d.error("no participant Id was provided and shared key usage is disabled");break;case"removeTransform":!function(e,t){const n=W.find((n=>n.getParticipantIdentity()===t&&n.getTrackId()===e));n?n.unsetParticipant():d.warn("Could not unset participant on cryptor",{trackId:e,participantIdentity:t})}(r.trackId,r.participantIdentity);break;case"updateCodec":ee(r.participantIdentity,r.trackId).setVideoCodec(r.codec);break;case"setRTPMap":W.forEach((e=>{e.getParticipantIdentity()===r.participantIdentity&&e.setRtpMap(r.map)}));break;case"ratchetRequest":!function(t){e(this,void 0,void 0,(function*(){if(Z){const e=ne();yield e.ratchetKey(t.keyIndex),e.resetKeyStatus()}else if(t.participantIdentity){const e=te(t.participantIdentity);yield e.ratchetKey(t.keyIndex),e.resetKeyStatus()}else d.error("no participant Id was provided for ratchet request and shared key usage is disabled")}))}(r);break;case"setSifTrailer":i=r.trailer,J=i,W.forEach((e=>{e.setSifTrailer(i)}))}var i,o,s,a,c},self.RTCTransformEvent&&(d.debug("setup transform event"),self.onrtctransform=e=>{const t=e.transformer;d.debug("transformer",t),t.handled=!0;const{kind:n,participantIdentity:r,trackId:i,codec:o}=t.options,s=ee(r,i);d.debug("transform",{codec:o}),s.setupTransform(n,t.readable,t.writable,i,o)})})); | ||
//# sourceMappingURL=livekit-client.e2ee.worker.js.map |
@@ -0,1 +1,2 @@ | ||
import type { LogLevel } from '../logger'; | ||
import type { VideoCodec } from '../room/track/options'; | ||
@@ -11,2 +12,3 @@ import type { BaseKeyProvider } from './KeyProvider'; | ||
keyProviderOptions: KeyProviderOptions; | ||
loglevel: LogLevel; | ||
}; | ||
@@ -13,0 +15,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { LogLevel, getLogger, setLogExtension, setLogLevel } from './logger'; | ||
import { LogLevel, LoggerNames, getLogger, setLogExtension, setLogLevel } from './logger'; | ||
import { DataPacket_Kind, DisconnectReason } from './proto/livekit_models_pb'; | ||
@@ -36,4 +36,4 @@ import DefaultReconnectPolicy from './room/DefaultReconnectPolicy'; | ||
export * from './room/track/processor/types'; | ||
export { setLogLevel, setLogExtension, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, isBrowserSupported, supportsAdaptiveStream, supportsDynacast, supportsAV1, supportsVP9, createAudioAnalyser, LogLevel, getLogger, Room, ConnectionState, DataPacket_Kind, DisconnectReason, Participant, RemoteParticipant, LocalParticipant, LocalAudioTrack, LocalVideoTrack, LocalTrack, LocalTrackPublication, RemoteTrack, RemoteAudioTrack, RemoteVideoTrack, RemoteTrackPublication, TrackPublication, ConnectionQuality, DefaultReconnectPolicy, CriticalTimers, }; | ||
export { setLogLevel, setLogExtension, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, isBrowserSupported, supportsAdaptiveStream, supportsDynacast, supportsAV1, supportsVP9, createAudioAnalyser, LogLevel, LoggerNames, getLogger, Room, ConnectionState, DataPacket_Kind, DisconnectReason, Participant, RemoteParticipant, LocalParticipant, LocalAudioTrack, LocalVideoTrack, LocalTrack, LocalTrackPublication, RemoteTrack, RemoteAudioTrack, RemoteVideoTrack, RemoteTrackPublication, TrackPublication, ConnectionQuality, DefaultReconnectPolicy, CriticalTimers, }; | ||
export type { ElementInfo, ParticipantTrackPermission, AudioAnalyserOptions, LiveKitReactNativeInfo, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -30,2 +30,4 @@ import * as log from 'loglevel'; | ||
setDefaultLevel: (level: log.LogLevelDesc) => void; | ||
setLevel: (level: log.LogLevelDesc) => void; | ||
getLevel: () => number; | ||
}; | ||
@@ -32,0 +34,0 @@ declare const _default: StructuredLogger; |
@@ -433,3 +433,4 @@ /** | ||
SubscribedQualityUpdate = "subscribedQualityUpdate", | ||
LocalTrackUnpublished = "localTrackUnpublished" | ||
LocalTrackUnpublished = "localTrackUnpublished", | ||
Offline = "offline" | ||
} | ||
@@ -436,0 +437,0 @@ export declare enum TrackEvent { |
@@ -156,4 +156,5 @@ import type TypedEventEmitter from 'typed-emitter'; | ||
remoteMute: (trackSid: string, muted: boolean) => void; | ||
offline: () => void; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=RTCEngine.d.ts.map |
@@ -6,2 +6,3 @@ import type { LoggerOptions } from '../types'; | ||
import type { TrackProcessor } from './processor/types'; | ||
import type { ReplaceTrackOptions } from './types'; | ||
export default abstract class LocalTrack<TrackKind extends Track.Kind = Track.Kind> extends Track<TrackKind> { | ||
@@ -45,3 +46,4 @@ /** @internal */ | ||
unmute(): Promise<this>; | ||
replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<this>; | ||
replaceTrack(track: MediaStreamTrack, options?: ReplaceTrackOptions): Promise<typeof this>; | ||
replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<typeof this>; | ||
protected restart(constraints?: MediaTrackConstraints): Promise<this>; | ||
@@ -48,0 +50,0 @@ protected setTrackMuted(muted: boolean): void; |
@@ -223,2 +223,10 @@ import type { Track } from './Track'; | ||
} | ||
export interface VideoPresetOptions { | ||
width: number; | ||
height: number; | ||
aspectRatio?: number; | ||
maxBitrate: number; | ||
maxFramerate?: number; | ||
priority?: RTCPriorityType; | ||
} | ||
export declare class VideoPreset { | ||
@@ -228,2 +236,4 @@ encoding: VideoEncoding; | ||
height: number; | ||
aspectRatio?: number; | ||
constructor(videoPresetOptions: VideoPresetOptions); | ||
constructor(width: number, height: number, maxBitrate: number, maxFramerate?: number, priority?: RTCPriorityType); | ||
@@ -230,0 +240,0 @@ get resolution(): VideoResolution; |
@@ -24,2 +24,6 @@ import type LocalAudioTrack from './LocalAudioTrack'; | ||
}; | ||
export interface ReplaceTrackOptions { | ||
userProvidedTrack?: boolean; | ||
stopProcessor?: boolean; | ||
} | ||
//# sourceMappingURL=types.d.ts.map |
@@ -0,1 +1,2 @@ | ||
import type { LogLevel } from '../logger'; | ||
import type { VideoCodec } from '../room/track/options'; | ||
@@ -11,2 +12,3 @@ import type { BaseKeyProvider } from './KeyProvider'; | ||
keyProviderOptions: KeyProviderOptions; | ||
loglevel: LogLevel; | ||
}; | ||
@@ -13,0 +15,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { LogLevel, getLogger, setLogExtension, setLogLevel } from './logger'; | ||
import { LogLevel, LoggerNames, getLogger, setLogExtension, setLogLevel } from './logger'; | ||
import { DataPacket_Kind, DisconnectReason } from './proto/livekit_models_pb'; | ||
@@ -36,4 +36,4 @@ import DefaultReconnectPolicy from './room/DefaultReconnectPolicy'; | ||
export * from './room/track/processor/types'; | ||
export { setLogLevel, setLogExtension, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, isBrowserSupported, supportsAdaptiveStream, supportsDynacast, supportsAV1, supportsVP9, createAudioAnalyser, LogLevel, getLogger, Room, ConnectionState, DataPacket_Kind, DisconnectReason, Participant, RemoteParticipant, LocalParticipant, LocalAudioTrack, LocalVideoTrack, LocalTrack, LocalTrackPublication, RemoteTrack, RemoteAudioTrack, RemoteVideoTrack, RemoteTrackPublication, TrackPublication, ConnectionQuality, DefaultReconnectPolicy, CriticalTimers, }; | ||
export { setLogLevel, setLogExtension, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, isBrowserSupported, supportsAdaptiveStream, supportsDynacast, supportsAV1, supportsVP9, createAudioAnalyser, LogLevel, LoggerNames, getLogger, Room, ConnectionState, DataPacket_Kind, DisconnectReason, Participant, RemoteParticipant, LocalParticipant, LocalAudioTrack, LocalVideoTrack, LocalTrack, LocalTrackPublication, RemoteTrack, RemoteAudioTrack, RemoteVideoTrack, RemoteTrackPublication, TrackPublication, ConnectionQuality, DefaultReconnectPolicy, CriticalTimers, }; | ||
export type { ElementInfo, ParticipantTrackPermission, AudioAnalyserOptions, LiveKitReactNativeInfo, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -30,2 +30,4 @@ import * as log from 'loglevel'; | ||
setDefaultLevel: (level: log.LogLevelDesc) => void; | ||
setLevel: (level: log.LogLevelDesc) => void; | ||
getLevel: () => number; | ||
}; | ||
@@ -32,0 +34,0 @@ declare const _default: StructuredLogger; |
@@ -433,3 +433,4 @@ /** | ||
SubscribedQualityUpdate = "subscribedQualityUpdate", | ||
LocalTrackUnpublished = "localTrackUnpublished" | ||
LocalTrackUnpublished = "localTrackUnpublished", | ||
Offline = "offline" | ||
} | ||
@@ -436,0 +437,0 @@ export declare enum TrackEvent { |
@@ -157,4 +157,5 @@ import type TypedEventEmitter from 'typed-emitter'; | ||
remoteMute: (trackSid: string, muted: boolean) => void; | ||
offline: () => void; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=RTCEngine.d.ts.map |
@@ -6,2 +6,3 @@ import type { LoggerOptions } from '../types'; | ||
import type { TrackProcessor } from './processor/types'; | ||
import type { ReplaceTrackOptions } from './types'; | ||
export default abstract class LocalTrack<TrackKind extends Track.Kind = Track.Kind> extends Track<TrackKind> { | ||
@@ -45,3 +46,4 @@ /** @internal */ | ||
unmute(): Promise<this>; | ||
replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<this>; | ||
replaceTrack(track: MediaStreamTrack, options?: ReplaceTrackOptions): Promise<typeof this>; | ||
replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<typeof this>; | ||
protected restart(constraints?: MediaTrackConstraints): Promise<this>; | ||
@@ -48,0 +50,0 @@ protected setTrackMuted(muted: boolean): void; |
@@ -223,2 +223,10 @@ import type { Track } from './Track'; | ||
} | ||
export interface VideoPresetOptions { | ||
width: number; | ||
height: number; | ||
aspectRatio?: number; | ||
maxBitrate: number; | ||
maxFramerate?: number; | ||
priority?: RTCPriorityType; | ||
} | ||
export declare class VideoPreset { | ||
@@ -228,2 +236,4 @@ encoding: VideoEncoding; | ||
height: number; | ||
aspectRatio?: number; | ||
constructor(videoPresetOptions: VideoPresetOptions); | ||
constructor(width: number, height: number, maxBitrate: number, maxFramerate?: number, priority?: RTCPriorityType); | ||
@@ -230,0 +240,0 @@ get resolution(): VideoResolution; |
@@ -24,2 +24,6 @@ import type LocalAudioTrack from './LocalAudioTrack'; | ||
}; | ||
export interface ReplaceTrackOptions { | ||
userProvidedTrack?: boolean; | ||
stopProcessor?: boolean; | ||
} | ||
//# sourceMappingURL=types.d.ts.map |
{ | ||
"name": "livekit-client", | ||
"version": "2.0.3", | ||
"version": "2.0.4", | ||
"description": "JavaScript/TypeScript client SDK for LiveKit", | ||
@@ -5,0 +5,0 @@ "main": "./dist/livekit-client.umd.js", |
@@ -286,2 +286,3 @@ import { protoInt64 } from '@bufbuild/protobuf'; | ||
if (this.state !== SignalConnectionState.CONNECTED) { | ||
this.state = SignalConnectionState.DISCONNECTED; | ||
clearTimeout(wsTimeout); | ||
@@ -288,0 +289,0 @@ try { |
import { EventEmitter } from 'events'; | ||
import type TypedEventEmitter from 'typed-emitter'; | ||
import log from '../logger'; | ||
import log, { LogLevel, workerLogger } from '../logger'; | ||
import { Encryption_Type, TrackInfo } from '../proto/livekit_models_pb'; | ||
@@ -71,2 +71,3 @@ import type RTCEngine from '../room/RTCEngine'; | ||
keyProviderOptions: this.keyProvider.getOptions(), | ||
loglevel: workerLogger.getLevel() as LogLevel, | ||
}, | ||
@@ -73,0 +74,0 @@ }; |
@@ -0,1 +1,2 @@ | ||
import type { LogLevel } from '../logger'; | ||
import type { VideoCodec } from '../room/track/options'; | ||
@@ -13,2 +14,3 @@ import type { BaseKeyProvider } from './KeyProvider'; | ||
keyProviderOptions: KeyProviderOptions; | ||
loglevel: LogLevel; | ||
}; | ||
@@ -15,0 +17,0 @@ } |
@@ -35,2 +35,3 @@ import { workerLogger } from '../../logger'; | ||
case 'init': | ||
workerLogger.setLevel(data.loglevel); | ||
workerLogger.info('worker initialized'); | ||
@@ -37,0 +38,0 @@ keyProviderOptions = data.keyProviderOptions; |
@@ -1,2 +0,2 @@ | ||
import { LogLevel, getLogger, setLogExtension, setLogLevel } from './logger'; | ||
import { LogLevel, LoggerNames, getLogger, setLogExtension, setLogLevel } from './logger'; | ||
import { DataPacket_Kind, DisconnectReason } from './proto/livekit_models_pb'; | ||
@@ -58,2 +58,3 @@ import DefaultReconnectPolicy from './room/DefaultReconnectPolicy'; | ||
LogLevel, | ||
LoggerNames, | ||
getLogger, | ||
@@ -60,0 +61,0 @@ Room, |
@@ -34,2 +34,4 @@ import * as log from 'loglevel'; | ||
setDefaultLevel: (level: log.LogLevelDesc) => void; | ||
setLevel: (level: log.LogLevelDesc) => void; | ||
getLevel: () => number; | ||
}; | ||
@@ -36,0 +38,0 @@ |
@@ -83,4 +83,13 @@ import log from '../logger'; | ||
const device = devices.find((d) => d.groupId === groupId && d.deviceId !== defaultId); | ||
// `default` devices will have the same groupId as the entry with the actual device id so we store the counts for each group id | ||
const groupIdCounts = new Map(devices.map((d) => [d.groupId, 0])); | ||
devices.forEach((d) => groupIdCounts.set(d.groupId, (groupIdCounts.get(d.groupId) ?? 0) + 1)); | ||
const device = devices.find( | ||
(d) => | ||
(groupId === d.groupId || (groupIdCounts.get(d.groupId) ?? 0) > 1) && | ||
d.deviceId !== defaultId, | ||
); | ||
return device?.deviceId; | ||
@@ -87,0 +96,0 @@ } |
@@ -494,2 +494,3 @@ /** | ||
LocalTrackUnpublished = 'localTrackUnpublished', | ||
Offline = 'offline', | ||
} | ||
@@ -496,0 +497,0 @@ |
@@ -516,2 +516,6 @@ import type { InternalRoomOptions } from '../../options'; | ||
): Promise<LocalTrackPublication> { | ||
if (track instanceof LocalAudioTrack) { | ||
track.setAudioContext(this.audioContext); | ||
} | ||
await this.reconnectFuture?.promise; | ||
@@ -570,6 +574,2 @@ if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) { | ||
if (track instanceof LocalAudioTrack) { | ||
track.setAudioContext(this.audioContext); | ||
} | ||
// is it already published? if so skip | ||
@@ -576,0 +576,0 @@ let existingPublication: LocalTrackPublication | undefined; |
@@ -421,2 +421,15 @@ import { EventEmitter } from 'events'; | ||
} | ||
// detect cases where both signal client and peer connection are severed and assume that user has lost network connection | ||
const isSignalSevered = | ||
this.client.isDisconnected || | ||
this.client.currentState === SignalConnectionState.RECONNECTING; | ||
const isPCSevered = [ | ||
PCTransportState.FAILED, | ||
PCTransportState.CLOSING, | ||
PCTransportState.CLOSED, | ||
].includes(connectionState); | ||
if (isSignalSevered && isPCSevered && !this._isClosed) { | ||
this.emit(EngineEvent.Offline); | ||
} | ||
}; | ||
@@ -1404,2 +1417,3 @@ this.pcManager.onTrack = (ev: RTCTrackEvent) => { | ||
remoteMute: (trackSid: string, muted: boolean) => void; | ||
offline: () => void; | ||
}; |
@@ -54,2 +54,7 @@ import { TrackEvent } from '../events'; | ||
try { | ||
if (this.isMuted) { | ||
this.log.debug('Track already muted', this.logContext); | ||
return this; | ||
} | ||
// disabled special handling as it will cause BT headsets to switch communication modes | ||
@@ -71,2 +76,7 @@ if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) { | ||
try { | ||
if (!this.isMuted) { | ||
this.log.debug('Track already unmuted', this.logContext); | ||
return this; | ||
} | ||
const deviceHasChanged = | ||
@@ -73,0 +83,0 @@ this._constraints.deviceId && |
@@ -11,2 +11,3 @@ import { debounce } from 'ts-debounce'; | ||
import type { TrackProcessor } from './processor/types'; | ||
import type { ReplaceTrackOptions } from './types'; | ||
@@ -228,3 +229,8 @@ const defaultDimensionsTimeout = 1000; | ||
async replaceTrack(track: MediaStreamTrack, userProvidedTrack = true) { | ||
async replaceTrack(track: MediaStreamTrack, options?: ReplaceTrackOptions): Promise<typeof this>; | ||
async replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<typeof this>; | ||
async replaceTrack( | ||
track: MediaStreamTrack, | ||
userProvidedOrOptions: boolean | ReplaceTrackOptions | undefined, | ||
) { | ||
if (!this.sender) { | ||
@@ -234,2 +240,14 @@ throw new TrackInvalidError('unable to replace an unpublished track'); | ||
let userProvidedTrack: boolean | undefined; | ||
let stopProcessor: boolean | undefined; | ||
if (typeof userProvidedOrOptions === 'boolean') { | ||
userProvidedTrack = userProvidedOrOptions; | ||
} else if (userProvidedOrOptions !== undefined) { | ||
userProvidedTrack = userProvidedOrOptions.userProvidedTrack; | ||
stopProcessor = userProvidedOrOptions.stopProcessor; | ||
} | ||
this.providedByUser = userProvidedTrack ?? true; | ||
this.log.debug('replace MediaStreamTrack', this.logContext); | ||
@@ -239,5 +257,4 @@ await this.setMediaStreamTrack(track); | ||
// on the previous state in order to cleanup | ||
this.providedByUser = userProvidedTrack; | ||
if (this.processor) { | ||
if (stopProcessor && this.processor) { | ||
await this.stopProcessor(); | ||
@@ -244,0 +261,0 @@ } |
@@ -121,2 +121,7 @@ import type { SignalClient } from '../../api/SignalClient'; | ||
try { | ||
if (this.isMuted) { | ||
this.log.debug('Track already muted', this.logContext); | ||
return this; | ||
} | ||
if (this.source === Track.Source.Camera && !this.isUserProvided) { | ||
@@ -137,2 +142,7 @@ this.log.debug('stopping camera track', this.logContext); | ||
try { | ||
if (!this.isMuted) { | ||
this.log.debug('Track already unmuted', this.logContext); | ||
return this; | ||
} | ||
if (this.source === Track.Source.Camera && !this.isUserProvided) { | ||
@@ -139,0 +149,0 @@ this.log.debug('reacquiring camera track', this.logContext); |
@@ -260,2 +260,11 @@ import type { Track } from './Track'; | ||
export interface VideoPresetOptions { | ||
width: number; | ||
height: number; | ||
aspectRatio?: number; | ||
maxBitrate: number; | ||
maxFramerate?: number; | ||
priority?: RTCPriorityType; | ||
} | ||
export class VideoPreset { | ||
@@ -268,2 +277,5 @@ encoding: VideoEncoding; | ||
aspectRatio?: number; | ||
constructor(videoPresetOptions: VideoPresetOptions); | ||
constructor( | ||
@@ -275,10 +287,31 @@ width: number, | ||
priority?: RTCPriorityType, | ||
); | ||
constructor( | ||
widthOrOptions: number | VideoPresetOptions, | ||
height?: number, | ||
maxBitrate?: number, | ||
maxFramerate?: number, | ||
priority?: RTCPriorityType, | ||
) { | ||
this.width = width; | ||
this.height = height; | ||
this.encoding = { | ||
maxBitrate, | ||
maxFramerate, | ||
priority, | ||
}; | ||
if (typeof widthOrOptions === 'object') { | ||
this.width = widthOrOptions.width; | ||
this.height = widthOrOptions.height; | ||
this.aspectRatio = widthOrOptions.aspectRatio; | ||
this.encoding = { | ||
maxBitrate: widthOrOptions.maxBitrate, | ||
maxFramerate: widthOrOptions.maxFramerate, | ||
priority: widthOrOptions.priority, | ||
}; | ||
} else if (height !== undefined && maxBitrate !== undefined) { | ||
this.width = widthOrOptions; | ||
this.height = height; | ||
this.aspectRatio = widthOrOptions / height; | ||
this.encoding = { | ||
maxBitrate, | ||
maxFramerate, | ||
priority, | ||
}; | ||
} else { | ||
throw new TypeError('Unsupported options: provide at least width, height and maxBitrate'); | ||
} | ||
} | ||
@@ -291,3 +324,3 @@ | ||
frameRate: this.encoding.maxFramerate, | ||
aspectRatio: this.width / this.height, | ||
aspectRatio: this.aspectRatio, | ||
}; | ||
@@ -294,0 +327,0 @@ } |
@@ -26,1 +26,6 @@ import type LocalAudioTrack from './LocalAudioTrack'; | ||
}; | ||
export interface ReplaceTrackOptions { | ||
userProvidedTrack?: boolean; | ||
stopProcessor?: boolean; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
6170170
60369