mirror of
https://github.com/koush/scrypted.git
synced 2026-09-18 01:30:39 +01:00
unifi-protect: use pipes, safe kill ffmpeg interocm
This commit is contained in:
45
plugins/unifi-protect/package-lock.json
generated
45
plugins/unifi-protect/package-lock.json
generated
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"name": "@scrypted/unifi-protect",
|
||||
"version": "0.0.106",
|
||||
"version": "0.0.107",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/unifi-protect",
|
||||
"version": "0.0.106",
|
||||
"version": "0.0.107",
|
||||
"license": "Apache",
|
||||
"dependencies": {
|
||||
"@koush/unifi-protect": "file:../../external/unifi-protect",
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"node-fetch": "^3.2.1",
|
||||
"ws": "^8.5.0"
|
||||
@@ -20,13 +21,29 @@
|
||||
"@types/ws": "^7.4.7"
|
||||
}
|
||||
},
|
||||
"../../common": {
|
||||
"version": "1.0.1",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@koush/werift": "file:../external/werift/packages/webrtc",
|
||||
"@koush/wrtc": "^0.5.3",
|
||||
"@scrypted/sdk": "file:../sdk",
|
||||
"http-auth-utils": "^3.0.2",
|
||||
"node-fetch-commonjs": "^3.1.1",
|
||||
"typescript": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.9.0"
|
||||
}
|
||||
},
|
||||
"../../external/unifi-protect": {
|
||||
"version": "3.0.2",
|
||||
"name": "@koush/unifi-protect",
|
||||
"version": "3.0.5",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"domexception": "^4.0.0",
|
||||
"node-fetch-cjs": "=3.2.0",
|
||||
"node-fetch": "^3.2.1",
|
||||
"util": "^0.12.4",
|
||||
"ws": "^8.5.0"
|
||||
},
|
||||
@@ -45,7 +62,7 @@
|
||||
},
|
||||
"../../sdk": {
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.0.174",
|
||||
"version": "0.0.177",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
@@ -85,6 +102,10 @@
|
||||
"resolved": "../../external/unifi-protect",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@scrypted/common": {
|
||||
"resolved": "../../common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@scrypted/sdk": {
|
||||
"resolved": "../../sdk",
|
||||
"link": true
|
||||
@@ -226,13 +247,25 @@
|
||||
"abort-controller": "^3.0.0",
|
||||
"domexception": "^4.0.0",
|
||||
"eslint": "^8.9.0",
|
||||
"node-fetch-cjs": "=3.2.0",
|
||||
"node-fetch": "^3.2.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5",
|
||||
"util": "^0.12.4",
|
||||
"ws": "^8.5.0"
|
||||
}
|
||||
},
|
||||
"@scrypted/common": {
|
||||
"version": "file:../../common",
|
||||
"requires": {
|
||||
"@koush/werift": "file:../external/werift/packages/webrtc",
|
||||
"@koush/wrtc": "^0.5.3",
|
||||
"@scrypted/sdk": "file:../sdk",
|
||||
"@types/node": "^16.9.0",
|
||||
"http-auth-utils": "^3.0.2",
|
||||
"node-fetch-commonjs": "^3.1.1",
|
||||
"typescript": "^4.4.3"
|
||||
}
|
||||
},
|
||||
"@scrypted/sdk": {
|
||||
"version": "file:../../sdk",
|
||||
"requires": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/unifi-protect",
|
||||
"version": "0.0.106",
|
||||
"version": "0.0.107",
|
||||
"description": "Unifi Protect Plugin for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
@@ -37,6 +37,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@koush/unifi-protect": "file:../../external/unifi-protect",
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"node-fetch": "^3.2.1",
|
||||
"ws": "^8.5.0"
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import sdk, { ScryptedDeviceBase, DeviceProvider, Settings, Setting, VideoCamera, MediaObject, MotionSensor, ScryptedInterface, Camera, MediaStreamOptions, Intercom, ScryptedMimeTypes, FFMpegInput, ObjectDetector, PictureOptions, ObjectDetectionTypes, ObjectsDetected, Notifier, VideoCameraConfiguration, OnOff, MediaStreamUrl } from "@scrypted/sdk";
|
||||
import { ProtectCameraChannelConfig, ProtectCameraConfigInterface, ProtectCameraLcdMessagePayload } from "./unifi-protect";
|
||||
import child_process, { ChildProcess } from 'child_process';
|
||||
import { ffmpegLogInitialOutput } from '../../../common/src/media-helpers';
|
||||
import { fitHeightToWidth } from "../../../common/src/resolution-utils";
|
||||
import { listenZero } from "../../../common/src/listen-cluster";
|
||||
import { ffmpegLogInitialOutput, safeKillFFmpeg } from '@scrypted/common/src/media-helpers';
|
||||
import { fitHeightToWidth } from "@scrypted/common/src/resolution-utils";
|
||||
import { listenZero } from "@scrypted/common/src/listen-cluster";
|
||||
import net from 'net';
|
||||
import WS from 'ws';
|
||||
import { once } from "events";
|
||||
import { FeatureFlagsShim } from "./shim";
|
||||
import { UnifiProtect } from "./main";
|
||||
import { Readable } from "stream";
|
||||
|
||||
const { log, deviceManager, mediaManager } = sdk;
|
||||
|
||||
@@ -90,6 +91,8 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
}
|
||||
|
||||
async startIntercom(media: MediaObject) {
|
||||
this.stopIntercom();
|
||||
|
||||
const buffer = await mediaManager.convertMediaObjectToBuffer(media, ScryptedMimeTypes.FFmpegInput);
|
||||
const ffmpegInput = JSON.parse(buffer.toString()) as FFMpegInput;
|
||||
|
||||
@@ -106,32 +109,6 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
const websocket = new WS(talkbackUrl, { rejectUnauthorized: false });
|
||||
await once(websocket, 'open');
|
||||
|
||||
const server = new net.Server(async (socket) => {
|
||||
server.close();
|
||||
|
||||
this.console.log('sending audio data to', talkbackUrl);
|
||||
|
||||
try {
|
||||
while (websocket.readyState === WS.OPEN) {
|
||||
await once(socket, 'readable');
|
||||
while (true) {
|
||||
const data = socket.read();
|
||||
if (!data)
|
||||
break;
|
||||
websocket.send(data, e => {
|
||||
if (e)
|
||||
socket.destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.console.log('talkback ended')
|
||||
this.intercomProcess.kill();
|
||||
}
|
||||
});
|
||||
const port = await listenZero(server)
|
||||
|
||||
const args = [
|
||||
'-hide_banner',
|
||||
|
||||
@@ -152,17 +129,48 @@ export class UnifiCamera extends ScryptedDeviceBase implements Notifier, Interco
|
||||
"-ac", camera.talkbackSettings.channels.toString(),
|
||||
"-b:a", "16k",
|
||||
"-f", "adts",
|
||||
`tcp://127.0.0.1:${port}`,
|
||||
`pipe:3`,
|
||||
);
|
||||
|
||||
this.console.log('starting 2 way audio', args);
|
||||
|
||||
const ffmpeg = await mediaManager.getFFmpegPath();
|
||||
this.intercomProcess = child_process.spawn(ffmpeg, args);
|
||||
this.intercomProcess.on('exit', () => {
|
||||
websocket.close();
|
||||
this.intercomProcess = undefined;
|
||||
const cp = this.intercomProcess = child_process.spawn(ffmpeg, args, {
|
||||
stdio: ['pipe', 'pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
this.intercomProcess.on('exit', () => {
|
||||
this.intercomProcess = undefined;
|
||||
websocket.close();
|
||||
});
|
||||
|
||||
websocket.on('close', () => safeKillFFmpeg(cp));
|
||||
|
||||
(async () => {
|
||||
const socket = cp.stdio[3] as Readable;
|
||||
this.console.log('sending audio data to', talkbackUrl);
|
||||
|
||||
try {
|
||||
while (websocket.readyState === WS.OPEN) {
|
||||
await once(socket, 'readable');
|
||||
while (true) {
|
||||
const data = socket.read();
|
||||
if (!data)
|
||||
break;
|
||||
websocket.send(data, e => {
|
||||
if (e) {
|
||||
safeKillFFmpeg(cp);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.console.log('talkback ended')
|
||||
safeKillFFmpeg(cp);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
ffmpegLogInitialOutput(this.console, this.intercomProcess);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import sdk, { ScryptedDeviceBase, DeviceProvider, Settings, Setting, ScryptedDeviceType, Device, ScryptedInterface, ObjectsDetected, ObjectDetectionResult } from "@scrypted/sdk";
|
||||
import { ProtectApi, ProtectApiUpdates, ProtectNvrUpdatePayloadCameraUpdate, ProtectNvrUpdatePayloadEventAdd } from "./unifi-protect";
|
||||
import { createInstanceableProviderPlugin, enableInstanceableProviderMode, isInstanceableProviderModeEnabled } from '../../../common/src/provider-plugin';
|
||||
import { createInstanceableProviderPlugin, enableInstanceableProviderMode, isInstanceableProviderModeEnabled } from '@scrypted/common/src/provider-plugin';
|
||||
import fetch, { RequestInfo, RequestInit, Response } from "node-fetch";
|
||||
import { defaultSensorTimeout, UnifiCamera } from "./camera";
|
||||
import { FeatureFlagsShim, LastSeenShim } from "./shim";
|
||||
|
||||
Reference in New Issue
Block a user