Merge branch 'main' of github.com:koush/scrypted

This commit is contained in:
Koushik Dutta
2023-04-22 21:27:54 -07:00
4 changed files with 87 additions and 24 deletions

View File

@@ -88,7 +88,10 @@ class CastDevice extends ScryptedDeviceBase implements MediaPlayer, Refresh, Eng
}
client.removeAllListeners();
client.close();
try {
client.close();
} catch (e) {
}
}
client.client.on('close', cleanup);
client.on('error', err => {
@@ -149,6 +152,14 @@ class CastDevice extends ScryptedDeviceBase implements MediaPlayer, Refresh, Eng
}
async load(media: string | MediaObject, options: MediaPlayerOptions) {
if (this.mediaPlayerPromise) {
try {
(await this.mediaPlayerPromise).close();
} catch (e) {
}
this.mediaPlayerPromise = undefined;
this.mediaPlayerStatus = undefined;
}
let url: string;
let urlMimeType: string;
@@ -341,15 +352,7 @@ class CastDevice extends ScryptedDeviceBase implements MediaPlayer, Refresh, Eng
});
})
player.getStatus((err, status) => {
if (err) {
reject(err);
return;
}
this.mediaPlayerStatus = status;
this.updateState();
resolve(player);
})
resolve(player);
});
});
});

View File

@@ -29,7 +29,7 @@ class ChromecastViewCameraExample implements StartStop {
}
async stop() {
device.running = false;
return chromecast.stop();
await chromecast.stop();
}
}

View File

