@scrypted/prebuffer-mixin 0.1.51 → 0.1.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  {
2
- "scrypted.debugHost": "192.168.2.119",
2
+ "scrypted.debugHost": "127.0.0.1",
3
3
  }
@@ -1,2 +1,2 @@
1
- !function(e,t){for(var r in t)e[r]=t[r]}(window,function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=5)}([function(e,t,r){"use strict";var n=r(6);try{n=Object.assign(n,{log:deviceManager.getDeviceLogger(void 0),deviceManager:deviceManager,endpointManager:endpointManager,mediaManager:mediaManager,systemManager:systemManager,pluginHostAPI:pluginHostAPI})}catch(e){console.error("sdk initialization error, import @scrypted/sdk/types instead",e)}e.exports=n,e.exports.default=n},function(e,t){e.exports=require("events")},function(e,t){e.exports=require("net")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.listenZeroCluster=async function(e){for(;;){const t=1e4+Math.round(3e4*Math.random());e.listen(t);try{return await(0,n.once)(e,"listening"),e.address().port}catch(e){}}};var n=r(1)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(12);Object.keys(n).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===n[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return n[e]}}))}))},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n,o=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=f();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(r(0)),i=r(2),s=r(3),a=(n=r(1))&&n.__esModule?n:{default:n},c=r(9),d=r(10),u=r(4),p=r(13),l=r(15);function f(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return f=function(){return e},e}function m(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const{mediaManager:h,log:g,systemManager:v,deviceManager:y}=o.default;class S extends c.SettingsMixinDeviceBase{constructor(e,t,r,n){super(e,r,{providerNativeId:n,mixinDeviceInterfaces:t,group:"Rebroadcast and Prebuffer Settings",groupKey:"prebuffer"}),m(this,"prebuffers",{mp4:[],mpegts:[]}),m(this,"events",new a.default),m(this,"released",!1),m(this,"detectedIdrInterval",0),m(this,"prevIdr",0),m(this,"unexpectedPCM",!1),this.console.log("prebuffer session starting in 10 seconds"),setTimeout(()=>this.ensurePrebufferSession(),1e4)}async getMixinSettings(){var e,t,r,n,o,i,s;const a=[];return a.push({title:"Prebuffer Duration",description:"Duration of the prebuffer in milliseconds.",type:"number",key:"prebufferDuration",value:this.storage.getItem("prebufferDuration")||15e3.toString()},{title:"Start at Previous Keyframe",description:"Start live streams from the previous key frame. Improves startup time.",type:"boolean",key:"sendKeyframe",value:("false"!==this.storage.getItem("sendKeyframe")).toString()},{title:"Reencode Audio",description:"Reencode the audio (necessary if camera outputs PCM).",type:"boolean",key:"reencodeAudio",value:("true"===this.storage.getItem("reencodeAudio")).toString()},{group:"Media Information",title:"Detected Resolution",readonly:!0,key:"detectedAcodec",value:""+((null===(e=this.session)||void 0===e||null===(t=e.inputVideoResolution)||void 0===t?void 0:t[0])||"unknown")},{group:"Media Information",title:"Detected Video/Audio Codecs",readonly:!0,key:"detectedVcodec",value:((null===(r=this.session)||void 0===r||null===(n=r.inputVideoCodec)||void 0===n?void 0:n.toString())||"unknown")+"/"+((null===(o=this.session)||void 0===o||null===(i=o.inputAudioCodec)||void 0===i?void 0:i.toString())||"unknown")},{group:"Media Information",title:"Detected Keyframe Interval",description:"Currently detected keyframe interval. This value may vary based on the stream behavior.",readonly:!0,key:"detectedIdr",value:(null===(s=this.detectedIdrInterval)||void 0===s?void 0:s.toString())||"none"}),a}async putMixinSetting(e,t){var r;this.storage.setItem(e,t.toString()),null===(r=this.prebufferSession)||void 0===r||r.then(e=>e.kill())}ensurePrebufferSession(){this.prebufferSession||this.released||(console.log("prebuffer session started"),this.prebufferSession=this.startPrebufferSession())}async startPrebufferSession(){this.prebuffers.mp4=[],this.prebuffers.mpegts=[];const e=parseInt(this.storage.getItem("prebufferDuration"))||15e3,t=JSON.parse((await h.convertMediaObjectToBuffer(await this.mixinDevice.getVideoStream(),o.ScryptedMimeTypes.FFmpegInput)).toString()),r="true"===this.storage.getItem("reencodeAudio")||this.unexpectedPCM,n=await(0,u.probeVideoCamera)(this.mixinDevice);let i;i=n.noAudio?["-an"]:r?[]:["-acodec","copy"];const s=["-vcodec","copy"],a=await(0,d.startRebroadcastSession)(t,{console:this.console,parsers:{mp4:(0,p.createFragmentedMp4Parser)({vcodec:s,acodec:i}),mpegts:(0,p.createMpegTsParser)({vcodec:s,acodec:i})}});this.session=a,this.session.inputAudioCodec?"aac"!==this.session.inputAudioCodec&&(this.console.error("Detected audio codec was not AAC."),n.noAudio||!a.inputAudioCodec||-1===a.inputAudioCodec.indexOf("pcm")||r||(g.a(this.name+" is using PCM audio and will be reencoded. Enable Reencode Audio in Rebroadcast Settings to disable this alert."),this.unexpectedPCM=!0)):this.console.warn("no audio detected."),"h264"!==this.session.inputVideoCodec&&this.console.error("video codec is not h264. If there are errors, try changing your camera's encoder output."),a.events.on("killed",()=>{this.prebufferSession=void 0});for(const t of["mpegts","mp4"]){const r=t+"-data",n=this.prebuffers[t];a.events.on(r,t=>{const o=Date.now();for("mdat"===t.type&&(this.prevIdr&&(this.detectedIdrInterval=o-this.prevIdr),this.prevIdr=o),n.push({time:o,chunk:t});n.length&&n[0].time<o-e;)n.shift();this.events.emit(r,t)})}return a}async getVideoStream(e){var t;this.ensurePrebufferSession();const r=await this.prebufferSession;if(null!=e&&e.id&&e.id!==(null===(t=r.ffmpegInputs.mpegts.mediaStreamOptions)||void 0===t?void 0:t.id))return this.console.log("rebroadcast session cant be used here",e),this.mixinDevice.getVideoStream(e);const n="false"!==this.storage.getItem("sendKeyframe");if(!(null!=e&&e.prebuffer||n)){return h.createFFmpegMediaObject(r.ffmpegInputs.mpegts)}this.console.log("prebuffer request started");const o=(null==e?void 0:e.container)||"mpegts",a=o+"-data",c=this.prebuffers[o],d=new i.Server(t=>{d.close();const r=(null==e?void 0:e.prebuffer)||(n?1.5*Math.max(4e3,this.detectedIdrInterval||4e3):0),o=Date.now();let i,s=!0;const u=e=>{s&&(s=!1,e.startStream&&t.write(e.startStream)),t.write(e.chunk)};for(const e of c)e.time<o-r||u(e.chunk);this.events.on(a,u),i=()=>{this.console.log("prebuffer request ended"),this.events.removeListener(a,u),this.events.removeListener("killed",i),t.removeAllListeners(),t.destroy()},this.events.once("killed",i),t.once("end",i),t.once("close",i),t.once("error",i)});setTimeout(()=>d.close(),3e4);const u=await(0,s.listenZeroCluster)(d),p=r.ffmpegInputs[o].mediaStreamOptions?Object.assign({},r.ffmpegInputs[o].mediaStreamOptions):void 0;if(p&&p.audio){"true"===this.storage.getItem("reencodeAudio")&&(p.audio={codec:"aac"})}p.video&&Object.assign(p.video,{width:parseInt(this.session.inputVideoResolution[2]),height:parseInt(this.session.inputVideoResolution[3])});const l={inputArguments:["-f",o,"-i","tcp://127.0.0.1:"+u],mediaStreamOptions:p};this.console.log("prebuffer ffmpeg input",l.inputArguments[3]);return h.createFFmpegMediaObject(l)}async getVideoStreamOptions(){const e=await this.mixinDevice.getVideoStreamOptions()||[];let t=e[0];return t||(t={},e.push(t)),t.prebuffer=parseInt(this.storage.getItem("prebufferDuration"))||15e3,e}release(){var e;this.console.log("prebuffer releasing if started"),this.released=!0,null===(e=this.prebufferSession)||void 0===e||e.then(e=>{this.console.log("prebuffer released"),e.kill()})}}class b extends l.AutoenableMixinProvider{constructor(e){super(e);for(const e of Object.keys(v.getSystemState())){var t;const r=v.getDeviceById(e);null!==(t=r.mixins)&&void 0!==t&&t.includes(this.id)&&r.getVideoStreamOptions()}const r=function(){var e=new Date;return e.setHours(24),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0),e.getTime()-(new Date).getTime()}()+72e5;this.log.i(`Rebroadcaster scheduled for restart at 2AM: ${Math.round(r/1e3/60)} minutes`),setTimeout(()=>y.requestRestart(),r)}async canMixin(e,t){return t.includes(o.ScryptedInterface.VideoCamera)?[o.ScryptedInterface.VideoCamera,o.ScryptedInterface.Settings]:null}async getMixin(e,t,r){return this.setHasEnabledMixin(r.id),new S(e,t,r,this.nativeId)}async releaseMixin(e,t){t.release()}}var M=new b;t.default=M},function(e,t,r){"use strict";const n=r(7);r(8);class o{constructor(e){this.nativeId=e}get storage(){return this._storage||(this._storage=deviceManager.getDeviceStorage(this.nativeId)),this._storage}get log(){return this._log||(this._log=deviceManager.getDeviceLogger(this.nativeId)),this._log}get console(){return this._console||(this._console=deviceManager.getDeviceConsole(this.nativeId)),this._console}_lazyLoadDeviceState(){this._deviceState||(this.nativeId?this._deviceState=deviceManager.getDeviceState(this.nativeId):this._deviceState=deviceManager.getDeviceState())}}class i{constructor(e,t,r,n){this.mixinDevice=e,this.mixinDevice=e,this.mixinDeviceInterfaces=t,this._deviceState=r,this.mixinProviderNativeId=n}get storage(){return this._storage||(this._storage=deviceManager.getMixinStorage(this.id,this.mixinProviderNativeId)),this._storage}get console(){return this._console||(deviceManager.getMixinConsole?this._console=deviceManager.getMixinConsole(this.id,this.mixinProviderNativeId):this._console=deviceManager.getDeviceConsole(this.mixinProviderNativeId)),this._console}_lazyLoadDeviceState(){}release(){}}!function(){function e(e){return function(){return this._lazyLoadDeviceState(),this._deviceState[e]}}function t(e){return function(t){this._lazyLoadDeviceState(),this._deviceState[e]=t}}for(var r of Object.values(n.ScryptedInterfaceProperty))Object.defineProperty(o.prototype,r,{set:t(r),get:e(r)}),Object.defineProperty(i.prototype,r,{set:t(r),get:e(r)})}();const s={ScryptedDeviceBase:o,MixinDeviceBase:i};Object.assign(s,n),e.exports=s,e.exports.default=s},function(e,t,r){"use strict";const n={};e.exports=n,e.exports.default=n,e.exports.ScryptedDeviceType={Builtin:"Builtin",Camera:"Camera",Fan:"Fan",Light:"Light",Switch:"Switch",Outlet:"Outlet",Sensor:"Sensor",Scene:"Scene",Program:"Program",Automation:"Automation",Vacuum:"Vacuum",Notifier:"Notifier",Thermostat:"Thermostat",Lock:"Lock",PasswordControl:"PasswordControl",Display:"Display",Speaker:"Speaker",Event:"Event",Entry:"Entry",Garage:"Garage",DeviceProvider:"DeviceProvider",DataSource:"DataSource",API:"API",Doorbell:"Doorbell",Irrigation:"Irrigation",Valve:"Valve",Unknown:"Unknown"},e.exports.TemperatureUnit={C:"C",F:"F"},e.exports.ThermostatMode={Off:"Off",Cool:"Cool",Heat:"Heat",HeatCool:"HeatCool",Auto:"Auto",FanOnly:"FanOnly",Purifier:"Purifier",Eco:"Eco",Dry:"Dry",On:"On"},e.exports.LockState={Locked:"Locked",Unlocked:"Unlocked",Jammed:"Jammed"},e.exports.MediaPlayerState={Idle:"Idle",Playing:"Playing",Paused:"Paused",Buffering:"Buffering"},e.exports.ScryptedInterface={ScryptedDevice:"ScryptedDevice",OnOff:"OnOff",Brightness:"Brightness",ColorSettingTemperature:"ColorSettingTemperature",ColorSettingRgb:"ColorSettingRgb",ColorSettingHsv:"ColorSettingHsv",Notifier:"Notifier",StartStop:"StartStop",Pause:"Pause",Dock:"Dock",TemperatureSetting:"TemperatureSetting",Thermometer:"Thermometer",HumiditySensor:"HumiditySensor",Camera:"Camera",VideoCamera:"VideoCamera",Intercom:"Intercom",Lock:"Lock",PasswordStore:"PasswordStore",Authenticator:"Authenticator",Scene:"Scene",Entry:"Entry",EntrySensor:"EntrySensor",DeviceProvider:"DeviceProvider",Battery:"Battery",Refresh:"Refresh",MediaPlayer:"MediaPlayer",Online:"Online",SoftwareUpdate:"SoftwareUpdate",BufferConverter:"BufferConverter",Settings:"Settings",BinarySensor:"BinarySensor",IntrusionSensor:"IntrusionSensor",PowerSensor:"PowerSensor",AudioSensor:"AudioSensor",MotionSensor:"MotionSensor",OccupancySensor:"OccupancySensor",FloodSensor:"FloodSensor",UltravioletSensor:"UltravioletSensor",LuminanceSensor:"LuminanceSensor",PositionSensor:"PositionSensor",MediaSource:"MediaSource",MessagingEndpoint:"MessagingEndpoint",OauthClient:"OauthClient",MixinProvider:"MixinProvider",HttpRequestHandler:"HttpRequestHandler",EngineIOHandler:"EngineIOHandler",PushHandler:"PushHandler",Program:"Program",Scriptable:"Scriptable"},e.exports.ScryptedInterfaceDescriptors={ScryptedDevice:{name:"ScryptedDevice",properties:["id","interfaces","mixins","info","name","providedInterfaces","providedName","providedRoom","providedType","providerId","room","type"],methods:["listen","setName","setRoom","setType"]},OnOff:{name:"OnOff",properties:["on"],methods:["turnOff","turnOn"]},Brightness:{name:"Brightness",properties:["brightness"],methods:["setBrightness"]},ColorSettingTemperature:{name:"ColorSettingTemperature",properties:["colorTemperature"],methods:["getTemperatureMaxK","getTemperatureMinK","setColorTemperature"]},ColorSettingRgb:{name:"ColorSettingRgb",properties:["rgb"],methods:["setRgb"]},ColorSettingHsv:{name:"ColorSettingHsv",properties:["hsv"],methods:["setHsv"]},Notifier:{name:"Notifier",properties:[],methods:["sendNotification"]},StartStop:{name:"StartStop",properties:["running"],methods:["start","stop"]},Pause:{name:"Pause",properties:["paused"],methods:["pause","resume"]},Dock:{name:"Dock",properties:["docked"],methods:["dock"]},TemperatureSetting:{name:"TemperatureSetting",properties:["thermostatAvailableModes","thermostatMode","thermostatSetpoint","thermostatSetpointHigh","thermostatSetpointLow"],methods:["setThermostatMode","setThermostatSetpoint","setThermostatSetpointHigh","setThermostatSetpointLow"]},Thermometer:{name:"Thermometer",properties:["temperature","temperatureUnit"],methods:[]},HumiditySensor:{name:"HumiditySensor",properties:["humidity"],methods:[]},Camera:{name:"Camera",properties:[],methods:["takePicture"]},VideoCamera:{name:"VideoCamera",properties:[],methods:["getVideoStream","getVideoStreamOptions"]},Intercom:{name:"Intercom",properties:[],methods:["startIntercom","stopIntercom"]},Lock:{name:"Lock",properties:["lockState"],methods:["lock","unlock"]},PasswordStore:{name:"PasswordStore",properties:[],methods:["addPassword","getPasswords","removePassword"]},Authenticator:{name:"Authenticator",properties:[],methods:["checkPassword"]},Scene:{name:"Scene",properties:[],methods:["activate","deactivate","isReversible"]},Entry:{name:"Entry",properties:[],methods:["closeEntry","openEntry"]},EntrySensor:{name:"EntrySensor",properties:["entryOpen"],methods:[]},DeviceProvider:{name:"DeviceProvider",properties:[],methods:["discoverDevices","getDevice"]},Battery:{name:"Battery",properties:["batteryLevel"],methods:[]},Refresh:{name:"Refresh",properties:[],methods:["getRefreshFrequency","refresh"]},MediaPlayer:{name:"MediaPlayer",properties:[],methods:["getMediaStatus","load","seek","skipNext","skipPrevious"]},Online:{name:"Online",properties:["online"],methods:[]},SoftwareUpdate:{name:"SoftwareUpdate",properties:["updateAvailable"],methods:["checkForUpdate","installUpdate"]},BufferConverter:{name:"BufferConverter",properties:["fromMimeType","toMimeType"],methods:["convert"]},Settings:{name:"Settings",properties:[],methods:["getSettings","putSetting"]},BinarySensor:{name:"BinarySensor",properties:["binaryState"],methods:[]},IntrusionSensor:{name:"IntrusionSensor",properties:["intrusionDetected"],methods:[]},PowerSensor:{name:"PowerSensor",properties:["powerDetected"],methods:[]},AudioSensor:{name:"AudioSensor",properties:["audioDetected"],methods:[]},MotionSensor:{name:"MotionSensor",properties:["motionDetected"],methods:[]},OccupancySensor:{name:"OccupancySensor",properties:["occupied"],methods:[]},FloodSensor:{name:"FloodSensor",properties:["flooded"],methods:[]},UltravioletSensor:{name:"UltravioletSensor",properties:["ultraviolet"],methods:[]},LuminanceSensor:{name:"LuminanceSensor",properties:["luminance"],methods:[]},PositionSensor:{name:"PositionSensor",properties:["position"],methods:[]},MediaSource:{name:"MediaSource",properties:[],methods:["getMedia"]},MessagingEndpoint:{name:"MessagingEndpoint",properties:[],methods:[]},OauthClient:{name:"OauthClient",properties:[],methods:["getOauthUrl","onOauthCallback"]},MixinProvider:{name:"MixinProvider",properties:[],methods:["canMixin","getMixin","releaseMixin"]},HttpRequestHandler:{name:"HttpRequestHandler",properties:[],methods:["onRequest"]},EngineIOHandler:{name:"EngineIOHandler",properties:[],methods:["onConnection"]},PushHandler:{name:"PushHandler",properties:[],methods:["onPush"]},Program:{name:"Program",properties:[],methods:["run"]},Scriptable:{name:"Scriptable",properties:[],methods:["saveScript","loadScripts","eval"]}},e.exports.ScryptedInterfaceProperty={},Object.values(e.exports.ScryptedInterfaceDescriptors).map(e=>e.properties).flat().forEach(t=>e.exports.ScryptedInterfaceProperty[t]=t),e.exports.ScryptedMimeTypes={AcceptUrlParameter:"accept-url",Url:"text/x-uri",InsecureLocalUrl:"text/x-insecure-local-uri",LocalUrl:"text/x-local-uri",PushEndpoint:"text/x-push-endpoint",FFmpegInput:"x-scrypted/x-ffmpeg-input",RTCAVOffer:"x-scrypted/x-rtc-av-offer",RTCAVAnswer:"x-scrypted/x-rtc-av-answer"}},function(e,t){e.exports=require("stream")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SettingsMixinDeviceBase=void 0;var n=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if(Object.prototype.hasOwnProperty.call(e,i)){var s=n?Object.getOwnPropertyDescriptor(e,i):null;s&&(s.get||s.set)?Object.defineProperty(r,i,s):r[i]=e[i]}r.default=e,t&&t.set(e,r);return r}(r(0));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}const{deviceManager:i}=n.default;class s extends n.MixinDeviceBase{constructor(e,t,r){super(e,r.mixinDeviceInterfaces,t,r.providerNativeId),this.settingsGroup=r.group,this.settingsGroupKey=r.groupKey}async getSettings(){const e=(this.mixinDeviceInterfaces.includes(n.ScryptedInterface.Settings)?await this.mixinDevice.getSettings():[])||[],t=await this.getMixinSettings();for(const e of t)e.group=e.group||this.settingsGroup,e.key=this.settingsGroupKey+":"+e.key;return e.push(...t),e}async putSetting(e,t){var r;const o=this.settingsGroupKey+":";if(null==e||!e.startsWith(o))return this.mixinDevice.putSetting(e,t);await this.putMixinSetting(e.substring(o.length),t),null===(r=i.onMixinEvent)||void 0===r||r.call(i,this.id,this.mixinProviderNativeId,n.ScryptedInterface.Settings,null)}}t.SettingsMixinDeviceBase=s},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parseResolution=p,t.parseVideoCodec=f,t.parseAudioCodec=m,t.startRebroadcastSession=async function(e,t){let r,a=0,d=!0;const l=new s.EventEmitter,{console:h}=t;let g,v,y;function S(){d&&l.emit("killed"),d=!1,null==I||I.kill();for(const e of x)null==e||e.close()}function b(){t.timeout&&(clearTimeout(r),r=setTimeout(S,t.timeout))}b();const M={},P=e.inputArguments.slice(),x=[];let O;const w=new Promise(e=>O=e);for(const o of Object.keys(t.parsers)){const s=t.parsers[o],c=o+"-data",d=(0,n.createServer)(e=>{a++,h.log("rebroadcast client",a),clearTimeout(r);let t=!0;const n=r=>{t&&(t=!1,r.startStream&&e.write(r.startStream)),e.write(r.chunk)},o=()=>{e.removeAllListeners(),l.removeListener(c,n),a--,0===a&&b(),e.destroy()};l.on(c,n),e.on("end",o),e.on("close",o),e.on("error",o)});x.push(d);const u=await(0,i.listenZeroCluster)(d);M[o]={inputArguments:["-f",o,"-i","tcp://127.0.0.1:"+u],mediaStreamOptions:e.mediaStreamOptions};const p=(0,n.createServer)(async e=>{p.close(),O(e);try{const n=o+"-data";for await(const o of s.parse(e,parseInt(null===(t=y)||void 0===t?void 0:t[2]),parseInt(null===(r=y)||void 0===r?void 0:r[3]))){var t,r;l.emit(n,o)}}catch(e){h.error("rebroadcast parse error",e),S()}});x.push(p);const f=await(0,i.listenZeroCluster)(p);P.push(...s.outputArguments,"tcp://127.0.0.1:"+f)}P.unshift("-hide_banner"),h.log(P);const I=o.default.spawn(await u.getFFmpegPath(),P);return(0,c.ffmpegLogInitialOutput)(h,I),I.on("exit",S),m(I).then(e=>g=e),f(I).then(e=>v=e),p(I).then(e=>y=e),await w,{inputAudioCodec:g,inputVideoCodec:v,inputVideoResolution:y,events:l,resetActivityTimer:b,isActive:()=>d,kill:S,servers:x,cp:I,ffmpegInputs:M}};var n=r(2),o=d(r(11)),i=r(3),s=r(1),a=d(r(0)),c=r(4);function d(e){return e&&e.__esModule?e:{default:e}}const{mediaManager:u}=a.default;async function p(e){return new Promise(t=>{const r=n=>{const o=n.toString(),i=/(([0-9]{2,5})x([0-9]{2,5}))/.exec(o);i&&(e.stdout.removeListener("data",r),e.stderr.removeListener("data",r),t(i))};e.stdout.on("data",r),e.stderr.on("data",r)})}async function l(e,t){return new Promise(r=>{const n=o=>{const i=o.toString(),s=i.indexOf(t+": ");if(-1!==s){const o=i.substring(s+t.length+1).trim();let a=o.indexOf(" ");const c=o.indexOf(",");-1!==a&&c<a&&(a=c),-1!==a&&(e.stdout.removeListener("data",n),e.stderr.removeListener("data",n),r(o.substring(0,a)))}};e.stdout.on("data",n),e.stderr.on("data",n)})}async function f(e){return l(e,"Video")}async function m(e){return l(e,"Audio")}},function(e,t){e.exports=require("child_process")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ffmpegLogInitialOutput=function(e,t,r){var o,i;function s(e){const o=i=>{const s=i.toString();for(const e of n)if(-1!==s.indexOf(e))return;if(!r&&(-1!==s.indexOf("frame=")||-1!==s.indexOf("size=")))return e(s),e("video/audio detected, discarding further input"),t.stdout.removeListener("data",o),void t.stderr.removeListener("data",o);e(s)};return o}null===(o=t.stdout)||void 0===o||o.on("data",s(e.log)),null===(i=t.stderr)||void 0===i||i.on("data",s(e.error)),t.on("exit",()=>e.log("ffmpeg exited"))},t.probeVideoCamera=async function(e){let t;try{t=await e.getVideoStreamOptions()||[]}catch(e){}const r=t&&t.length&&null===t[0].audio;return{options:t,noAudio:r}};const n=["decode_slice_header error","no frame!","non-existing PPS"]},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.createMpegTsParser=function(e){return{container:"mpegts",outputArguments:["-f","mpegts",...(null==e?void 0:e.vcodec)||[],...(null==e?void 0:e.acodec)||[]],async*parse(e){let t=[],r=0;for(;;){const o=e.read();if(!o){await(0,n.once)(e,"readable");continue}if(t.push(o),r+=o.length,r<188)continue;const i=Buffer.concat(t);if(71!=i[0])throw new Error("Invalid sync byte in mpeg-ts packet. Terminating stream.");const s=i.length%188,a=i.slice(0,i.length-s),c=i.slice(i.length-s);t=[c],r=c.length,yield{chunk:a}}}}},t.parseFragmentedMP4=i,t.createFragmentedMp4Parser=function(e){return{container:"mp4",outputArguments:["-f","mp4",...(null==e?void 0:e.vcodec)||[],...(null==e?void 0:e.acodec)||[],"-movflags","frag_keyframe+empty_moov+default_base_moof"],async*parse(e){const t=i(e);let r,n,o;for await(const e of t)r?n||(n=e):r=e,yield{startStream:o,chunk:Buffer.concat([e.header,e.data]),type:e.type},r&&n&&!o&&(o=Buffer.concat([r.header,r.data,n.header,n.data]))}}},t.createRawVideoParser=function(e){let t;e&&(t=["-vf",`scale=${e.width}:${e.height}`]);return{container:"rawvideo",outputArguments:[...t||[],"-an","-vcodec","rawvideo","-pix_fmt","yuv420p","-f","rawvideo"],async*parse(t,r,n){if(!r||!n)throw new Error("error parsing rawvideo, unknown width and height");const i=(r=(null==e?void 0:e.width)||r)*(n=(null==e?void 0:e.height)||n)*1.5;for(;;){const e=await(0,o.readLength)(t,i);yield{chunk:e,width:r,height:n}}}}};var n=r(1),o=r(14);async function*i(e){for(;;){const t=await(0,o.readLength)(e,8),r=t.readInt32BE(0)-8,n=t.slice(4).toString(),i=await(0,o.readLength)(e,r);yield{header:t,length:r,type:n,data:i}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.readLength=async function(e,t){if(!t)return Buffer.alloc(0);{const r=e.read(t);if(r)return r}return new Promise((r,n)=>{const o=()=>{const n=e.read(t);n&&(s(),r(n))},i=()=>{s(),n(new Error(`stream ended during read for minimum ${t} bytes`))},s=()=>{e.removeListener("readable",o),e.removeListener("end",i)};e.on("readable",o),e.on("end",i)})}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AutoenableMixinProvider=void 0;var n=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if(Object.prototype.hasOwnProperty.call(e,i)){var s=n?Object.getOwnPropertyDescriptor(e,i):null;s&&(s.get||s.set)?Object.defineProperty(r,i,s):r[i]=e[i]}r.default=e,t&&t.set(e,r);return r}(r(0));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}const{systemManager:i}=n.default;class s extends n.ScryptedDeviceBase{constructor(e){var t,r,o;super(e),o={},(r="hasEnabledMixin")in(t=this)?Object.defineProperty(t,r,{value:o,enumerable:!0,configurable:!0,writable:!0}):t[r]=o;try{this.hasEnabledMixin=JSON.parse(this.storage.getItem("hasEnabledMixin"))}catch(e){this.hasEnabledMixin={}}this.pluginsComponent=i.getComponent("plugins"),i.listen(async(e,t,r)=>{t.eventInterface!==n.ScryptedInterface.ScryptedDevice||t.property||this.maybeEnableMixin(e)});for(const e of Object.keys(i.getSystemState())){const t=i.getDeviceById(e);this.maybeEnableMixin(t)}}async maybeEnableMixin(e){var t;if(!e||null!==(t=e.mixins)&&void 0!==t&&t.includes(this.id))return;if(this.hasEnabledMixin[e.id])return;if(!await this.canMixin(e.type,e.interfaces))return;this.log.i("auto enabling mixin for "+e.name);const r=e.mixins||[];r.push(this.id);const n=await this.pluginsComponent;await n.setMixins(e.id,r)}setHasEnabledMixin(e){this.hasEnabledMixin[e]||(this.hasEnabledMixin[e]=!0,this.storage.setItem("hasEnabledMixin",JSON.stringify(this.hasEnabledMixin)))}}t.AutoenableMixinProvider=s}]));
1
+ !function(e,t){for(var r in t)e[r]=t[r]}(window,function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=6)}([function(e,t,r){"use strict";var n=Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]},o=function(e,t){for(var r in e)"default"===r||Object.prototype.hasOwnProperty.call(t,r)||n(t,e,r)};Object.defineProperty(t,"__esModule",{value:!0}),t.MixinDeviceBase=t.ScryptedDeviceBase=void 0,o(r(2),t);const i=r(2);class s{constructor(e){this.nativeId=e}get storage(){return this._storage||(this._storage=deviceManager.getDeviceStorage(this.nativeId)),this._storage}get log(){return this._log||(this._log=deviceManager.getDeviceLogger(this.nativeId)),this._log}get console(){return this._console||(this._console=deviceManager.getDeviceConsole(this.nativeId)),this._console}_lazyLoadDeviceState(){this._deviceState||(this.nativeId?this._deviceState=deviceManager.getDeviceState(this.nativeId):this._deviceState=deviceManager.getDeviceState())}onDeviceEvent(e,t){return deviceManager.onDeviceEvent(this.nativeId,e,t)}}t.ScryptedDeviceBase=s;class a{constructor(e,t,r,n){this.mixinDevice=e,this.mixinDeviceInterfaces=t,this.mixinProviderNativeId=n,this._deviceState=r}get storage(){return this._storage||(this._storage=deviceManager.getMixinStorage(this.id,this.mixinProviderNativeId)),this._storage}get console(){return this._console||(deviceManager.getMixinConsole?this._console=deviceManager.getMixinConsole(this.id,this.mixinProviderNativeId):this._console=deviceManager.getDeviceConsole(this.mixinProviderNativeId)),this._console}onDeviceEvent(e,t){return deviceManager.onMixinEvent(this.id,this.mixinProviderNativeId,e,t)}_lazyLoadDeviceState(){}release(){}}t.MixinDeviceBase=a,function(){function e(e){return function(){return this._lazyLoadDeviceState(),this._deviceState[e]}}function t(e){return function(t){this._lazyLoadDeviceState(),this._deviceState[e]=t}}for(var r of Object.values(i.ScryptedInterfaceProperty))Object.defineProperty(s.prototype,r,{set:t(r),get:e(r)}),Object.defineProperty(a.prototype,r,{set:t(r),get:e(r)})}();let d={};try{d=Object.assign(d,{log:deviceManager.getDeviceLogger(void 0),deviceManager:deviceManager,endpointManager:endpointManager,mediaManager:mediaManager,systemManager:systemManager,pluginHostAPI:pluginHostAPI})}catch(e){console.error("sdk initialization error, import @scrypted/sdk/types instead",e)}t.default=d},function(e,t){e.exports=require("events")},function(e,t,r){"use strict";let n,o,i,s,a,d,c,u;Object.defineProperty(t,"__esModule",{value:!0}),t.ScryptedInterfaceDescriptors=t.ScryptedMimeTypes=t.ScryptedInterfaceProperty=t.ScryptedInterface=t.MediaPlayerState=t.LockState=t.ThermostatMode=t.TemperatureUnit=t.ScryptedDeviceType=void 0,t.ScryptedDeviceType=n,function(e){e.Builtin="Builtin",e.Camera="Camera",e.Fan="Fan",e.Light="Light",e.Switch="Switch",e.Outlet="Outlet",e.Sensor="Sensor",e.Scene="Scene",e.Program="Program",e.Automation="Automation",e.Vacuum="Vacuum",e.Notifier="Notifier",e.Thermostat="Thermostat",e.Lock="Lock",e.PasswordControl="PasswordControl",e.Display="Display",e.Speaker="Speaker",e.Event="Event",e.Entry="Entry",e.Garage="Garage",e.DeviceProvider="DeviceProvider",e.DataSource="DataSource",e.API="API",e.Doorbell="Doorbell",e.Irrigation="Irrigation",e.Valve="Valve",e.Person="Person",e.Unknown="Unknown"}(n||(t.ScryptedDeviceType=n={})),t.TemperatureUnit=o,function(e){e.C="C",e.F="F"}(o||(t.TemperatureUnit=o={})),t.ThermostatMode=i,function(e){e.Off="Off",e.Cool="Cool",e.Heat="Heat",e.HeatCool="HeatCool",e.Auto="Auto",e.FanOnly="FanOnly",e.Purifier="Purifier",e.Eco="Eco",e.Dry="Dry",e.On="On"}(i||(t.ThermostatMode=i={})),t.LockState=s,function(e){e.Locked="Locked",e.Unlocked="Unlocked",e.Jammed="Jammed"}(s||(t.LockState=s={})),t.MediaPlayerState=a,function(e){e.Idle="Idle",e.Playing="Playing",e.Paused="Paused",e.Buffering="Buffering"}(a||(t.MediaPlayerState=a={})),t.ScryptedInterface=d,function(e){e.ScryptedDevice="ScryptedDevice",e.OnOff="OnOff",e.Brightness="Brightness",e.ColorSettingTemperature="ColorSettingTemperature",e.ColorSettingRgb="ColorSettingRgb",e.ColorSettingHsv="ColorSettingHsv",e.Notifier="Notifier",e.StartStop="StartStop",e.Pause="Pause",e.Dock="Dock",e.TemperatureSetting="TemperatureSetting",e.Thermometer="Thermometer",e.HumiditySensor="HumiditySensor",e.Camera="Camera",e.VideoCamera="VideoCamera",e.Intercom="Intercom",e.Lock="Lock",e.PasswordStore="PasswordStore",e.Authenticator="Authenticator",e.Scene="Scene",e.Entry="Entry",e.EntrySensor="EntrySensor",e.DeviceProvider="DeviceProvider",e.Battery="Battery",e.Refresh="Refresh",e.MediaPlayer="MediaPlayer",e.Online="Online",e.SoftwareUpdate="SoftwareUpdate",e.BufferConverter="BufferConverter",e.Settings="Settings",e.BinarySensor="BinarySensor",e.IntrusionSensor="IntrusionSensor",e.PowerSensor="PowerSensor",e.AudioSensor="AudioSensor",e.MotionSensor="MotionSensor",e.OccupancySensor="OccupancySensor",e.FloodSensor="FloodSensor",e.UltravioletSensor="UltravioletSensor",e.LuminanceSensor="LuminanceSensor",e.PositionSensor="PositionSensor",e.MediaSource="MediaSource",e.MessagingEndpoint="MessagingEndpoint",e.OauthClient="OauthClient",e.MixinProvider="MixinProvider",e.HttpRequestHandler="HttpRequestHandler",e.EngineIOHandler="EngineIOHandler",e.PushHandler="PushHandler",e.Program="Program",e.Scriptable="Scriptable",e.ObjectDetector="ObjectDetector"}(d||(t.ScryptedInterface=d={})),t.ScryptedInterfaceProperty=c,function(e){e.id="id",e.interfaces="interfaces",e.mixins="mixins",e.info="info",e.name="name",e.providedInterfaces="providedInterfaces",e.providedName="providedName",e.providedRoom="providedRoom",e.providedType="providedType",e.providerId="providerId",e.room="room",e.type="type",e.on="on",e.brightness="brightness",e.colorTemperature="colorTemperature",e.rgb="rgb",e.hsv="hsv",e.running="running",e.paused="paused",e.docked="docked",e.thermostatAvailableModes="thermostatAvailableModes",e.thermostatMode="thermostatMode",e.thermostatSetpoint="thermostatSetpoint",e.thermostatSetpointHigh="thermostatSetpointHigh",e.thermostatSetpointLow="thermostatSetpointLow",e.temperature="temperature",e.temperatureUnit="temperatureUnit",e.humidity="humidity",e.lockState="lockState",e.entryOpen="entryOpen",e.batteryLevel="batteryLevel",e.online="online",e.updateAvailable="updateAvailable",e.fromMimeType="fromMimeType",e.toMimeType="toMimeType",e.binaryState="binaryState",e.intrusionDetected="intrusionDetected",e.powerDetected="powerDetected",e.motionDetected="motionDetected",e.audioDetected="audioDetected",e.occupied="occupied",e.flooded="flooded",e.ultraviolet="ultraviolet",e.luminance="luminance",e.position="position"}(c||(t.ScryptedInterfaceProperty=c={})),t.ScryptedMimeTypes=u,function(e){e.AcceptUrlParameter="accept-url",e.Url="text/x-uri",e.InsecureLocalUrl="text/x-insecure-local-uri",e.LocalUrl="text/x-local-uri",e.PushEndpoint="text/x-push-endpoint",e.FFmpegInput="x-scrypted/x-ffmpeg-input",e.RTCAVOffer="x-scrypted/x-rtc-av-offer",e.RTCAVAnswer="x-scrypted/x-rtc-av-answer"}(u||(t.ScryptedMimeTypes=u={}));t.ScryptedInterfaceDescriptors={ScryptedDevice:{name:"ScryptedDevice",properties:["id","interfaces","mixins","info","name","providedInterfaces","providedName","providedRoom","providedType","providerId","room","type"],methods:["listen","setName","setRoom","setType"]},OnOff:{name:"OnOff",properties:["on"],methods:["turnOff","turnOn"]},Brightness:{name:"Brightness",properties:["brightness"],methods:["setBrightness"]},ColorSettingTemperature:{name:"ColorSettingTemperature",properties:["colorTemperature"],methods:["getTemperatureMaxK","getTemperatureMinK","setColorTemperature"]},ColorSettingRgb:{name:"ColorSettingRgb",properties:["rgb"],methods:["setRgb"]},ColorSettingHsv:{name:"ColorSettingHsv",properties:["hsv"],methods:["setHsv"]},Notifier:{name:"Notifier",properties:[],methods:["sendNotification"]},StartStop:{name:"StartStop",properties:["running"],methods:["start","stop"]},Pause:{name:"Pause",properties:["paused"],methods:["pause","resume"]},Dock:{name:"Dock",properties:["docked"],methods:["dock"]},TemperatureSetting:{name:"TemperatureSetting",properties:["thermostatAvailableModes","thermostatMode","thermostatSetpoint","thermostatSetpointHigh","thermostatSetpointLow"],methods:["setThermostatMode","setThermostatSetpoint","setThermostatSetpointHigh","setThermostatSetpointLow"]},Thermometer:{name:"Thermometer",properties:["temperature","temperatureUnit"],methods:[]},HumiditySensor:{name:"HumiditySensor",properties:["humidity"],methods:[]},Camera:{name:"Camera",properties:[],methods:["takePicture"]},VideoCamera:{name:"VideoCamera",properties:[],methods:["getVideoStream","getVideoStreamOptions"]},Intercom:{name:"Intercom",properties:[],methods:["startIntercom","stopIntercom"]},Lock:{name:"Lock",properties:["lockState"],methods:["lock","unlock"]},PasswordStore:{name:"PasswordStore",properties:[],methods:["addPassword","getPasswords","removePassword"]},Authenticator:{name:"Authenticator",properties:[],methods:["checkPassword"]},Scene:{name:"Scene",properties:[],methods:["activate","deactivate","isReversible"]},Entry:{name:"Entry",properties:[],methods:["closeEntry","openEntry"]},EntrySensor:{name:"EntrySensor",properties:["entryOpen"],methods:[]},DeviceProvider:{name:"DeviceProvider",properties:[],methods:["discoverDevices","getDevice"]},Battery:{name:"Battery",properties:["batteryLevel"],methods:[]},Refresh:{name:"Refresh",properties:[],methods:["getRefreshFrequency","refresh"]},MediaPlayer:{name:"MediaPlayer",properties:[],methods:["getMediaStatus","load","seek","skipNext","skipPrevious"]},Online:{name:"Online",properties:["online"],methods:[]},SoftwareUpdate:{name:"SoftwareUpdate",properties:["updateAvailable"],methods:["checkForUpdate","installUpdate"]},BufferConverter:{name:"BufferConverter",properties:["fromMimeType","toMimeType"],methods:["convert"]},Settings:{name:"Settings",properties:[],methods:["getSettings","putSetting"]},BinarySensor:{name:"BinarySensor",properties:["binaryState"],methods:[]},IntrusionSensor:{name:"IntrusionSensor",properties:["intrusionDetected"],methods:[]},PowerSensor:{name:"PowerSensor",properties:["powerDetected"],methods:[]},AudioSensor:{name:"AudioSensor",properties:["audioDetected"],methods:[]},MotionSensor:{name:"MotionSensor",properties:["motionDetected"],methods:[]},OccupancySensor:{name:"OccupancySensor",properties:["occupied"],methods:[]},FloodSensor:{name:"FloodSensor",properties:["flooded"],methods:[]},UltravioletSensor:{name:"UltravioletSensor",properties:["ultraviolet"],methods:[]},LuminanceSensor:{name:"LuminanceSensor",properties:["luminance"],methods:[]},PositionSensor:{name:"PositionSensor",properties:["position"],methods:[]},MediaSource:{name:"MediaSource",properties:[],methods:["getMedia"]},MessagingEndpoint:{name:"MessagingEndpoint",properties:[],methods:[]},OauthClient:{name:"OauthClient",properties:[],methods:["getOauthUrl","onOauthCallback"]},MixinProvider:{name:"MixinProvider",properties:[],methods:["canMixin","getMixin","releaseMixin"]},HttpRequestHandler:{name:"HttpRequestHandler",properties:[],methods:["onRequest"]},EngineIOHandler:{name:"EngineIOHandler",properties:[],methods:["onConnection"]},PushHandler:{name:"PushHandler",properties:[],methods:["onPush"]},Program:{name:"Program",properties:[],methods:["run"]},Scriptable:{name:"Scriptable",properties:[],methods:["saveScript","loadScripts","eval"]},ObjectDetector:{name:"ObjectDetector",properties:[],methods:["getDetectionInput","getObjectTypes"]}}},function(e,t){e.exports=require("net")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.listenZeroCluster=async function(e){for(;;){const t=1e4+Math.round(3e4*Math.random());e.listen(t);try{return await(0,n.once)(e,"listening"),e.address().port}catch(e){}}};var n=r(1)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(10);Object.keys(n).forEach((function(e){"default"!==e&&"__esModule"!==e&&(e in t&&t[e]===n[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return n[e]}}))}))},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n,o=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=m();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(r(0)),i=r(3),s=r(4),a=(n=r(1))&&n.__esModule?n:{default:n},d=r(7),c=r(8),u=r(5),p=r(11),l=r(13);function m(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return m=function(){return e},e}function f(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}const{mediaManager:h,log:g,systemManager:v,deviceManager:y}=o.default;class S extends d.SettingsMixinDeviceBase{constructor(e,t,r,n){super(e,r,{providerNativeId:n,mixinDeviceInterfaces:t,group:"Rebroadcast and Prebuffer Settings",groupKey:"prebuffer"}),f(this,"prebuffers",{mp4:[],mpegts:[]}),f(this,"events",new a.default),f(this,"released",!1),f(this,"detectedIdrInterval",0),f(this,"prevIdr",0),f(this,"unexpectedPCM",!1),this.console.log("prebuffer session starting in 10 seconds"),setTimeout(()=>this.ensurePrebufferSession(),1e4)}async getMixinSettings(){var e,t,r,n,o,i,s;const a=[];return a.push({title:"Prebuffer Duration",description:"Duration of the prebuffer in milliseconds.",type:"number",key:"prebufferDuration",value:this.storage.getItem("prebufferDuration")||15e3.toString()},{title:"Start at Previous Keyframe",description:"Start live streams from the previous key frame. Improves startup time.",type:"boolean",key:"sendKeyframe",value:("false"!==this.storage.getItem("sendKeyframe")).toString()},{title:"Reencode Audio",description:"Reencode the audio (necessary if camera outputs PCM).",type:"boolean",key:"reencodeAudio",value:("true"===this.storage.getItem("reencodeAudio")).toString()},{group:"Media Information",title:"Detected Resolution",readonly:!0,key:"detectedAcodec",value:""+((null===(e=this.session)||void 0===e||null===(t=e.inputVideoResolution)||void 0===t?void 0:t[0])||"unknown")},{group:"Media Information",title:"Detected Video/Audio Codecs",readonly:!0,key:"detectedVcodec",value:((null===(r=this.session)||void 0===r||null===(n=r.inputVideoCodec)||void 0===n?void 0:n.toString())||"unknown")+"/"+((null===(o=this.session)||void 0===o||null===(i=o.inputAudioCodec)||void 0===i?void 0:i.toString())||"unknown")},{group:"Media Information",title:"Detected Keyframe Interval",description:"Currently detected keyframe interval. This value may vary based on the stream behavior.",readonly:!0,key:"detectedIdr",value:(null===(s=this.detectedIdrInterval)||void 0===s?void 0:s.toString())||"none"}),a}async putMixinSetting(e,t){var r;this.storage.setItem(e,t.toString()),null===(r=this.prebufferSession)||void 0===r||r.then(e=>e.kill())}ensurePrebufferSession(){this.prebufferSession||this.released||(console.log("prebuffer session started"),this.prebufferSession=this.startPrebufferSession())}async startPrebufferSession(){this.prebuffers.mp4=[],this.prebuffers.mpegts=[];const e=parseInt(this.storage.getItem("prebufferDuration"))||15e3,t=JSON.parse((await h.convertMediaObjectToBuffer(await this.mixinDevice.getVideoStream(),o.ScryptedMimeTypes.FFmpegInput)).toString()),r="true"===this.storage.getItem("reencodeAudio")||this.unexpectedPCM,n=await(0,u.probeVideoCamera)(this.mixinDevice);let i;i=n.noAudio?["-an"]:r?[]:["-acodec","copy"];const s=["-vcodec","copy"],a=await(0,c.startRebroadcastSession)(t,{console:this.console,parsers:{mp4:(0,p.createFragmentedMp4Parser)({vcodec:s,acodec:i}),mpegts:(0,p.createMpegTsParser)({vcodec:s,acodec:i})}});this.session=a,this.session.inputAudioCodec?"aac"!==this.session.inputAudioCodec&&(this.console.error("Detected audio codec was not AAC."),n.noAudio||!a.inputAudioCodec||-1===a.inputAudioCodec.indexOf("pcm")||r||(g.a(this.name+" is using PCM audio and will be reencoded. Enable Reencode Audio in Rebroadcast Settings to disable this alert."),this.unexpectedPCM=!0)):this.console.warn("no audio detected."),"h264"!==this.session.inputVideoCodec&&this.console.error("video codec is not h264. If there are errors, try changing your camera's encoder output."),a.events.on("killed",()=>{this.prebufferSession=void 0});for(const t of["mpegts","mp4"]){const r=t+"-data";let n=this.prebuffers[t],o=0;a.events.on(r,i=>{const s=Date.now();for("mdat"===i.type&&(this.prevIdr&&(this.detectedIdrInterval=s-this.prevIdr),this.prevIdr=s),n.push({time:s,chunk:i});n.length&&n[0].time<s-e;)n.shift(),o++;o>1e3&&(n=this.prebuffers[t]=n.slice(),o=0),this.events.emit(r,i)})}return a.events.on("mp4-data",()=>{clearTimeout(void 0),setTimeout(()=>{this.console.error("watchdog for mp4 parser timed out... killing ffmpeg session"),a.kill()},3e4)}),a.events.once("killed",()=>clearTimeout(void 0)),a}async getVideoStream(e){var t;this.ensurePrebufferSession();const r=await this.prebufferSession;if(null!=e&&e.id&&e.id!==(null===(t=r.ffmpegInputs.mpegts.mediaStreamOptions)||void 0===t?void 0:t.id))return this.console.log("rebroadcast session cant be used here",e),this.mixinDevice.getVideoStream(e);const n="false"!==this.storage.getItem("sendKeyframe");if(!(null!=e&&e.prebuffer||n)){return h.createFFmpegMediaObject(r.ffmpegInputs.mpegts)}this.console.log("prebuffer request started");const o=(null==e?void 0:e.container)||"mpegts",a=o+"-data",d=this.prebuffers[o],c=new i.Server(t=>{c.close();const r=(null==e?void 0:e.prebuffer)||(n?1.5*Math.max(4e3,this.detectedIdrInterval||4e3):0),o=Date.now();let i,s=!0;const u=e=>{s&&(s=!1,e.startStream&&t.write(e.startStream));for(const r of e.chunks)t.write(r)};for(const e of d)e.time<o-r||u(e.chunk);this.events.on(a,u),i=()=>{this.console.log("prebuffer request ended"),this.events.removeListener(a,u),this.events.removeListener("killed",i),t.removeAllListeners(),t.destroy()},this.events.once("killed",i),t.once("end",i),t.once("close",i),t.once("error",i)});setTimeout(()=>c.close(),3e4);const u=await(0,s.listenZeroCluster)(c),p=r.ffmpegInputs[o].mediaStreamOptions?Object.assign({},r.ffmpegInputs[o].mediaStreamOptions):void 0;if(p&&p.audio){"true"===this.storage.getItem("reencodeAudio")&&(p.audio={codec:"aac"})}p.video&&Object.assign(p.video,{width:parseInt(this.session.inputVideoResolution[2]),height:parseInt(this.session.inputVideoResolution[3])});const l={inputArguments:["-f",o,"-i","tcp://127.0.0.1:"+u],mediaStreamOptions:p};this.console.log("prebuffer ffmpeg input",l.inputArguments[3]);return h.createFFmpegMediaObject(l)}async getVideoStreamOptions(){const e=await this.mixinDevice.getVideoStreamOptions()||[];let t=e[0];return t||(t={},e.push(t)),t.prebuffer=parseInt(this.storage.getItem("prebufferDuration"))||15e3,e}release(){var e;this.console.log("prebuffer releasing if started"),this.released=!0,null===(e=this.prebufferSession)||void 0===e||e.then(e=>{this.console.log("prebuffer released"),e.kill()})}}class b extends l.AutoenableMixinProvider{constructor(e){super(e);for(const e of Object.keys(v.getSystemState())){var t;const r=v.getDeviceById(e);null!==(t=r.mixins)&&void 0!==t&&t.includes(this.id)&&r.getVideoStreamOptions()}const r=function(){var e=new Date;return e.setHours(24),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0),e.getTime()-(new Date).getTime()}()+72e5;this.log.i(`Rebroadcaster scheduled for restart at 2AM: ${Math.round(r/1e3/60)} minutes`),setTimeout(()=>y.requestRestart(),r)}async canMixin(e,t){return t.includes(o.ScryptedInterface.VideoCamera)?[o.ScryptedInterface.VideoCamera,o.ScryptedInterface.Settings]:null}async getMixin(e,t,r){return this.setHasEnabledMixin(r.id),new S(e,t,r,this.nativeId)}async releaseMixin(e,t){t.release()}}var M=new b;t.default=M},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SettingsMixinDeviceBase=void 0;var n=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if(Object.prototype.hasOwnProperty.call(e,i)){var s=n?Object.getOwnPropertyDescriptor(e,i):null;s&&(s.get||s.set)?Object.defineProperty(r,i,s):r[i]=e[i]}r.default=e,t&&t.set(e,r);return r}(r(0));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}const{deviceManager:i}=n.default;class s extends n.MixinDeviceBase{constructor(e,t,r){super(e,r.mixinDeviceInterfaces,t,r.providerNativeId),this.settingsGroup=r.group,this.settingsGroupKey=r.groupKey}async getSettings(){const e=(this.mixinDeviceInterfaces.includes(n.ScryptedInterface.Settings)?await this.mixinDevice.getSettings():[])||[],t=await this.getMixinSettings();for(const e of t)e.group=e.group||this.settingsGroup,e.key=this.settingsGroupKey+":"+e.key;return e.push(...t),e}async putSetting(e,t){var r;const o=this.settingsGroupKey+":";if(null==e||!e.startsWith(o))return this.mixinDevice.putSetting(e,t);await this.putMixinSetting(e.substring(o.length),t),null===(r=i.onMixinEvent)||void 0===r||r.call(i,this.id,this.mixinProviderNativeId,n.ScryptedInterface.Settings,null)}}t.SettingsMixinDeviceBase=s},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parseResolution=p,t.parseVideoCodec=m,t.parseAudioCodec=f,t.startRebroadcastSession=async function(e,t){let r,a=0,c=!0;const l=new s.EventEmitter,{console:h}=t;let g,v,y;function S(){c&&l.emit("killed"),c=!1,null==x||x.kill();for(const e of O)null==e||e.close()}function b(){t.timeout&&(clearTimeout(r),r=setTimeout(S,t.timeout))}b();const M={},P=e.inputArguments.slice(),O=[];let w;const I=new Promise(e=>w=e);for(const o of Object.keys(t.parsers)){const s=t.parsers[o],d=o+"-data",c=(0,n.createServer)(e=>{a++,h.log("rebroadcast client",a),clearTimeout(r);let t=!0;const n=r=>{t&&(t=!1,r.startStream&&e.write(r.startStream)),e.write(r.chunk)},o=()=>{e.removeAllListeners(),l.removeListener(d,n),a--,0===a&&b(),e.destroy()};l.on(d,n),e.on("end",o),e.on("close",o),e.on("error",o)});O.push(c);const u=await(0,i.listenZeroCluster)(c);M[o]={inputArguments:["-f",o,"-i","tcp://127.0.0.1:"+u],mediaStreamOptions:e.mediaStreamOptions};const p=(0,n.createServer)(async e=>{p.close(),w(e);try{const n=o+"-data";for await(const o of s.parse(e,parseInt(null===(t=y)||void 0===t?void 0:t[2]),parseInt(null===(r=y)||void 0===r?void 0:r[3]))){var t,r;l.emit(n,o)}}catch(e){h.error("rebroadcast parse error",e),S()}});O.push(p);const m=await(0,i.listenZeroCluster)(p);P.push(...s.outputArguments,"tcp://127.0.0.1:"+m)}P.unshift("-hide_banner"),h.log(P);const x=o.default.spawn(await u.getFFmpegPath(),P);return(0,d.ffmpegLogInitialOutput)(h,x),x.on("exit",S),f(x).then(e=>g=e),m(x).then(e=>v=e),p(x).then(e=>y=e),await I,{inputAudioCodec:g,inputVideoCodec:v,inputVideoResolution:y,events:l,resetActivityTimer:b,isActive:()=>c,kill:S,servers:O,cp:x,ffmpegInputs:M}};var n=r(3),o=c(r(9)),i=r(4),s=r(1),a=c(r(0)),d=r(5);function c(e){return e&&e.__esModule?e:{default:e}}const{mediaManager:u}=a.default;async function p(e){return new Promise(t=>{const r=n=>{const o=n.toString(),i=/(([0-9]{2,5})x([0-9]{2,5}))/.exec(o);i&&(e.stdout.removeListener("data",r),e.stderr.removeListener("data",r),t(i))};e.stdout.on("data",r),e.stderr.on("data",r)})}async function l(e,t){return new Promise(r=>{const n=o=>{const i=o.toString(),s=i.indexOf(t+": ");if(-1!==s){const o=i.substring(s+t.length+1).trim();let a=o.indexOf(" ");const d=o.indexOf(",");-1!==a&&d<a&&(a=d),-1!==a&&(e.stdout.removeListener("data",n),e.stderr.removeListener("data",n),r(o.substring(0,a)))}};e.stdout.on("data",n),e.stderr.on("data",n)})}async function m(e){return l(e,"Video")}async function f(e){return l(e,"Audio")}},function(e,t){e.exports=require("child_process")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ffmpegLogInitialOutput=function(e,t,r){var o,i;function s(e){const o=i=>{const s=i.toString();for(const e of n)if(-1!==s.indexOf(e))return;if(!r&&(-1!==s.indexOf("frame=")||-1!==s.indexOf("size=")))return e(s),e("video/audio detected, discarding further input"),t.stdout.removeListener("data",o),void t.stderr.removeListener("data",o);e(s)};return o}null===(o=t.stdout)||void 0===o||o.on("data",s(e.log)),null===(i=t.stderr)||void 0===i||i.on("data",s(e.error)),t.on("exit",()=>e.log("ffmpeg exited"))},t.probeVideoCamera=async function(e){let t;try{t=await e.getVideoStreamOptions()||[]}catch(e){}const r=t&&t.length&&null===t[0].audio;return{options:t,noAudio:r}};const n=["decode_slice_header error","no frame!","non-existing PPS"]},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.createMpegTsParser=function(e){return{container:"mpegts",outputArguments:["-f","mpegts",...(null==e?void 0:e.vcodec)||[],...(null==e?void 0:e.acodec)||[]],async*parse(e){let t=[],r=0;for(;;){const o=e.read();if(!o){await(0,n.once)(e,"readable");continue}if(t.push(o),r+=o.length,r<188)continue;const i=Buffer.concat(t);if(71!=i[0])throw new Error("Invalid sync byte in mpeg-ts packet. Terminating stream.");const s=i.length%188,a=i.slice(0,i.length-s),d=i.slice(i.length-s);t=[d],r=d.length,yield{chunks:[a]}}}}},t.parseFragmentedMP4=i,t.createFragmentedMp4Parser=function(e){return{container:"mp4",outputArguments:["-f","mp4",...(null==e?void 0:e.vcodec)||[],...(null==e?void 0:e.acodec)||[],"-movflags","frag_keyframe+empty_moov+default_base_moof"],async*parse(e){const t=i(e);let r,n,o;for await(const e of t)r?n||(n=e):r=e,yield{startStream:o,chunks:[e.header,e.data],type:e.type},r&&n&&!o&&(o=Buffer.concat([r.header,r.data,n.header,n.data]))}}},t.createRawVideoParser=function(e){let t;e=e||{};const{size:r,everyNFrames:n}=e;r&&(t=`scale=${r.width}:${r.height}`);n&&n>1&&(t?t+=",":t="",t+=`select=not(mod(n\\,${n}))`);return{container:"rawvideo",outputArguments:[...t?["-vf",t]:[],"-an","-vcodec","rawvideo","-pix_fmt","yuv420p","-f","rawvideo"],async*parse(e,t,n){if(!t||!n)throw new Error("error parsing rawvideo, unknown width and height");const i=(t=(null==r?void 0:r.width)||t)*(n=(null==r?void 0:r.height)||n)*1.5;for(;;){const r=await(0,o.readLength)(e,i);yield{chunks:[r],width:t,height:n}}}}};var n=r(1),o=r(12);async function*i(e){for(;;){const t=await(0,o.readLength)(e,8),r=t.readInt32BE(0)-8,n=t.slice(4).toString(),i=await(0,o.readLength)(e,r);yield{header:t,length:r,type:n,data:i}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.readLength=async function(e,t){if(!t)return Buffer.alloc(0);{const r=e.read(t);if(r)return r}return new Promise((r,n)=>{const o=()=>{const n=e.read(t);n&&(s(),r(n))},i=()=>{s(),n(new Error(`stream ended during read for minimum ${t} bytes`))},s=()=>{e.removeListener("readable",o),e.removeListener("end",i)};e.on("readable",o),e.on("end",i)})}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.AutoenableMixinProvider=void 0;var n=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=o();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if(Object.prototype.hasOwnProperty.call(e,i)){var s=n?Object.getOwnPropertyDescriptor(e,i):null;s&&(s.get||s.set)?Object.defineProperty(r,i,s):r[i]=e[i]}r.default=e,t&&t.set(e,r);return r}(r(0));function o(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return o=function(){return e},e}const{systemManager:i}=n.default;class s extends n.ScryptedDeviceBase{constructor(e){var t,r,o;super(e),o={},(r="hasEnabledMixin")in(t=this)?Object.defineProperty(t,r,{value:o,enumerable:!0,configurable:!0,writable:!0}):t[r]=o;try{this.hasEnabledMixin=JSON.parse(this.storage.getItem("hasEnabledMixin"))}catch(e){this.hasEnabledMixin={}}this.pluginsComponent=i.getComponent("plugins"),i.listen(async(e,t,r)=>{t.eventInterface!==n.ScryptedInterface.ScryptedDevice||t.property||this.maybeEnableMixin(e)});for(const e of Object.keys(i.getSystemState())){const t=i.getDeviceById(e);this.maybeEnableMixin(t)}}async maybeEnableMixin(e){var t;if(!e||null!==(t=e.mixins)&&void 0!==t&&t.includes(this.id))return;if(this.hasEnabledMixin[e.id])return;if(!await this.canMixin(e.type,e.interfaces))return;this.log.i("auto enabling mixin for "+e.name);const r=e.mixins||[];r.push(this.id);const n=await this.pluginsComponent;await n.setMixins(e.id,r)}setHasEnabledMixin(e){this.hasEnabledMixin[e]||(this.hasEnabledMixin[e]=!0,this.storage.setItem("hasEnabledMixin",JSON.stringify(this.hasEnabledMixin)))}}t.AutoenableMixinProvider=s}]));
2
2
  //# sourceMappingURL=main.nodejs.js.map
