From 032fec4eb6d4e5eea37d1b1032ce87ccd942a4f2 Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Mon, 22 Aug 2022 09:02:27 -0700 Subject: [PATCH] cameras: fix event timeout, add debug event log --- plugins/amcrest/package-lock.json | 4 +-- plugins/amcrest/package.json | 2 +- plugins/hikvision/package-lock.json | 4 +-- plugins/hikvision/package.json | 2 +- plugins/hikvision/src/hikvision-camera-api.ts | 6 ++-- plugins/hikvision/src/main.ts | 32 ++++++++++++------- plugins/onvif/package-lock.json | 4 +-- plugins/onvif/package.json | 2 +- plugins/onvif/src/main.ts | 12 +++---- plugins/onvif/src/onvif-api.ts | 11 ++----- plugins/onvif/src/onvif-intercom.ts | 2 ++ plugins/rtsp/src/rtsp.ts | 17 +++++++++- 12 files changed, 60 insertions(+), 38 deletions(-) diff --git a/plugins/amcrest/package-lock.json b/plugins/amcrest/package-lock.json index bf81fb6ad..604eb23bc 100644 --- a/plugins/amcrest/package-lock.json +++ b/plugins/amcrest/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/amcrest", - "version": "0.0.105", + "version": "0.0.106", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/amcrest", - "version": "0.0.105", + "version": "0.0.106", "hasInstallScript": true, "license": "Apache", "dependencies": { diff --git a/plugins/amcrest/package.json b/plugins/amcrest/package.json index c4802e85d..7966d3063 100644 --- a/plugins/amcrest/package.json +++ b/plugins/amcrest/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/amcrest", - "version": "0.0.105", + "version": "0.0.106", "description": "Amcrest Plugin for Scrypted", "author": "Scrypted", "license": "Apache", diff --git a/plugins/hikvision/package-lock.json b/plugins/hikvision/package-lock.json index d532212e7..1f8b5e02b 100644 --- a/plugins/hikvision/package-lock.json +++ b/plugins/hikvision/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/hikvision", - "version": "0.0.96", + "version": "0.0.97", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/hikvision", - "version": "0.0.96", + "version": "0.0.97", "hasInstallScript": true, "license": "Apache", "dependencies": { diff --git a/plugins/hikvision/package.json b/plugins/hikvision/package.json index a353be793..5cc7a50b0 100644 --- a/plugins/hikvision/package.json +++ b/plugins/hikvision/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/hikvision", - "version": "0.0.96", + "version": "0.0.97", "description": "HikVision Plugin for Scrypted", "author": "Scrypted", "license": "Apache", diff --git a/plugins/hikvision/src/hikvision-camera-api.ts b/plugins/hikvision/src/hikvision-camera-api.ts index b1571569a..e370e1e04 100644 --- a/plugins/hikvision/src/hikvision-camera-api.ts +++ b/plugins/hikvision/src/hikvision-camera-api.ts @@ -111,7 +111,7 @@ export class HikVisionCameraAPI { if (!this.listenerPromise) { this.listenerPromise = new Promise(async (resolve, reject) => { const url = `http://${this.ip}/ISAPI/Event/notification/alertStream`; - this.console.log('listener url', url); + // this.console.log('listener url', url); const response = await this.digestAuth.request({ method: "GET", @@ -123,11 +123,11 @@ export class HikVisionCameraAPI { stream.on('data', (buffer: Buffer) => { const data = buffer.toString(); - // this.console.log(data); for (const event of Object.values(HikVisionCameraEvent)) { if (data.indexOf(event) !== -1) { const cameraNumber = data.match(/(.*?)(.*?)inactive') !== -1; + stream.emit('event', event, cameraNumber, inactive); } } }); diff --git a/plugins/hikvision/src/main.ts b/plugins/hikvision/src/main.ts index 3e3e410d6..4641dba3e 100644 --- a/plugins/hikvision/src/main.ts +++ b/plugins/hikvision/src/main.ts @@ -1,4 +1,4 @@ -import sdk, { MediaObject, Camera, ScryptedInterface } from "@scrypted/sdk"; +import sdk, { MediaObject, Camera, ScryptedInterface, Setting } from "@scrypted/sdk"; import { EventEmitter } from "stream"; import { HikVisionCameraAPI } from "./hikvision-camera-api"; import { Destroyable, UrlMediaStreamOptions, RtspProvider, RtspSmartCamera } from "../../rtsp/src/rtsp"; @@ -36,7 +36,7 @@ class HikVisionCamera extends RtspSmartCamera implements Camera { let ignoreCameraNumber: boolean; - events.on('event', async (event: HikVisionCameraEvent, cameraNumber: string) => { + events.on('event', async (event: HikVisionCameraEvent, cameraNumber: string, inactive: boolean) => { if (event === HikVisionCameraEvent.MotionDetected || event === HikVisionCameraEvent.LineDetection || event === HikVisionCameraEvent.FieldDetection) { @@ -75,7 +75,7 @@ class HikVisionCamera extends RtspSmartCamera implements Camera { // this.console.error('### Detected motion, camera: ', cameraNumber); this.motionDetected = true; clearTimeout(motionTimeout); - motionTimeout = setTimeout(() => this.motionDetected = false, 30000); + motionTimeout = setTimeout(() => this.motionDetected = false, inactive ? 5000 : 30000); } }) @@ -97,9 +97,26 @@ class HikVisionCamera extends RtspSmartCamera implements Camera { return mediaManager.createMediaObject(await api.jpegSnapshot(this.getRtspChannel()), 'image/jpeg'); } - async getUrlSettings() { + async getRtspUrlSettings(): Promise { + const ret = await super.getRtspUrlSettings(); + + ret.push( + { + group: 'Advanced', + key: 'rtspUrlParams', + title: 'RTSP URL Parameters Override', + description: "Optional: Override the RTSP URL parameters. E.g.: ?transportmode=unicast", + placeholder: this.getRtspUrlParams(), + value: this.storage.getItem('rtspUrlParams'), + }, + ); + return ret; + } + + async getUrlSettings(): Promise { return [ { + group: 'Advanced', key: 'rtspChannel', title: 'Channel Number', description: "Optional: The channel number to use for snapshots. E.g., 101, 201, etc. The camera portion, e.g., 1, 2, etc, will be used to construct the RTSP stream.", @@ -107,13 +124,6 @@ class HikVisionCamera extends RtspSmartCamera implements Camera { value: this.storage.getItem('rtspChannel'), }, ...await super.getUrlSettings(), - { - key: 'rtspUrlParams', - title: 'RTSP URL Parameters Override', - description: "Optional: Override the RTSP URL parameters. E.g.: ?transportmode=unicast", - placeholder: this.getRtspUrlParams(), - value: this.storage.getItem('rtspUrlParams'), - }, ] } diff --git a/plugins/onvif/package-lock.json b/plugins/onvif/package-lock.json index 6421ff776..0b475e3ba 100644 --- a/plugins/onvif/package-lock.json +++ b/plugins/onvif/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/onvif", - "version": "0.0.93", + "version": "0.0.94", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/onvif", - "version": "0.0.93", + "version": "0.0.94", "license": "Apache", "dependencies": { "@koush/axios-digest-auth": "^0.8.5", diff --git a/plugins/onvif/package.json b/plugins/onvif/package.json index 9c4e38480..b7e1d9b18 100644 --- a/plugins/onvif/package.json +++ b/plugins/onvif/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/onvif", - "version": "0.0.93", + "version": "0.0.94", "description": "ONVIF Camera Plugin for Scrypted", "author": "Scrypted", "license": "Apache", diff --git a/plugins/onvif/src/main.ts b/plugins/onvif/src/main.ts index c9c468c46..4701e1c86 100644 --- a/plugins/onvif/src/main.ts +++ b/plugins/onvif/src/main.ts @@ -1,9 +1,9 @@ -import sdk, { MediaObject, ScryptedInterface, Setting, ScryptedDeviceType, PictureOptions, VideoCamera, DeviceDiscovery, ObjectDetector, ObjectDetectionTypes, ObjectsDetected, Settings, Intercom, SettingValue } from "@scrypted/sdk"; -import { EventEmitter, Stream } from "stream"; -import { RtspSmartCamera, RtspProvider, Destroyable, UrlMediaStreamOptions } from "../../rtsp/src/rtsp"; -import { connectCameraAPI, OnvifCameraAPI, OnvifEvent } from "./onvif-api"; -import xml2js from 'xml2js'; +import sdk, { DeviceDiscovery, Intercom, MediaObject, ObjectDetectionTypes, ObjectDetector, ObjectsDetected, PictureOptions, ScryptedDeviceType, ScryptedInterface, Setting, Settings, SettingValue, VideoCamera } from "@scrypted/sdk"; import onvif from 'onvif'; +import { Stream } from "stream"; +import xml2js from 'xml2js'; +import { Destroyable, RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp"; +import { connectCameraAPI, OnvifCameraAPI, OnvifEvent } from "./onvif-api"; import { OnvifIntercom } from "./onvif-intercom"; const { mediaManager, systemManager, deviceManager } = sdk; @@ -224,7 +224,7 @@ class OnvifCamera extends RtspSmartCamera implements ObjectDetector, Intercom { } createClient() { - return connectCameraAPI(this.getHttpAddress(), this.getUsername(), this.getPassword(), this.console, this.storage.getItem('onvifDoorbellEvent'), !!this.storage.getItem('debug')); + return connectCameraAPI(this.getHttpAddress(), this.getUsername(), this.getPassword(), this.console, this.storage.getItem('onvifDoorbellEvent')); } async getClient() { diff --git a/plugins/onvif/src/onvif-api.ts b/plugins/onvif/src/onvif-api.ts index 1092b85ac..98a16d6c0 100644 --- a/plugins/onvif/src/onvif-api.ts +++ b/plugins/onvif/src/onvif-api.ts @@ -61,7 +61,7 @@ export class OnvifCameraAPI { digestAuth: AxiosDigestAuth; detections: Map; - constructor(public cam: any, username: string, password: string, public console: Console, binaryStateEvent: string, public debug?: boolean) { + constructor(public cam: any, username: string, password: string, public console: Console, binaryStateEvent: string) { this.binaryStateEvent = binaryStateEvent this.digestAuth = new AxiosDigestAuth({ username, @@ -74,11 +74,6 @@ export class OnvifCameraAPI { this.cam.on('event', (event: any, xml: string) => { const eventTopic = stripNamespaces(event.topic._) - if (this.debug) { - this.console.log('event', eventTopic); - this.console.log(JSON.stringify(event, null, 2)); - this.console.log(xml); - } if (event.message.message.data && event.message.message.data.simpleItem) { const dataValue = event.message.message.data.simpleItem.$.Value; @@ -271,7 +266,7 @@ export class OnvifCameraAPI { } } -export async function connectCameraAPI(ipAndPort: string, username: string, password: string, console: Console, binaryStateEvent: string, debugLog?: boolean) { +export async function connectCameraAPI(ipAndPort: string, username: string, password: string, console: Console, binaryStateEvent: string) { const split = ipAndPort.split(':'); const [hostname, port] = split; const cam = await promisify(cb => { @@ -282,5 +277,5 @@ export async function connectCameraAPI(ipAndPort: string, username: string, pass port, }, (err: Error) => cb(err, cam)); }); - return new OnvifCameraAPI(cam, username, password, console, binaryStateEvent, debugLog); + return new OnvifCameraAPI(cam, username, password, console, binaryStateEvent); } diff --git a/plugins/onvif/src/onvif-intercom.ts b/plugins/onvif/src/onvif-intercom.ts index 44c55a436..1c6ff3c9b 100644 --- a/plugins/onvif/src/onvif-intercom.ts +++ b/plugins/onvif/src/onvif-intercom.ts @@ -40,6 +40,7 @@ function addSupportedCodec(ffmpegCodec: string, sdpName: string) { addSupportedCodec('pcm_mulaw', 'PCMU'); addSupportedCodec('pcm_alaw', 'PCMA'); addSupportedCodec('pcm_s16be', 'L16'); +addSupportedCodec('adpcm_g726', 'G726'); addSupportedCodec('aac', 'MPEG4-GENERIC'); interface CodecMatch { @@ -78,6 +79,7 @@ export class OnvifIntercom implements Intercom { url.username = username; url.password = password; this.intercomClient = new RtspClient(url.toString()); + this.intercomClient.console = this.camera.console; await this.intercomClient.options(); const Require = 'www.onvif.org/ver20/backchannel'; diff --git a/plugins/rtsp/src/rtsp.ts b/plugins/rtsp/src/rtsp.ts index f3d4d28c6..7cbc83f31 100644 --- a/plugins/rtsp/src/rtsp.ts +++ b/plugins/rtsp/src/rtsp.ts @@ -199,7 +199,11 @@ export abstract class RtspSmartCamera extends RtspCamera { } resetActivityTimeout(); - listener.on('data', resetActivityTimeout); + listener.on('data', (data) => { + if (this.storage.getItem('debug') === 'true') + this.console.log('debug event:\n', data.toString()); + resetActivityTimeout(); + }); listener.on('close', () => { this.console.error('listen loop closed, restarting listener.'); @@ -260,6 +264,17 @@ export abstract class RtspSmartCamera extends RtspCamera { ); } + ret.push( + { + group: 'Advanced', + key: 'debug', + title: 'Debug Events', + description: "Log all events to the console. This will be very noisy and should not be left enabled.", + value: !!this.storage.getItem('debug'), + type: 'boolean', + } + ) + return ret; }