mirror of
https://github.com/koush/scrypted.git
synced 2026-02-09 08:42:19 +00:00
rebroadcast: support rtsps in RTSPClient.
google-device-access: fixup interface shenanigans between camera types.
This commit is contained in:
@@ -4,6 +4,7 @@ import { randomBytes } from 'crypto';
|
||||
import { StreamChunk, StreamParser } from './stream-parser';
|
||||
import dgram from 'dgram';
|
||||
import net from 'net';
|
||||
import tls from 'tls';
|
||||
|
||||
export const RTSP_FRAME_MAGIC = 36;
|
||||
|
||||
@@ -103,7 +104,17 @@ export class RtspClient extends RtspBase {
|
||||
constructor(public url: string) {
|
||||
super();
|
||||
const u = new URL(url);
|
||||
this.client = net.connect(parseInt(u.port) || 554, u.hostname);
|
||||
const port = parseInt(u.port) || 554;
|
||||
if (url.startsWith('rtsps')) {
|
||||
this.client = tls.connect({
|
||||
rejectUnauthorized: false,
|
||||
port,
|
||||
host: u.hostname,
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.client = net.connect(port, u.hostname);
|
||||
}
|
||||
}
|
||||
|
||||
async request(method: string, headers?: Headers, path?: string, body?: Buffer) {
|
||||
|
||||
@@ -18,8 +18,6 @@ const { deviceManager, mediaManager, endpointManager, systemManager } = sdk;
|
||||
|
||||
const refreshFrequency = 60;
|
||||
|
||||
const black = fs.readFileSync('unavailable.jpg');
|
||||
|
||||
const readmeV1 = fs.readFileSync('README-camera-v1.md').toString();
|
||||
const readmeV2 = fs.readFileSync('README-camera-v2.md').toString();
|
||||
|
||||
@@ -35,10 +33,20 @@ function getSdmRtspMediaStreamOptions(): MediaStreamOptions {
|
||||
codec: 'aac',
|
||||
},
|
||||
source: 'cloud',
|
||||
tool: 'scrypted',
|
||||
userConfigurable: false,
|
||||
};
|
||||
}
|
||||
|
||||
function deviceHasEventImages(device: any) {
|
||||
return !!device?.traits?.['sdm.devices.traits.CameraEventImage'];
|
||||
}
|
||||
|
||||
function deviceIsWebRtc(device: any) {
|
||||
return device?.traits?.['sdm.devices.traits.CameraLiveStream']?.supportedProtocols?.includes('WEB_RTC');
|
||||
}
|
||||
|
||||
|
||||
const RtcMediaStreamOptionsId = 'webrtc';
|
||||
|
||||
function getSdmRtcMediaStreamOptions(): MediaStreamOptions {
|
||||
@@ -198,7 +206,7 @@ class NestCamera extends ScryptedDeviceBase implements Readme, Camera, VideoCame
|
||||
}
|
||||
|
||||
// try to fetch the latest event image if one is queued
|
||||
const hasEventImages = !!this.device?.traits?.['sdm.devices.traits.CameraEventImage'];
|
||||
const hasEventImages = deviceHasEventImages(this.device);
|
||||
if (hasEventImages && this.lastMotionEventId) {
|
||||
const eventId = this.lastMotionEventId;
|
||||
this.lastMotionEventId = undefined;
|
||||
@@ -217,8 +225,7 @@ class NestCamera extends ScryptedDeviceBase implements Readme, Camera, VideoCame
|
||||
return mediaManager.createMediaObject(data, 'image/jpeg');
|
||||
}
|
||||
|
||||
// send "no snapshot available" image
|
||||
return mediaManager.createMediaObject(black, 'image/jpeg');
|
||||
throw new Error('snapshot unavailable');
|
||||
}
|
||||
|
||||
async getPictureOptions(): Promise<PictureOptions[]> {
|
||||
@@ -248,7 +255,7 @@ class NestCamera extends ScryptedDeviceBase implements Readme, Camera, VideoCame
|
||||
}
|
||||
|
||||
get isWebRtc() {
|
||||
return this.device?.traits?.['sdm.devices.traits.CameraLiveStream']?.supportedProtocols?.includes('WEB_RTC');
|
||||
return deviceIsWebRtc(this.device);
|
||||
}
|
||||
|
||||
async getVideoStream(options?: RequestMediaStreamOptions): Promise<MediaObject> {
|
||||
@@ -763,14 +770,18 @@ class GoogleSmartDeviceAccess extends ScryptedDeviceBase implements OauthClient,
|
||||
|
||||
const interfaces = [
|
||||
ScryptedInterface.BufferConverter,
|
||||
ScryptedInterface.RTCSignalingChannel,
|
||||
ScryptedInterface.VideoCamera,
|
||||
ScryptedInterface.Camera,
|
||||
ScryptedInterface.MotionSensor,
|
||||
ScryptedInterface.ObjectDetector,
|
||||
ScryptedInterface.Readme,
|
||||
];
|
||||
|
||||
if (deviceHasEventImages(device))
|
||||
interfaces.push(ScryptedInterface.Camera);
|
||||
|
||||
if (deviceIsWebRtc(device))
|
||||
interfaces.push(ScryptedInterface.RTCSignalingChannel);
|
||||
|
||||
let type = ScryptedDeviceType.Camera;
|
||||
if (device.type === 'sdm.devices.types.DOORBELL') {
|
||||
interfaces.push(ScryptedInterface.BinarySensor);
|
||||
|
||||
4
plugins/prebuffer-mixin/package-lock.json
generated
4
plugins/prebuffer-mixin/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/prebuffer-mixin",
|
||||
"version": "0.1.171",
|
||||
"version": "0.1.172",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/prebuffer-mixin",
|
||||
"version": "0.1.171",
|
||||
"version": "0.1.172",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/prebuffer-mixin",
|
||||
"version": "0.1.171",
|
||||
"version": "0.1.172",
|
||||
"description": "Rebroadcast and Prebuffer for VideoCameras.",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -208,7 +208,7 @@ class PrebufferSession {
|
||||
title: 'Detected Keyframe Interval',
|
||||
description: "Configuring your camera to 4 seconds is recommended (IDR aka Frame Interval = FPS * 4 seconds).",
|
||||
readonly: true,
|
||||
value: ((this.detectedIdrInterval || 0) / 1000).toString() || 'none',
|
||||
value: (this.detectedIdrInterval || 0) / 1000 || 'unknown',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1329,7 +1329,7 @@ export interface RTCSignalingClient {
|
||||
* strict requirements and expectations on client setup.
|
||||
*/
|
||||
export interface RTCSignalingChannel {
|
||||
startRTCSignalingSession(session: RTCSignalingSession, options?: RTCSignalingClientOptions): Promise<RTCSessionControl|void>;
|
||||
startRTCSignalingSession(session: RTCSignalingSession, options?: RTCSignalingClientOptions): Promise<RTCSessionControl|undefined>;
|
||||
}
|
||||
|
||||
export interface RTCAVSignalingSetup {
|
||||
|
||||
@@ -703,7 +703,7 @@ class PushHandler:
|
||||
pass
|
||||
|
||||
class RTCSignalingChannel:
|
||||
async def startRTCSignalingSession(self, session: RTCSignalingSession, options: RTCSignalingClientOptions = None) -> None | RTCSessionControl:
|
||||
async def startRTCSignalingSession(self, session: RTCSignalingSession, options: RTCSignalingClientOptions = None) -> RTCSessionControl:
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
2
sdk/types/index.d.ts
vendored
2
sdk/types/index.d.ts
vendored
@@ -1364,7 +1364,7 @@ export interface RTCSignalingClient {
|
||||
* strict requirements and expectations on client setup.
|
||||
*/
|
||||
export interface RTCSignalingChannel {
|
||||
startRTCSignalingSession(session: RTCSignalingSession, options?: RTCSignalingClientOptions): Promise<RTCSessionControl | void>;
|
||||
startRTCSignalingSession(session: RTCSignalingSession, options?: RTCSignalingClientOptions): Promise<RTCSessionControl | undefined>;
|
||||
}
|
||||
export interface RTCAVSignalingSetup {
|
||||
/**
|
||||
|
||||
@@ -1992,7 +1992,7 @@ export interface RTCSignalingClient {
|
||||
* strict requirements and expectations on client setup.
|
||||
*/
|
||||
export interface RTCSignalingChannel {
|
||||
startRTCSignalingSession(session: RTCSignalingSession, options?: RTCSignalingClientOptions): Promise<RTCSessionControl|void>;
|
||||
startRTCSignalingSession(session: RTCSignalingSession, options?: RTCSignalingClientOptions): Promise<RTCSessionControl|undefined>;
|
||||
}
|
||||
|
||||
export interface RTCAVSignalingSetup {
|
||||
|
||||
@@ -703,7 +703,7 @@ class PushHandler:
|
||||
pass
|
||||
|
||||
class RTCSignalingChannel:
|
||||
async def startRTCSignalingSession(self, session: RTCSignalingSession, options: RTCSignalingClientOptions = None) -> None | RTCSessionControl:
|
||||
async def startRTCSignalingSession(self, session: RTCSignalingSession, options: RTCSignalingClientOptions = None) -> RTCSessionControl:
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user