mirror of
https://github.com/koush/scrypted.git
synced 2026-06-21 00:50:30 +01:00
cameras: auto detect two way audio
This commit is contained in:
4
plugins/amcrest/package-lock.json
generated
4
plugins/amcrest/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/amcrest",
|
||||
"version": "0.0.117",
|
||||
"version": "0.0.118",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/amcrest",
|
||||
"version": "0.0.117",
|
||||
"version": "0.0.118",
|
||||
"license": "Apache",
|
||||
"dependencies": {
|
||||
"@koush/axios-digest-auth": "^0.8.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/amcrest",
|
||||
"version": "0.0.117",
|
||||
"version": "0.0.118",
|
||||
"description": "Amcrest Plugin for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
|
||||
@@ -32,6 +32,16 @@ export class AmcrestCameraClient {
|
||||
});
|
||||
}
|
||||
|
||||
async checkTwoWayAudio() {
|
||||
const response = await this.digestAuth.request({
|
||||
httpsAgent: amcrestHttpsAgent,
|
||||
method: "GET",
|
||||
responseType: 'text',
|
||||
url: `http://${this.ip}/cgi-bin/devAudioOutput.cgi?action=getCollect`,
|
||||
});
|
||||
return (response.data as string).includes('result=1');
|
||||
}
|
||||
|
||||
// appAutoStart=true
|
||||
// deviceType=IP4M-1041B
|
||||
// hardwareVersion=1.00
|
||||
|
||||
@@ -545,9 +545,10 @@ class AmcrestProvider extends RtspProvider {
|
||||
const username = settings.username?.toString();
|
||||
const password = settings.password?.toString();
|
||||
const skipValidate = settings.skipValidate === 'true';
|
||||
let twoWayAudio: string;
|
||||
if (!skipValidate) {
|
||||
const api = new AmcrestCameraClient(httpAddress, username, password, this.console);
|
||||
try {
|
||||
const api = new AmcrestCameraClient(httpAddress, username, password, this.console);
|
||||
const deviceInfo = await api.getDeviceInfo();
|
||||
|
||||
settings.newCamera = deviceInfo.deviceType;
|
||||
@@ -558,6 +559,16 @@ class AmcrestProvider extends RtspProvider {
|
||||
this.console.error('Error adding Amcrest camera', e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
if (await api.checkTwoWayAudio()) {
|
||||
// onvif seems to work better than Amcrest, except for AD110.
|
||||
twoWayAudio = 'ONVIF';
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.console.warn('Error probing two way audio', e);
|
||||
}
|
||||
}
|
||||
settings.newCamera ||= 'Hikvision Camera';
|
||||
|
||||
@@ -569,6 +580,8 @@ class AmcrestProvider extends RtspProvider {
|
||||
device.putSetting('password', password);
|
||||
device.setIPAddress(settings.ip?.toString());
|
||||
device.setHttpPortOverride(settings.httpPort?.toString());
|
||||
if (twoWayAudio)
|
||||
device.putSetting('twoWayAudio', twoWayAudio);
|
||||
return nativeId;
|
||||
}
|
||||
|
||||
|
||||
@@ -208,6 +208,7 @@ export abstract class CameraProviderBase<T extends ResponseMediaStreamOptions> e
|
||||
name,
|
||||
interfaces,
|
||||
type: type || ScryptedDeviceType.Camera,
|
||||
info: deviceManager.getNativeIds().includes(nativeId) ? deviceManager.getDeviceState(nativeId)?.info : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
4
plugins/hikvision/package-lock.json
generated
4
plugins/hikvision/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/hikvision",
|
||||
"version": "0.0.123",
|
||||
"version": "0.0.124",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/hikvision",
|
||||
"version": "0.0.123",
|
||||
"version": "0.0.124",
|
||||
"license": "Apache",
|
||||
"dependencies": {
|
||||
"@koush/axios-digest-auth": "^0.8.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/hikvision",
|
||||
"version": "0.0.123",
|
||||
"version": "0.0.124",
|
||||
"description": "Hikvision Plugin for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
|
||||
@@ -43,6 +43,17 @@ export class HikvisionCameraAPI {
|
||||
return getDeviceInfo(this.digestAuth, this.ip);
|
||||
}
|
||||
|
||||
async checkTwoWayAudio() {
|
||||
const response = await this.digestAuth.request({
|
||||
httpsAgent: hikvisionHttpsAgent,
|
||||
method: "GET",
|
||||
responseType: 'text',
|
||||
url: `http://${this.ip}/ISAPI/System/TwoWayAudio/channels`,
|
||||
});
|
||||
|
||||
return (response.data as string).includes('Speaker');
|
||||
}
|
||||
|
||||
async checkDeviceModel(): Promise<string> {
|
||||
if (!this.deviceModel) {
|
||||
this.deviceModel = this.getDeviceInfo().then(d => d.deviceModel).catch(e => {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { ffmpegLogInitialOutput } from '@scrypted/common/src/media-helpers';
|
||||
import { readLength } from '@scrypted/common/src/read-stream';
|
||||
import sdk, { Camera, DeviceCreatorSettings, DeviceInformation, FFmpegInput, Intercom, MediaObject, MediaStreamOptions, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, VideoStreamOptions } from "@scrypted/sdk";
|
||||
import sdk, { Camera, DeviceCreatorSettings, DeviceInformation, FFmpegInput, Intercom, MediaObject, MediaStreamOptions, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting } from "@scrypted/sdk";
|
||||
import child_process, { ChildProcess } from 'child_process';
|
||||
import { PassThrough, Readable } from "stream";
|
||||
import { sleep } from "../../../common/src/sleep";
|
||||
import xml2js from 'xml2js';
|
||||
import { OnvifIntercom } from "../../onvif/src/onvif-intercom";
|
||||
import { RtspProvider, RtspSmartCamera, UrlMediaStreamOptions } from "../../rtsp/src/rtsp";
|
||||
import { getChannel, HikvisionCameraAPI, HikvisionCameraEvent } from "./hikvision-camera-api";
|
||||
import xml2js from 'xml2js';
|
||||
import { HikvisionCameraAPI, HikvisionCameraEvent } from "./hikvision-camera-api";
|
||||
import { hikvisionHttpsAgent } from './probe';
|
||||
|
||||
const { mediaManager } = sdk;
|
||||
@@ -537,9 +536,10 @@ class HikvisionProvider extends RtspProvider {
|
||||
const username = settings.username?.toString();
|
||||
const password = settings.password?.toString();
|
||||
const skipValidate = settings.skipValidate === 'true';
|
||||
let twoWayAudio: string;
|
||||
if (!skipValidate) {
|
||||
const api = new HikvisionCameraAPI(httpAddress, username, password, this.console);
|
||||
try {
|
||||
const api = new HikvisionCameraAPI(httpAddress, username, password, this.console);
|
||||
const deviceInfo = await api.getDeviceInfo();
|
||||
|
||||
settings.newCamera = deviceInfo.deviceName;
|
||||
@@ -553,6 +553,15 @@ class HikvisionProvider extends RtspProvider {
|
||||
this.console.error('Error adding Hikvision camera', e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
if (await api.checkTwoWayAudio()) {
|
||||
twoWayAudio = 'Hikvision';
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.console.warn('Error probing two way audio', e);
|
||||
}
|
||||
}
|
||||
settings.newCamera ||= 'Hikvision Camera';
|
||||
|
||||
@@ -564,6 +573,8 @@ class HikvisionProvider extends RtspProvider {
|
||||
device.putSetting('password', password);
|
||||
device.setIPAddress(settings.ip?.toString());
|
||||
device.setHttpPortOverride(settings.httpPort?.toString());
|
||||
if (twoWayAudio)
|
||||
device.putSetting('twoWayAudio', twoWayAudio);
|
||||
return nativeId;
|
||||
}
|
||||
|
||||
|
||||
4
plugins/onvif/package-lock.json
generated
4
plugins/onvif/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/onvif",
|
||||
"version": "0.0.113",
|
||||
"version": "0.0.114",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/onvif",
|
||||
"version": "0.0.113",
|
||||
"version": "0.0.114",
|
||||
"license": "Apache",
|
||||
"dependencies": {
|
||||
"@koush/axios-digest-auth": "^0.8.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/onvif",
|
||||
"version": "0.0.113",
|
||||
"version": "0.0.114",
|
||||
"description": "ONVIF Camera Plugin for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
|
||||
@@ -561,6 +561,21 @@ class OnvifProvider extends RtspProvider implements DeviceDiscovery {
|
||||
device.putSetting('password', password);
|
||||
device.setIPAddress(settings.ip?.toString());
|
||||
device.setHttpPortOverride(settings.httpPort?.toString());
|
||||
|
||||
const intercom = new OnvifIntercom(device);
|
||||
try {
|
||||
intercom.url = (await device.getConstructedVideoStreamOptions())[0].url;
|
||||
if (await intercom.checkIntercom()) {
|
||||
device.putSetting('onvifTwoWay', 'true');
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.console.warn("error while probing intercom", e);
|
||||
}
|
||||
finally {
|
||||
intercom.intercomClient?.client.destroy();
|
||||
}
|
||||
|
||||
return nativeId;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ function* parseCodecs(audioSection: string): Generator<CodecMatch> {
|
||||
}
|
||||
}
|
||||
|
||||
const Require = 'www.onvif.org/ver20/backchannel';
|
||||
|
||||
export class OnvifIntercom implements Intercom {
|
||||
intercomClient: RtspClient;
|
||||
url: string;
|
||||
@@ -72,9 +74,7 @@ export class OnvifIntercom implements Intercom {
|
||||
constructor(public camera: RtspSmartCamera) {
|
||||
}
|
||||
|
||||
async startIntercom(media: MediaObject) {
|
||||
await this.stopIntercom();
|
||||
|
||||
async checkIntercom() {
|
||||
const username = this.camera.storage.getItem("username");
|
||||
const password = this.camera.storage.getItem("password");
|
||||
const url = new URL(this.url);
|
||||
@@ -83,7 +83,6 @@ export class OnvifIntercom implements Intercom {
|
||||
this.intercomClient = new RtspClient(url.toString());
|
||||
this.intercomClient.console = this.camera.console;
|
||||
await this.intercomClient.options();
|
||||
const Require = 'www.onvif.org/ver20/backchannel';
|
||||
|
||||
const describe = await this.intercomClient.describe({
|
||||
Require,
|
||||
@@ -95,6 +94,16 @@ export class OnvifIntercom implements Intercom {
|
||||
if (!audioBackchannel)
|
||||
throw new Error('ONVIF audio backchannel not found');
|
||||
|
||||
return audioBackchannel;
|
||||
}
|
||||
|
||||
async startIntercom(media: MediaObject) {
|
||||
await this.stopIntercom();
|
||||
|
||||
const audioBackchannel = await this.checkIntercom();
|
||||
if (!audioBackchannel)
|
||||
throw new Error('ONVIF audio backchannel not found');
|
||||
|
||||
const rtp = await reserveUdpPort();
|
||||
const rtcp = rtp + 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user