@homebridge-plugins/homebridge-eufy-security 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/FUNDING.yml +1 -0
- package/LICENSE +176 -0
- package/README.md +67 -0
- package/config.schema.json +6 -0
- package/dist/accessories/AutoSyncStationAccessory.js +156 -0
- package/dist/accessories/AutoSyncStationAccessory.js.map +1 -0
- package/dist/accessories/BaseAccessory.js +247 -0
- package/dist/accessories/BaseAccessory.js.map +1 -0
- package/dist/accessories/CameraAccessory.js +431 -0
- package/dist/accessories/CameraAccessory.js.map +1 -0
- package/dist/accessories/Device.js +67 -0
- package/dist/accessories/Device.js.map +1 -0
- package/dist/accessories/EntrySensorAccessory.js +48 -0
- package/dist/accessories/EntrySensorAccessory.js.map +1 -0
- package/dist/accessories/LockAccessory.js +142 -0
- package/dist/accessories/LockAccessory.js.map +1 -0
- package/dist/accessories/MotionSensorAccessory.js +48 -0
- package/dist/accessories/MotionSensorAccessory.js.map +1 -0
- package/dist/accessories/SmartDropAccessory.js +145 -0
- package/dist/accessories/SmartDropAccessory.js.map +1 -0
- package/dist/accessories/StationAccessory.js +371 -0
- package/dist/accessories/StationAccessory.js.map +1 -0
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -0
- package/dist/controller/LocalLivestreamManager.js +116 -0
- package/dist/controller/LocalLivestreamManager.js.map +1 -0
- package/dist/controller/recordingDelegate.js +208 -0
- package/dist/controller/recordingDelegate.js.map +1 -0
- package/dist/controller/snapshotDelegate.js +345 -0
- package/dist/controller/snapshotDelegate.js.map +1 -0
- package/dist/controller/streamingDelegate.js +345 -0
- package/dist/controller/streamingDelegate.js.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.js +2 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/Snapshot-black.png +0 -0
- package/dist/media/camera-disabled.png +0 -0
- package/dist/media/camera-offline.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/media/Snapshot-black.png +0 -0
- package/dist/media/media/camera-disabled.png +0 -0
- package/dist/media/media/camera-offline.png +0 -0
- package/dist/platform.js +716 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.js +38 -0
- package/dist/settings.js.map +1 -0
- package/dist/utils/Talkback.js +92 -0
- package/dist/utils/Talkback.js.map +1 -0
- package/dist/utils/accessoriesStore.js +206 -0
- package/dist/utils/accessoriesStore.js.map +1 -0
- package/dist/utils/configTypes.js +35 -0
- package/dist/utils/configTypes.js.map +1 -0
- package/dist/utils/ffmpeg.js +843 -0
- package/dist/utils/ffmpeg.js.map +1 -0
- package/dist/utils/interfaces.js +8 -0
- package/dist/utils/interfaces.js.map +1 -0
- package/dist/utils/utils.js +44 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/eslint.config.mjs +18 -0
- package/homebridge-eufy-security.png +0 -0
- package/homebridge-ui/public/app.js +225 -0
- package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C30.png +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C31.png +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell2kdual_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell_e340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufy-security-client.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2cpro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycame330_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlightcame340_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/homebase2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/homebasemini_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamc120_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcammini_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamp24_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcams350_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/keypad_large.png +0 -0
- package/homebridge-ui/public/assets/devices/minibase_chime_T8023_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/motionsensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/sensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8503_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8504_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8510P_t8520P_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8502_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8506_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8520_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_video_t8530_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlockwifibridge_t8021_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_card_t87B2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_link_t87B0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocamc210_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocaml20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams220_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocams40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/soloindoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc22_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/unknown.png +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s100_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s120_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell2k_large.png +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbelldual_large.jpg +0 -0
- package/homebridge-ui/public/assets/icons/attach.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_0.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_1.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_2.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_3.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_4.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_5.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_6.svg +1 -0
- package/homebridge-ui/public/assets/icons/bolt.svg +1 -0
- package/homebridge-ui/public/assets/icons/bug-report.svg +1 -0
- package/homebridge-ui/public/assets/icons/copy.svg +1 -0
- package/homebridge-ui/public/assets/icons/delete.svg +1 -0
- package/homebridge-ui/public/assets/icons/download.svg +1 -0
- package/homebridge-ui/public/assets/icons/info.svg +1 -0
- package/homebridge-ui/public/assets/icons/inventory.svg +1 -0
- package/homebridge-ui/public/assets/icons/refresh.svg +1 -0
- package/homebridge-ui/public/assets/icons/satellite_alt.svg +1 -0
- package/homebridge-ui/public/assets/icons/settings.svg +1 -0
- package/homebridge-ui/public/assets/icons/settings_backup_restore.svg +1 -0
- package/homebridge-ui/public/assets/icons/solar_power.svg +1 -0
- package/homebridge-ui/public/assets/icons/warning.svg +1 -0
- package/homebridge-ui/public/components/device-card.js +162 -0
- package/homebridge-ui/public/components/guard-modes.js +88 -0
- package/homebridge-ui/public/components/number-input.js +121 -0
- package/homebridge-ui/public/components/select.js +73 -0
- package/homebridge-ui/public/components/toggle.js +68 -0
- package/homebridge-ui/public/index.html +27 -0
- package/homebridge-ui/public/services/api.js +214 -0
- package/homebridge-ui/public/services/config.js +144 -0
- package/homebridge-ui/public/style.css +775 -0
- package/homebridge-ui/public/utils/countries.js +73 -0
- package/homebridge-ui/public/utils/device-images.js +89 -0
- package/homebridge-ui/public/utils/helpers.js +87 -0
- package/homebridge-ui/public/views/dashboard.js +226 -0
- package/homebridge-ui/public/views/device-detail.js +610 -0
- package/homebridge-ui/public/views/diagnostics.js +296 -0
- package/homebridge-ui/public/views/login.js +636 -0
- package/homebridge-ui/public/views/settings.js +192 -0
- package/homebridge-ui/public/views/unsupported-detail.js +296 -0
- package/homebridge-ui/server.js +1327 -0
- package/media/Snapshot-Unavailable.png +0 -0
- package/media/Snapshot-Unavailable.xcf +0 -0
- package/media/Snapshot-black.png +0 -0
- package/media/camera-disabled.png +0 -0
- package/media/camera-offline.png +0 -0
- package/package.json +64 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { createSocket } from 'dgram';
|
|
2
|
+
import { pickPort } from 'pick-port';
|
|
3
|
+
import { PropertyName } from 'eufy-security-client';
|
|
4
|
+
import { FFmpeg, FFmpegParameters } from '../utils/ffmpeg.js';
|
|
5
|
+
import { TalkbackStream } from '../utils/Talkback.js';
|
|
6
|
+
import { HAP, isRtspReady } from '../utils/utils.js';
|
|
7
|
+
import { LocalLivestreamManager } from './LocalLivestreamManager.js';
|
|
8
|
+
import { snapshotDelegate } from './snapshotDelegate.js';
|
|
9
|
+
export class StreamingDelegate {
|
|
10
|
+
camera;
|
|
11
|
+
controller;
|
|
12
|
+
log;
|
|
13
|
+
localLivestreamManager;
|
|
14
|
+
snapshotDelegate;
|
|
15
|
+
// keep track of sessions
|
|
16
|
+
pendingSessions = new Map();
|
|
17
|
+
ongoingSessions = new Map();
|
|
18
|
+
get device() {
|
|
19
|
+
return this.camera.device;
|
|
20
|
+
}
|
|
21
|
+
get videoConfig() {
|
|
22
|
+
return this.camera.cameraConfig.videoConfig;
|
|
23
|
+
}
|
|
24
|
+
constructor(camera) {
|
|
25
|
+
this.camera = camera;
|
|
26
|
+
this.log = camera.log;
|
|
27
|
+
this.localLivestreamManager = new LocalLivestreamManager(camera);
|
|
28
|
+
this.snapshotDelegate = new snapshotDelegate(this.camera, this.localLivestreamManager);
|
|
29
|
+
}
|
|
30
|
+
setController(controller) {
|
|
31
|
+
this.controller = controller;
|
|
32
|
+
}
|
|
33
|
+
getLivestreamManager() {
|
|
34
|
+
return this.localLivestreamManager;
|
|
35
|
+
}
|
|
36
|
+
getSnapshotDelegate() {
|
|
37
|
+
return this.snapshotDelegate;
|
|
38
|
+
}
|
|
39
|
+
async handleSnapshotRequest(request, callback) {
|
|
40
|
+
this.log.debug(`Snapshot requested: ${request.width}x${request.height}`);
|
|
41
|
+
try {
|
|
42
|
+
const snapshot = await this.snapshotDelegate.getSnapshotBufferResized(request);
|
|
43
|
+
this.log.debug('Snapshot byte length: ' + snapshot?.byteLength);
|
|
44
|
+
callback(undefined, snapshot);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.log.error(error);
|
|
48
|
+
callback();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async prepareStream(request, callback) {
|
|
52
|
+
this.log.debug(`stream prepare request with session id ${request.sessionID} was received.`);
|
|
53
|
+
const [videoReturnPort, audioReturnPort] = await Promise.all([
|
|
54
|
+
pickPort({ type: 'udp' }),
|
|
55
|
+
pickPort({ type: 'udp' }),
|
|
56
|
+
]);
|
|
57
|
+
const videoSSRC = HAP.CameraController.generateSynchronisationSource();
|
|
58
|
+
const audioSSRC = HAP.CameraController.generateSynchronisationSource();
|
|
59
|
+
const srtpBuffer = (m) => Buffer.concat([m.srtp_key, m.srtp_salt]);
|
|
60
|
+
const sessionInfo = {
|
|
61
|
+
address: request.targetAddress,
|
|
62
|
+
ipv6: request.addressVersion === 'ipv6',
|
|
63
|
+
videoPort: request.video.port,
|
|
64
|
+
videoReturnPort,
|
|
65
|
+
videoCryptoSuite: request.video.srtpCryptoSuite,
|
|
66
|
+
videoSRTP: srtpBuffer(request.video),
|
|
67
|
+
videoSSRC,
|
|
68
|
+
audioPort: request.audio.port,
|
|
69
|
+
audioReturnPort,
|
|
70
|
+
audioCryptoSuite: request.audio.srtpCryptoSuite,
|
|
71
|
+
audioSRTP: srtpBuffer(request.audio),
|
|
72
|
+
audioSSRC,
|
|
73
|
+
};
|
|
74
|
+
this.pendingSessions.set(request.sessionID, sessionInfo);
|
|
75
|
+
const response = {
|
|
76
|
+
video: this.buildMediaResponse(videoReturnPort, videoSSRC, request.video),
|
|
77
|
+
audio: this.buildMediaResponse(audioReturnPort, audioSSRC, request.audio),
|
|
78
|
+
};
|
|
79
|
+
callback(undefined, response);
|
|
80
|
+
}
|
|
81
|
+
buildMediaResponse(returnPort, ssrc, media) {
|
|
82
|
+
return {
|
|
83
|
+
port: returnPort,
|
|
84
|
+
ssrc,
|
|
85
|
+
srtp_key: media.srtp_key,
|
|
86
|
+
srtp_salt: media.srtp_salt,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async startStream(request, callback) {
|
|
90
|
+
const sessionInfo = this.pendingSessions.get(request.sessionID);
|
|
91
|
+
if (!sessionInfo) {
|
|
92
|
+
this.log.error('Error finding session information.');
|
|
93
|
+
callback(new Error('Error finding session information'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const activeSession = {};
|
|
98
|
+
activeSession.socket = this.createKeepAliveSocket(sessionInfo, request, activeSession);
|
|
99
|
+
const { videoParams, audioParams } = await this.buildStreamParameters(sessionInfo, request);
|
|
100
|
+
const isP2P = await this.configureStreamInput(videoParams, audioParams);
|
|
101
|
+
await this.startFFmpegProcesses(activeSession, videoParams, audioParams, request, callback, isP2P);
|
|
102
|
+
await this.setupTalkback(activeSession, sessionInfo);
|
|
103
|
+
this.finalizeSession(request.sessionID, activeSession);
|
|
104
|
+
// Opportunistically capture a snapshot from the running livestream
|
|
105
|
+
this.captureSnapshotFromLivestream();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
this.log.error('Stream could not be started: ' + error);
|
|
109
|
+
callback(error);
|
|
110
|
+
this.pendingSessions.delete(request.sessionID);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Creates a UDP socket that monitors RTCP keep-alive messages.
|
|
115
|
+
* If no message is received within 5x the RTCP interval, the stream is considered inactive.
|
|
116
|
+
*/
|
|
117
|
+
createKeepAliveSocket(sessionInfo, request, activeSession) {
|
|
118
|
+
const socket = createSocket(sessionInfo.ipv6 ? 'udp6' : 'udp4');
|
|
119
|
+
socket.on('error', (err) => {
|
|
120
|
+
this.log.error('Socket error: ' + err.message);
|
|
121
|
+
this.stopStream(request.sessionID);
|
|
122
|
+
});
|
|
123
|
+
socket.on('message', () => {
|
|
124
|
+
if (activeSession.timeout) {
|
|
125
|
+
clearTimeout(activeSession.timeout);
|
|
126
|
+
}
|
|
127
|
+
activeSession.timeout = setTimeout(() => {
|
|
128
|
+
this.log.debug('Device appears to be inactive. Stopping video stream.');
|
|
129
|
+
this.controller?.forceStopStreamingSession(request.sessionID);
|
|
130
|
+
this.stopStream(request.sessionID);
|
|
131
|
+
}, request.video.rtcp_interval * 5 * 1000);
|
|
132
|
+
});
|
|
133
|
+
socket.bind(sessionInfo.videoReturnPort);
|
|
134
|
+
return socket;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Builds FFmpeg parameters for video and (optionally) audio streams.
|
|
138
|
+
*/
|
|
139
|
+
async buildStreamParameters(sessionInfo, request) {
|
|
140
|
+
const videoParams = await FFmpegParameters.forVideo(this.videoConfig.debug);
|
|
141
|
+
videoParams.setup(this.camera.cameraConfig, request);
|
|
142
|
+
videoParams.setRTPTarget(sessionInfo, request);
|
|
143
|
+
const isCodecSupported = request.audio.codec === "OPUS" /* AudioStreamingCodecType.OPUS */
|
|
144
|
+
|| request.audio.codec === "AAC-eld" /* AudioStreamingCodecType.AAC_ELD */;
|
|
145
|
+
if (!isCodecSupported) {
|
|
146
|
+
this.log.warn(`An unsupported audio codec (type: ${request.audio.codec}) was requested. Audio streaming will be omitted.`);
|
|
147
|
+
}
|
|
148
|
+
let audioParams;
|
|
149
|
+
if (isCodecSupported) {
|
|
150
|
+
audioParams = await FFmpegParameters.forAudio(this.videoConfig.debug);
|
|
151
|
+
audioParams.setup(this.camera.cameraConfig, request);
|
|
152
|
+
audioParams.setRTPTarget(sessionInfo, request);
|
|
153
|
+
}
|
|
154
|
+
return { videoParams, audioParams };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Configures the input source (RTSP URL or P2P livestream) for the FFmpeg parameters.
|
|
158
|
+
*
|
|
159
|
+
* @returns `true` when the stream is a P2P livestream, `false` for RTSP.
|
|
160
|
+
*/
|
|
161
|
+
async configureStreamInput(videoParams, audioParams) {
|
|
162
|
+
if (isRtspReady(this.device, this.camera.cameraConfig)) {
|
|
163
|
+
const url = this.device.getPropertyValue(PropertyName.DeviceRTSPStreamUrl);
|
|
164
|
+
this.log.debug('RTSP URL: ' + url);
|
|
165
|
+
videoParams.setInputSource(url);
|
|
166
|
+
audioParams?.setInputSource(url);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
this.log.debug(`Using P2P local livestream for ${this.device.getName()} ` +
|
|
170
|
+
`(serial: ${this.device.getSerial()}, type: ${this.device.getDeviceType()})`);
|
|
171
|
+
const streamData = await this.localLivestreamManager.getLocalLiveStream();
|
|
172
|
+
this.log.debug('Livestream obtained successfully. Setting up FFmpeg input streams...');
|
|
173
|
+
await videoParams.setInputStream(streamData.videostream);
|
|
174
|
+
await audioParams?.setInputStream(streamData.audiostream);
|
|
175
|
+
this.log.debug('FFmpeg input streams configured.');
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
/** Delay before extracting a snapshot from a running livestream (ms). */
|
|
179
|
+
static LIVESTREAM_SNAPSHOT_DELAY_MS = 2_000;
|
|
180
|
+
/** Grace period for a P2P audio process before it is killed for inactivity (ms). */
|
|
181
|
+
static P2P_AUDIO_TIMEOUT_MS = 8_000;
|
|
182
|
+
/**
|
|
183
|
+
* Starts the video (and optionally separate audio) FFmpeg processes.
|
|
184
|
+
*
|
|
185
|
+
* For P2P streams the video and audio inputs arrive on separate TCP
|
|
186
|
+
* connections. Some camera models advertise an audio codec in their
|
|
187
|
+
* stream metadata but never deliver any audio data. When video and
|
|
188
|
+
* audio share a single FFmpeg process the stalled audio input blocks
|
|
189
|
+
* video output, causing HomeKit to time out the stream.
|
|
190
|
+
*
|
|
191
|
+
* To prevent that, P2P streams always use separate FFmpeg processes:
|
|
192
|
+
* the video process starts immediately and independently of the audio
|
|
193
|
+
* process. If the audio process fails to produce output within
|
|
194
|
+
* {@link P2P_AUDIO_TIMEOUT_MS} it is killed silently so that resources
|
|
195
|
+
* are not wasted on a stalled input.
|
|
196
|
+
*/
|
|
197
|
+
async startFFmpegProcesses(activeSession, videoParams, audioParams, request, callback, isP2P = false) {
|
|
198
|
+
const videoProcess = new FFmpeg('[Video Process]', !isP2P && audioParams ? [videoParams, audioParams] : videoParams);
|
|
199
|
+
videoProcess.on('started', () => callback());
|
|
200
|
+
videoProcess.on('error', (error) => {
|
|
201
|
+
this.log.error('Video process ended with error: ' + error);
|
|
202
|
+
this.stopStream(request.sessionID);
|
|
203
|
+
});
|
|
204
|
+
activeSession.videoProcess = videoProcess;
|
|
205
|
+
await videoProcess.start();
|
|
206
|
+
if (isP2P && audioParams) {
|
|
207
|
+
const audioProcess = new FFmpeg('[Audio Process]', audioParams);
|
|
208
|
+
if (isP2P) {
|
|
209
|
+
// For P2P, audio failure must not tear down the video stream.
|
|
210
|
+
// Set up a timeout: if FFmpeg never reports progress (i.e. the
|
|
211
|
+
// camera is not providing audio data), kill the process early.
|
|
212
|
+
let audioStarted = false;
|
|
213
|
+
const audioTimeout = setTimeout(() => {
|
|
214
|
+
if (!audioStarted) {
|
|
215
|
+
this.log.warn(`No audio data received from ${this.device.getName()} — ` +
|
|
216
|
+
'killing audio process (video continues).');
|
|
217
|
+
audioProcess.stop();
|
|
218
|
+
activeSession.audioProcess = undefined;
|
|
219
|
+
}
|
|
220
|
+
}, StreamingDelegate.P2P_AUDIO_TIMEOUT_MS);
|
|
221
|
+
audioProcess.on('started', () => {
|
|
222
|
+
audioStarted = true;
|
|
223
|
+
clearTimeout(audioTimeout);
|
|
224
|
+
});
|
|
225
|
+
audioProcess.on('error', (error) => {
|
|
226
|
+
clearTimeout(audioTimeout);
|
|
227
|
+
if (audioStarted) {
|
|
228
|
+
// Audio was working but failed mid-stream — log but keep video.
|
|
229
|
+
this.log.warn('P2P audio process ended unexpectedly: ' + error);
|
|
230
|
+
}
|
|
231
|
+
activeSession.audioProcess = undefined;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
audioProcess.on('error', (error) => {
|
|
236
|
+
this.log.error('Audio process ended with error: ' + error);
|
|
237
|
+
this.stopStream(request.sessionID);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
activeSession.audioProcess = audioProcess;
|
|
241
|
+
await audioProcess.start();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Sets up talkback (return audio) if enabled in the camera config.
|
|
246
|
+
*/
|
|
247
|
+
async setupTalkback(activeSession, sessionInfo) {
|
|
248
|
+
if (!this.camera.cameraConfig.talkback) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const talkbackParams = await FFmpegParameters.forAudio(this.videoConfig.debug);
|
|
252
|
+
await talkbackParams.setTalkbackInput(sessionInfo);
|
|
253
|
+
if (this.camera.cameraConfig.talkbackChannels) {
|
|
254
|
+
talkbackParams.setTalkbackChannels(this.camera.cameraConfig.talkbackChannels);
|
|
255
|
+
}
|
|
256
|
+
activeSession.talkbackStream = new TalkbackStream(this.camera.platform, this.device);
|
|
257
|
+
activeSession.returnProcess = new FFmpeg('[Talkback Process]', talkbackParams);
|
|
258
|
+
activeSession.returnProcess.on('error', (error) => {
|
|
259
|
+
this.log.error('Talkback process ended with error: ' + error);
|
|
260
|
+
});
|
|
261
|
+
await activeSession.returnProcess.start();
|
|
262
|
+
activeSession.returnProcess.stdout?.pipe(activeSession.talkbackStream);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Transfers session from pending to ongoing, or stops it immediately if it was cancelled.
|
|
266
|
+
*/
|
|
267
|
+
finalizeSession(sessionId, activeSession) {
|
|
268
|
+
const pendingSession = this.pendingSessions.get(sessionId);
|
|
269
|
+
this.ongoingSessions.set(sessionId, activeSession);
|
|
270
|
+
if (pendingSession) {
|
|
271
|
+
this.pendingSessions.delete(sessionId);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
this.log.info('Session was cancelled before start completed. Stopping immediately.');
|
|
275
|
+
this.stopStream(sessionId);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Captures a snapshot from the currently running livestream after a brief
|
|
280
|
+
* delay to allow the stream to produce stable frames.
|
|
281
|
+
*/
|
|
282
|
+
captureSnapshotFromLivestream() {
|
|
283
|
+
setTimeout(() => {
|
|
284
|
+
this.snapshotDelegate.captureSnapshotFromActiveLivestream().catch((error) => {
|
|
285
|
+
this.log.debug('Snapshot capture from livestream failed: ' + error);
|
|
286
|
+
});
|
|
287
|
+
}, StreamingDelegate.LIVESTREAM_SNAPSHOT_DELAY_MS);
|
|
288
|
+
}
|
|
289
|
+
handleStreamRequest(request, callback) {
|
|
290
|
+
switch (request.type) {
|
|
291
|
+
case "start" /* StreamRequestTypes.START */:
|
|
292
|
+
this.log.debug(`Received request to start stream with id ${request.sessionID}`, request);
|
|
293
|
+
this.startStream(request, callback);
|
|
294
|
+
break;
|
|
295
|
+
case "reconfigure" /* StreamRequestTypes.RECONFIGURE */:
|
|
296
|
+
this.log.debug(`Reconfigure request: ${request.video.width}x${request.video.height}, ` +
|
|
297
|
+
`${request.video.fps} fps, ${request.video.max_bit_rate} kbps (Ignored)`);
|
|
298
|
+
callback();
|
|
299
|
+
break;
|
|
300
|
+
case "stop" /* StreamRequestTypes.STOP */:
|
|
301
|
+
this.log.debug('Receive Apple HK Stop request', request);
|
|
302
|
+
this.stopStream(request.sessionID);
|
|
303
|
+
callback();
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
stopStream(sessionId) {
|
|
308
|
+
this.log.debug('Stopping session with id: ' + sessionId);
|
|
309
|
+
this.pendingSessions.delete(sessionId);
|
|
310
|
+
const session = this.ongoingSessions.get(sessionId);
|
|
311
|
+
if (!session) {
|
|
312
|
+
this.log.debug('No session to stop.');
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (session.timeout) {
|
|
316
|
+
clearTimeout(session.timeout);
|
|
317
|
+
}
|
|
318
|
+
const cleanupSteps = [
|
|
319
|
+
['returnAudio FFmpeg process', () => {
|
|
320
|
+
session.talkbackStream?.stopTalkbackStream();
|
|
321
|
+
session.returnProcess?.stdout?.unpipe();
|
|
322
|
+
session.returnProcess?.stop();
|
|
323
|
+
}],
|
|
324
|
+
['video FFmpeg process', () => session.videoProcess?.stop()],
|
|
325
|
+
['audio FFmpeg process', () => session.audioProcess?.stop()],
|
|
326
|
+
['socket', () => session.socket?.close()],
|
|
327
|
+
['Eufy Station livestream', () => {
|
|
328
|
+
if (!isRtspReady(this.device, this.camera.cameraConfig)) {
|
|
329
|
+
this.localLivestreamManager.stopLocalLiveStream();
|
|
330
|
+
}
|
|
331
|
+
}],
|
|
332
|
+
];
|
|
333
|
+
for (const [label, cleanup] of cleanupSteps) {
|
|
334
|
+
try {
|
|
335
|
+
cleanup();
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
this.log.error(`Error occurred terminating ${label}: ${error}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
this.ongoingSessions.delete(sessionId);
|
|
342
|
+
this.log.info('Stopped video stream.');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=streamingDelegate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamingDelegate.js","sourceRoot":"","sources":["../../src/controller/streamingDelegate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
|
|
2
|
+
import { EufySecurityPlatform } from './platform.js';
|
|
3
|
+
import { setHap } from './utils/utils.js';
|
|
4
|
+
/**
|
|
5
|
+
* This method registers the platform with Homebridge
|
|
6
|
+
*/
|
|
7
|
+
export default (api) => {
|
|
8
|
+
setHap(api.hap);
|
|
9
|
+
api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, EufySecurityPlatform);
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;GAEG;AACH,eAAe,CAAC,GAAQ,EAAE,EAAE;IAC1B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,GAAG,CAAC,gBAAgB,CAAC,WAAW,EAAE,aAAa,EAAE,oBAAoB,CAAC,CAAC;AACzE,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":""}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|