@@ -58,11 +58,11 @@ class CoreMLPlugin(PredictPlugin, scrypted_sdk.BufferConverter, scrypted_sdk.Set
else:
out_dict = self.model.predict({'image': input, 'confidenceThreshold': self.minThreshold })
coordinatesList = out_dict['coordinates']
coordinatesList = out_dict['coordinates'].astype(float)
objs = []
for index, confidenceList in enumerate(out_dict['confidence']):
for index, confidenceList in enumerate(out_dict['confidence'].astype(float)):
values = confidenceList
maxConfidenceIndex = max(range(len(values)), key=values.__getitem__)
maxConfidence = confidenceList[maxConfidenceIndex]

View File

@@ -10,7 +10,7 @@ import { addTrackControls, parseSdp } from '@scrypted/common/src/sdp-utils';
import { SettingsMixinDeviceBase, SettingsMixinDeviceOptions } from "@scrypted/common/src/settings-mixin";
import { sleep } from '@scrypted/common/src/sleep';
import { createFragmentedMp4Parser, createMpegTsParser, StreamChunk, StreamParser } from '@scrypted/common/src/stream-parser';
import sdk, { BufferConverter, DeviceProvider, DeviceState, EventListenerRegister, FFmpegInput, H264Info, MediaObject, MediaStreamDestination, MediaStreamOptions, MixinProvider, RequestMediaStreamOptions, ResponseMediaStreamOptions, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera, VideoCameraConfiguration } from '@scrypted/sdk';
import sdk, { BufferConverter, ChargeState, DeviceBase, DeviceProvider, DeviceState, EventListenerRegister, FFmpegInput, H264Info, MediaObject, MediaStreamDestination, MediaStreamOptions, MixinProvider, RequestMediaStreamOptions, ResponseMediaStreamOptions, ScryptedDevice, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera, VideoCameraConfiguration } from '@scrypted/sdk';
import { StorageSettings } from '@scrypted/sdk/storage-settings';
import crypto from 'crypto';
import { once } from 'events';
@@ -105,7 +105,10 @@ class PrebufferSession {
rtspServerPath: string;
rtspServerMutedPath: string;
constructor(public mixin: PrebufferMixin, public advertisedMediaStreamOptions: ResponseMediaStreamOptions, public stopInactive: boolean) {
batteryListener: EventListenerRegister;
chargerListener: EventListenerRegister;
constructor(public mixin: PrebufferMixin, public advertisedMediaStreamOptions: ResponseMediaStreamOptions, public enabled: boolean, public forceBatteryPrebuffer: boolean) {
this.storage = mixin.storage;
this.console = mixin.console;
this.mixinDevice = mixin.mixinDevice;
@@ -129,6 +132,12 @@ class PrebufferSession {
this.rtspServerMutedPath = crypto.randomBytes(8).toString('hex');
this.storage.setItem(rtspServerMutedPathKey, this.rtspServerMutedPath);
}
this.handleChargingBatteryEvents();
}
get stopInactive() {
return !this.enabled || this.shouldDisableBatteryPrebuffer();
}
get canPrebuffer() {
@@ -206,6 +215,14 @@ class PrebufferSession {
parserSession.kill(new Error('rebroadcast disabled'));
this.clearPrebuffers();
});
if (this.batteryListener) {
this.batteryListener.removeListener();
this.batteryListener = null;
}
if (this.chargerListener) {
this.chargerListener.removeListener();
this.chargerListener = null;
}
}
ensurePrebufferSession() {
@@ -934,6 +951,46 @@ class PrebufferSession {
}, 10000);
}
handleChargingBatteryEvents() {
if (!this.mixin.interfaces.includes(ScryptedInterface.Charger) ||
!this.mixin.interfaces.includes(ScryptedInterface.Battery)) {
return;
}
const checkDisablePrebuffer = async () => {
if (this.stopInactive) {
this.console.log(this.streamName, 'low battery or not charging, prebuffering and rebroadcasting will only work on demand')
if (!this.activeClients && this.parserSessionPromise) {
this.console.log(this.streamName, 'terminating rebroadcast due to low battery or not charging')
const session = await this.parserSessionPromise;
session.kill(new Error('low battery or not charging'));
}
} else {
this.ensurePrebufferSession();
}
}
const id = this.mixin.id;
if (!this.batteryListener) {
this.batteryListener = systemManager.listenDevice(id, ScryptedInterface.Battery, () => checkDisablePrebuffer());
}
if (!this.chargerListener) {
this.chargerListener = systemManager.listenDevice(id, ScryptedInterface.Charger, () => checkDisablePrebuffer());
}
}
shouldDisableBatteryPrebuffer(): boolean | null {
if (!this.mixin.interfaces.includes(ScryptedInterface.Battery)) {
return null;
}
if (this.forceBatteryPrebuffer) {
return false;
}
const lowBattery = this.mixin.batteryLevel == null || this.mixin.batteryLevel < 20;
const hasCharger = this.mixin.interfaces.includes(ScryptedInterface.Charger);
return !hasCharger || lowBattery || this.mixin.chargeState !== ChargeState.Charging;
}
async handleRebroadcasterClient(options: {
findSyncFrame: boolean,
isActiveClient: boolean,
@@ -1497,8 +1554,6 @@ class PrebufferMixin extends SettingsMixinDeviceBase<VideoCamera> implements Vid
}
}
const isBatteryPowered = this.mixinDeviceInterfaces.includes(ScryptedInterface.Battery);
if (!enabledIds.length)
this.online = true;
@@ -1524,22 +1579,27 @@ class PrebufferMixin extends SettingsMixinDeviceBase<VideoCamera> implements Vid
}
const name = mso?.name;
const enabled = enabledIds.includes(id);
const stopInactive = (isBatteryPowered && !mso.allowBatteryPrebuffer) || !enabled;
session = new PrebufferSession(this, mso, stopInactive);
session = new PrebufferSession(this, mso, enabled, mso.allowBatteryPrebuffer);
this.sessions.set(id, session);
if (isBatteryPowered && !mso.allowBatteryPrebuffer) {
this.console.log('camera is battery powered, prebuffering and rebroadcasting will only work on demand.');
if (!enabled) {
this.console.log('stream', name, 'is not enabled and will be rebroadcast on demand.');
continue;
}
if (!enabled) {
this.console.log('stream', name, 'will be rebroadcast on demand.');
continue;
if (session.shouldDisableBatteryPrebuffer()) {
this.console.log('camera is battery powered and either not charging or on low battery, prebuffering and rebroadcasting will only work on demand.');
}
(async () => {
while (this.sessions.get(id) === session && !this.released) {
if (session.shouldDisableBatteryPrebuffer()) {
// since battery devices could be eligible for prebuffer, check periodically
// in the event the battery device becomes eligible again
await new Promise(resolve => setTimeout(resolve, 60000));
continue;
}
session.ensurePrebufferSession();
let wasActive = false;
try {