package/dist/plugin.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrypted/prebuffer-mixin",
3
- "version": "0.1.51",
3
+ "version": "0.1.52",
4
4
  "description": "Rebroadcast and Prebuffer for VideoCameras.",
5
5
  "author": "Scrypted",
6
6
  "license": "Apache-2.0",
package/src/main.ts CHANGED
@@ -178,7 +178,8 @@ class PrebufferMixin extends SettingsMixinDeviceBase<VideoCamera> implements Vid
178
178
 
179
179
  for (const container of ['mpegts', 'mp4']) {
180
180
  const eventName = container + '-data';
181
- const prebufferContainer: PrebufferStreamChunk[] = this.prebuffers[container];
181
+ let prebufferContainer: PrebufferStreamChunk[] = this.prebuffers[container];
182
+ let shifts = 0;
182
183
 
183
184
  session.events.on(eventName, (chunk: StreamChunk) => {
184
185
  const now = Date.now();
@@ -196,12 +197,28 @@ class PrebufferMixin extends SettingsMixinDeviceBase<VideoCamera> implements Vid
196
197
 
197
198
  while (prebufferContainer.length && prebufferContainer[0].time < now - prebufferDurationMs) {
198
199
  prebufferContainer.shift();
200
+ shifts++;
201
+ }
202
+
203
+ if (shifts > 1000) {
204
+ prebufferContainer = this.prebuffers[container] = prebufferContainer.slice();
205
+ shifts = 0;
199
206
  }
200
207
 
201
208
  this.events.emit(eventName, chunk);
202
209
  });
203
210
  }
204
211
 
212
+ let watchdog: NodeJS.Timeout;
213
+ session.events.on('mp4-data', () => {
214
+ clearTimeout(watchdog);
215
+ setTimeout(() => {
216
+ this.console.error('watchdog for mp4 parser timed out... killing ffmpeg session');
217
+ session.kill();
218
+ }, 30000);
219
+ })
220
+ session.events.once('killed', () => clearTimeout(watchdog));
221
+
205
222
  return session;
206
223
  }
207
224
 
@@ -244,7 +261,9 @@ class PrebufferMixin extends SettingsMixinDeviceBase<VideoCamera> implements Vid
244
261
  socket.write(data.startStream)
245
262
  }
246
263
  }
247
- socket.write(data.chunk);
264
+ for (const chunk of data.chunks) {
265
+ socket.write(chunk);
266
+ }
248
267
  };
249
268
 
250
269
  for (const prebuffer of prebufferContainer) {