homebridge-ring 10.0.0-beta.1 → 10.0.0-beta.2
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 +12 -0
- package/lib/api/live-call.d.ts +6 -2
- package/lib/api/live-call.js +129 -25
- package/lib/api/peer-connection.d.ts +7 -4
- package/lib/api/peer-connection.js +25 -6
- package/lib/api/ring-camera.d.ts +1 -0
- package/lib/api/ring-camera.js +6 -16
- package/lib/api/ring-types.d.ts +7 -15
- package/package.json +1 -1
- package/lib/api/rtp-utils.d.ts +0 -26
- package/lib/api/rtp-utils.js +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [10.0.0-beta.2](https://github.com/dgreif/ring/compare/v10.0.0-beta.1...v10.0.0-beta.2) (2022-03-26)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* support ring edge camera streaming ([b30d99f](https://github.com/dgreif/ring/commit/b30d99f9ffaa1fabc1d09b830cf8ba0e69fe84a0))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **api:** allow snapshot to be force-updated based on options ([fa0212a](https://github.com/dgreif/ring/commit/fa0212ab539cc268f8000c5b9ea39a00799cb8d7))
|
|
16
|
+
|
|
5
17
|
## [10.0.0-beta.1](https://github.com/dgreif/ring/compare/v10.0.0-beta.0...v10.0.0-beta.1) (2022-02-27)
|
|
6
18
|
|
|
7
19
|
|
package/lib/api/live-call.d.ts
CHANGED
|
@@ -10,25 +10,29 @@ export interface FfmpegOptions {
|
|
|
10
10
|
output: SpawnInput[];
|
|
11
11
|
}
|
|
12
12
|
export declare class LiveCall extends Subscribed {
|
|
13
|
-
private sessionId;
|
|
14
13
|
private camera;
|
|
15
14
|
private readonly ws;
|
|
16
15
|
private readonly onWsOpen;
|
|
17
16
|
private readonly onMessage;
|
|
18
17
|
private readonly pc;
|
|
18
|
+
readonly onSessionId: ReplaySubject<string>;
|
|
19
19
|
readonly onCallAnswered: ReplaySubject<string>;
|
|
20
20
|
readonly onCallEnded: ReplaySubject<void>;
|
|
21
21
|
private readonly audioSplitter;
|
|
22
22
|
private readonly videoSplitter;
|
|
23
23
|
readonly onVideoRtp: import("rxjs").Subject<RtpPacket>;
|
|
24
24
|
readonly onAudioRtp: import("rxjs").Subject<RtpPacket>;
|
|
25
|
-
|
|
25
|
+
private readonly onOfferSent;
|
|
26
|
+
constructor(authToken: string, camera: RingCamera);
|
|
27
|
+
private initiateCall;
|
|
28
|
+
private sessionId;
|
|
26
29
|
private handleMessage;
|
|
27
30
|
reservePort(bufferPorts?: number): Promise<number>;
|
|
28
31
|
startTranscoding(ffmpegOptions: FfmpegOptions): Promise<void>;
|
|
29
32
|
activated: boolean;
|
|
30
33
|
activate(): Promise<void>;
|
|
31
34
|
activateCameraSpeaker(): Promise<void>;
|
|
35
|
+
private sendSessionMessage;
|
|
32
36
|
private sendMessage;
|
|
33
37
|
private callEnded;
|
|
34
38
|
stop(): void;
|
package/lib/api/live-call.js
CHANGED
|
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.LiveCall = void 0;
|
|
13
|
-
const rtp_utils_1 = require("./rtp-utils");
|
|
14
13
|
const ws_1 = require("ws");
|
|
15
14
|
const rxjs_1 = require("rxjs");
|
|
16
15
|
const peer_connection_1 = require("./peer-connection");
|
|
@@ -19,6 +18,17 @@ const operators_1 = require("rxjs/operators");
|
|
|
19
18
|
const subscribed_1 = require("./subscribed");
|
|
20
19
|
const camera_utils_1 = require("@homebridge/camera-utils");
|
|
21
20
|
const ffmpeg_1 = require("./ffmpeg");
|
|
21
|
+
// eslint-disable-next-line no-shadow
|
|
22
|
+
var CloseReasonCode;
|
|
23
|
+
(function (CloseReasonCode) {
|
|
24
|
+
CloseReasonCode[CloseReasonCode["NormalClose"] = 0] = "NormalClose";
|
|
25
|
+
// reason: { code: 5, text: '[rsl-apps/webrtc-liveview-server/Session.cpp:429] [Auth] [0xd540]: [rsl-apps/session-manager/Manager.cpp:227] [AppAuth] Unauthorized: invalid or expired token' }
|
|
26
|
+
// reason: { code: 5, text: 'Authentication failed: -1' }
|
|
27
|
+
// reason: { code: 5, text: 'Sessions with the provided ID not found' }
|
|
28
|
+
CloseReasonCode[CloseReasonCode["AuthenticationFailed"] = 5] = "AuthenticationFailed";
|
|
29
|
+
// reason: { code: 6, text: 'Timeout waiting for ping' }
|
|
30
|
+
CloseReasonCode[CloseReasonCode["Timeout"] = 6] = "Timeout";
|
|
31
|
+
})(CloseReasonCode || (CloseReasonCode = {}));
|
|
22
32
|
function getCleanSdp(sdp, includeVideo) {
|
|
23
33
|
return sdp
|
|
24
34
|
.split('\nm=')
|
|
@@ -28,22 +38,25 @@ function getCleanSdp(sdp, includeVideo) {
|
|
|
28
38
|
.join('\n');
|
|
29
39
|
}
|
|
30
40
|
class LiveCall extends subscribed_1.Subscribed {
|
|
31
|
-
constructor(
|
|
41
|
+
constructor(authToken, camera) {
|
|
32
42
|
super();
|
|
33
|
-
this.sessionId = sessionId;
|
|
34
43
|
this.camera = camera;
|
|
44
|
+
this.onSessionId = new rxjs_1.ReplaySubject(1);
|
|
35
45
|
this.onCallAnswered = new rxjs_1.ReplaySubject(1);
|
|
36
46
|
this.onCallEnded = new rxjs_1.ReplaySubject(1);
|
|
37
47
|
this.audioSplitter = new camera_utils_1.RtpSplitter();
|
|
38
48
|
this.videoSplitter = new camera_utils_1.RtpSplitter();
|
|
49
|
+
this.onOfferSent = new rxjs_1.ReplaySubject(1);
|
|
50
|
+
this.sessionId = null;
|
|
39
51
|
this.activated = false;
|
|
40
|
-
const liveCallSession = (0, rtp_utils_1.parseLiveCallSession)(sessionId);
|
|
41
52
|
this.pc = new peer_connection_1.PeerConnection();
|
|
42
|
-
this.ws = new ws_1.WebSocket(
|
|
53
|
+
this.ws = new ws_1.WebSocket('wss://api.prod.signalling.ring.devices.a2z.com:443/ws', {
|
|
43
54
|
headers: {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
Authorization: `Bearer ${authToken}`,
|
|
56
|
+
'X-Sig-API-Version': '4.0',
|
|
57
|
+
'X-Sig-Client-ID': 'ring_android-aabb123',
|
|
58
|
+
'X-Sig-Client-Info': 'Ring/3.49.0;Platform/Android;OS/7.0;Density/2.0;Device/samsung-SM-T710;Locale/en-US;TimeZone/GMT-07:00',
|
|
59
|
+
'X-Sig-Auth-Type': 'ring_oauth',
|
|
47
60
|
},
|
|
48
61
|
});
|
|
49
62
|
this.onAudioRtp = this.pc.onAudioRtp;
|
|
@@ -57,28 +70,109 @@ class LiveCall extends subscribed_1.Subscribed {
|
|
|
57
70
|
}))
|
|
58
71
|
.subscribe(), this.onWsOpen.subscribe(() => {
|
|
59
72
|
(0, util_1.logDebug)(`WebSocket connected for ${this.camera.name}`);
|
|
73
|
+
this.initiateCall().catch((e) => {
|
|
74
|
+
(0, util_1.logError)(e);
|
|
75
|
+
this.callEnded();
|
|
76
|
+
});
|
|
60
77
|
}), onError.subscribe((e) => {
|
|
61
78
|
(0, util_1.logError)(e);
|
|
62
79
|
this.callEnded();
|
|
63
80
|
}), onClose.subscribe(() => {
|
|
64
81
|
this.callEnded();
|
|
82
|
+
}), this.onCallAnswered
|
|
83
|
+
.pipe((0, operators_1.switchMap)(() => (0, rxjs_1.interval)(5000)))
|
|
84
|
+
.subscribe(() => {
|
|
85
|
+
if (!this.sessionId) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.sendSessionMessage('ping');
|
|
89
|
+
}), this.pc.onIceCandidate.subscribe((iceCandidate) => __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
yield (0, rxjs_1.firstValueFrom)(this.onOfferSent);
|
|
91
|
+
this.sendMessage({
|
|
92
|
+
method: 'ice',
|
|
93
|
+
body: {
|
|
94
|
+
doorbot_id: this.camera.id,
|
|
95
|
+
ice: iceCandidate.candidate,
|
|
96
|
+
mlineindex: 0,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
// HACK: send ice candidate with both mline indexes to convince ring edge to connect both audio and video
|
|
100
|
+
// Without this, only audio will connect unless you connect from the network of the Ring Edge router
|
|
101
|
+
this.sendMessage({
|
|
102
|
+
method: 'ice',
|
|
103
|
+
body: {
|
|
104
|
+
doorbot_id: this.camera.id,
|
|
105
|
+
ice: iceCandidate.candidate,
|
|
106
|
+
mlineindex: 1,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
})), this.pc.onConnectionState.subscribe((state) => {
|
|
110
|
+
if (state === 'failed') {
|
|
111
|
+
(0, util_1.logError)('Stream connection failed');
|
|
112
|
+
this.callEnded();
|
|
113
|
+
}
|
|
114
|
+
if (state === 'closed') {
|
|
115
|
+
(0, util_1.logDebug)('Stream connection closed');
|
|
116
|
+
this.callEnded();
|
|
117
|
+
}
|
|
65
118
|
}));
|
|
66
119
|
}
|
|
120
|
+
initiateCall() {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
const offer = yield this.pc.createOffer();
|
|
123
|
+
offer.sdp = offer.sdp.replace('\na=group:BUNDLE 0 1', '');
|
|
124
|
+
this.sendMessage({
|
|
125
|
+
method: 'live_view',
|
|
126
|
+
body: {
|
|
127
|
+
doorbot_id: this.camera.id,
|
|
128
|
+
stream_options: { audio_enabled: true, video_enabled: true },
|
|
129
|
+
sdp: offer.sdp,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
this.onOfferSent.next();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
67
135
|
handleMessage(message) {
|
|
68
136
|
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
if (message.body.doorbot_id !== this.camera.id) {
|
|
138
|
+
// ignore messages for other cameras
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (['session_created', 'session_started'].includes(message.method) &&
|
|
142
|
+
'session_id' in message.body &&
|
|
143
|
+
!this.sessionId) {
|
|
144
|
+
this.sessionId = message.body.session_id;
|
|
145
|
+
this.onSessionId.next(this.sessionId);
|
|
146
|
+
}
|
|
147
|
+
if (message.body.session_id && message.body.session_id !== this.sessionId) {
|
|
148
|
+
// ignore messages for other sessions
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
69
151
|
switch (message.method) {
|
|
152
|
+
case 'session_created':
|
|
153
|
+
case 'session_started':
|
|
154
|
+
// session already stored above
|
|
155
|
+
return;
|
|
70
156
|
case 'sdp':
|
|
71
|
-
|
|
72
|
-
this.
|
|
73
|
-
this.onCallAnswered.next(message.sdp);
|
|
157
|
+
yield this.pc.acceptAnswer(message.body);
|
|
158
|
+
this.onCallAnswered.next(message.body.sdp);
|
|
74
159
|
return;
|
|
75
160
|
case 'ice':
|
|
76
161
|
yield this.pc.addIceCandidate({
|
|
77
|
-
candidate: message.ice,
|
|
78
|
-
sdpMLineIndex: message.mlineindex,
|
|
162
|
+
candidate: message.body.ice,
|
|
163
|
+
sdpMLineIndex: message.body.mlineindex,
|
|
79
164
|
});
|
|
80
165
|
return;
|
|
166
|
+
case 'pong':
|
|
167
|
+
return;
|
|
168
|
+
case 'close':
|
|
169
|
+
(0, util_1.logError)('Video stream closed');
|
|
170
|
+
(0, util_1.logError)(message.body);
|
|
171
|
+
this.callEnded();
|
|
172
|
+
return;
|
|
81
173
|
}
|
|
174
|
+
(0, util_1.logError)('UNKNOWN MESSAGE');
|
|
175
|
+
(0, util_1.logError)(message);
|
|
82
176
|
});
|
|
83
177
|
}
|
|
84
178
|
reservePort(bufferPorts = 0) {
|
|
@@ -142,32 +236,42 @@ class LiveCall extends subscribed_1.Subscribed {
|
|
|
142
236
|
return;
|
|
143
237
|
}
|
|
144
238
|
this.activated = true;
|
|
145
|
-
yield (0, rxjs_1.firstValueFrom)(this.
|
|
146
|
-
|
|
147
|
-
this.
|
|
148
|
-
video_enabled: true,
|
|
149
|
-
audio_enabled: true,
|
|
150
|
-
method: 'stream_options',
|
|
151
|
-
});
|
|
239
|
+
yield (0, rxjs_1.firstValueFrom)(this.pc.onConnectionState.pipe((0, operators_1.filter)((state) => state === 'connected')));
|
|
240
|
+
(0, util_1.logInfo)('Activating Session');
|
|
241
|
+
this.sendSessionMessage('activate_session');
|
|
152
242
|
});
|
|
153
243
|
}
|
|
154
244
|
activateCameraSpeaker() {
|
|
155
245
|
return __awaiter(this, void 0, void 0, function* () {
|
|
156
246
|
yield (0, rxjs_1.firstValueFrom)(this.onCallAnswered);
|
|
157
|
-
this.
|
|
247
|
+
this.sendSessionMessage('camera_options', {
|
|
158
248
|
stealth_mode: false,
|
|
159
|
-
method: 'camera_options',
|
|
160
249
|
});
|
|
161
250
|
});
|
|
162
251
|
}
|
|
252
|
+
sendSessionMessage(method, body = {}) {
|
|
253
|
+
const message = {
|
|
254
|
+
method,
|
|
255
|
+
body: Object.assign(Object.assign({}, body), { doorbot_id: this.camera.id, session_id: this.sessionId }),
|
|
256
|
+
};
|
|
257
|
+
if (this.sessionId) {
|
|
258
|
+
// Send immediately if we already have a session id
|
|
259
|
+
// This is needed to send `close` before closing the websocket
|
|
260
|
+
this.sendMessage(message);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
(0, rxjs_1.firstValueFrom)(this.onSessionId)
|
|
264
|
+
.then(() => this.sendMessage(message))
|
|
265
|
+
.catch((e) => (0, util_1.logError)(e));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
163
268
|
sendMessage(message) {
|
|
164
269
|
this.ws.send(JSON.stringify(message));
|
|
165
270
|
}
|
|
166
271
|
callEnded() {
|
|
167
272
|
try {
|
|
168
|
-
this.
|
|
169
|
-
reason: { code:
|
|
170
|
-
method: 'close',
|
|
273
|
+
this.sendSessionMessage('close', {
|
|
274
|
+
reason: { code: CloseReasonCode.NormalClose, text: '' },
|
|
171
275
|
});
|
|
172
276
|
this.ws.close();
|
|
173
277
|
}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { MediaStreamTrack, RTCIceCandidate, RTCPeerConnection, RtcpPacket, RtpPacket } from '@koush/werift';
|
|
2
|
-
import { Subject } from 'rxjs';
|
|
2
|
+
import { ReplaySubject, Subject } from 'rxjs';
|
|
3
3
|
export declare class PeerConnection {
|
|
4
4
|
pc: RTCPeerConnection;
|
|
5
5
|
onAudioRtp: Subject<RtpPacket>;
|
|
6
6
|
onAudioRtcp: Subject<RtcpPacket>;
|
|
7
7
|
onVideoRtp: Subject<RtpPacket>;
|
|
8
8
|
onVideoRtcp: Subject<RtcpPacket>;
|
|
9
|
+
onIceCandidate: Subject<RTCIceCandidate>;
|
|
10
|
+
onConnectionState: ReplaySubject<"failed" | "closed" | "connected" | "connecting" | "new" | "disconnected">;
|
|
9
11
|
returnAudioTrack: MediaStreamTrack;
|
|
10
12
|
constructor();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
createOffer(): Promise<import("@koush/werift").RTCSessionDescription>;
|
|
14
|
+
acceptAnswer(answer: {
|
|
15
|
+
type: 'answer';
|
|
13
16
|
sdp: string;
|
|
14
|
-
}): Promise<
|
|
17
|
+
}): Promise<void>;
|
|
15
18
|
addIceCandidate(candidate: RTCIceCandidate): Promise<void>;
|
|
16
19
|
close(): void;
|
|
17
20
|
}
|
|
@@ -20,6 +20,8 @@ class PeerConnection {
|
|
|
20
20
|
this.onAudioRtcp = new rxjs_1.Subject();
|
|
21
21
|
this.onVideoRtp = new rxjs_1.Subject();
|
|
22
22
|
this.onVideoRtcp = new rxjs_1.Subject();
|
|
23
|
+
this.onIceCandidate = new rxjs_1.Subject();
|
|
24
|
+
this.onConnectionState = new rxjs_1.ReplaySubject(1);
|
|
23
25
|
this.returnAudioTrack = new werift_1.MediaStreamTrack({ kind: 'audio' });
|
|
24
26
|
const pc = (this.pc = new werift_1.RTCPeerConnection({
|
|
25
27
|
codecs: {
|
|
@@ -41,7 +43,7 @@ class PeerConnection {
|
|
|
41
43
|
{ type: 'nack', parameter: 'pli' },
|
|
42
44
|
{ type: 'goog-remb' },
|
|
43
45
|
],
|
|
44
|
-
parameters: '
|
|
46
|
+
parameters: 'profile-level-id=42801F',
|
|
45
47
|
}),
|
|
46
48
|
],
|
|
47
49
|
},
|
|
@@ -77,13 +79,30 @@ class PeerConnection {
|
|
|
77
79
|
setInterval(() => videoTransceiver.receiver.sendRtcpPLI(track.ssrc), 2000);
|
|
78
80
|
});
|
|
79
81
|
});
|
|
82
|
+
this.pc.onIceCandidate.subscribe((iceCandidate) => {
|
|
83
|
+
this.onIceCandidate.next(iceCandidate);
|
|
84
|
+
});
|
|
85
|
+
pc.iceConnectionStateChange.subscribe(() => {
|
|
86
|
+
(0, util_1.logInfo)(`iceConnectionStateChange: ${pc.iceConnectionState}`);
|
|
87
|
+
if (pc.iceConnectionState === 'closed') {
|
|
88
|
+
this.onConnectionState.next('closed');
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
pc.connectionStateChange.subscribe(() => {
|
|
92
|
+
(0, util_1.logInfo)(`connectionStateChange: ${pc.connectionState}`);
|
|
93
|
+
this.onConnectionState.next(pc.connectionState);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
createOffer() {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const offer = yield this.pc.createOffer();
|
|
99
|
+
yield this.pc.setLocalDescription(offer);
|
|
100
|
+
return offer;
|
|
101
|
+
});
|
|
80
102
|
}
|
|
81
|
-
|
|
103
|
+
acceptAnswer(answer) {
|
|
82
104
|
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
-
yield this.pc.setRemoteDescription(
|
|
84
|
-
const answer = yield this.pc.createAnswer();
|
|
85
|
-
yield this.pc.setLocalDescription(answer);
|
|
86
|
-
return answer;
|
|
105
|
+
yield this.pc.setRemoteDescription(answer);
|
|
87
106
|
});
|
|
88
107
|
}
|
|
89
108
|
addIceCandidate(candidate) {
|
package/lib/api/ring-camera.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export declare class RingCamera extends Subscribed {
|
|
|
42
42
|
get isCharging(): boolean;
|
|
43
43
|
get operatingOnBattery(): boolean;
|
|
44
44
|
get isOffline(): boolean;
|
|
45
|
+
get isRingEdgeEnabled(): boolean;
|
|
45
46
|
get hasInHomeDoorbell(): boolean;
|
|
46
47
|
doorbotUrl(path?: string): string;
|
|
47
48
|
deviceUrl(path?: string): string;
|
package/lib/api/ring-camera.js
CHANGED
|
@@ -145,6 +145,9 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
145
145
|
get isOffline() {
|
|
146
146
|
return this.data.alerts.connection === 'offline';
|
|
147
147
|
}
|
|
148
|
+
get isRingEdgeEnabled() {
|
|
149
|
+
return this.data.settings.sheila_settings.local_storage_enabled === true;
|
|
150
|
+
}
|
|
148
151
|
get hasInHomeDoorbell() {
|
|
149
152
|
const { chime_settings } = this.data.settings;
|
|
150
153
|
return (this.isDoorbot &&
|
|
@@ -231,21 +234,8 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
231
234
|
}
|
|
232
235
|
startLiveCall() {
|
|
233
236
|
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
method: 'POST',
|
|
237
|
-
url: this.doorbotUrl('live_call'),
|
|
238
|
-
})
|
|
239
|
-
.catch((e) => {
|
|
240
|
-
var _a;
|
|
241
|
-
if (((_a = e.response) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) {
|
|
242
|
-
const errorMessage = `Camera ${this.name} returned 403 when starting a live stream. This usually indicates that live streaming is blocked by Modes settings. Check your Ring app and verify that you are able to stream from this camera with the current Modes settings.`;
|
|
243
|
-
(0, util_1.logError)(errorMessage);
|
|
244
|
-
throw new Error(errorMessage);
|
|
245
|
-
}
|
|
246
|
-
throw e;
|
|
247
|
-
});
|
|
248
|
-
return new live_call_1.LiveCall(liveCall.data.session_id, this);
|
|
237
|
+
const auth = yield this.restClient.getCurrentAuth();
|
|
238
|
+
return new live_call_1.LiveCall(auth.access_token, this);
|
|
249
239
|
});
|
|
250
240
|
}
|
|
251
241
|
removeDingById(idToRemove) {
|
|
@@ -362,7 +352,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
362
352
|
getNextSnapshot({ afterMs, maxWaitMs, force, }) {
|
|
363
353
|
return __awaiter(this, void 0, void 0, function* () {
|
|
364
354
|
const response = yield this.restClient.request({
|
|
365
|
-
url: `https://app-snaps.ring.com/snapshots/next/${this.id}
|
|
355
|
+
url: `https://app-snaps.ring.com/snapshots/next/${this.id}`,
|
|
366
356
|
responseType: 'buffer',
|
|
367
357
|
searchParams: {
|
|
368
358
|
'after-ms': afterMs,
|
package/lib/api/ring-types.d.ts
CHANGED
|
@@ -379,6 +379,13 @@ export interface CameraData {
|
|
|
379
379
|
live_view_disabled?: boolean;
|
|
380
380
|
motion_detection_enabled?: boolean;
|
|
381
381
|
power_mode?: 'battery' | 'wired';
|
|
382
|
+
sheila_settings: {
|
|
383
|
+
cv_processing_enabled: boolean | null;
|
|
384
|
+
local_storage_enabled: boolean | null;
|
|
385
|
+
};
|
|
386
|
+
server_settings: {
|
|
387
|
+
ring_media_server_enabled: boolean;
|
|
388
|
+
};
|
|
382
389
|
};
|
|
383
390
|
features: {
|
|
384
391
|
motions_enabled: boolean;
|
|
@@ -689,21 +696,6 @@ export interface ActiveDing {
|
|
|
689
696
|
sip_token: string;
|
|
690
697
|
sip_ding_id: string;
|
|
691
698
|
}
|
|
692
|
-
export interface LiveCallResponse {
|
|
693
|
-
ding_id: string;
|
|
694
|
-
ding_kind: DingKind;
|
|
695
|
-
device_id: number;
|
|
696
|
-
device_kind: RingCameraKind;
|
|
697
|
-
device_description: string;
|
|
698
|
-
state: DingState;
|
|
699
|
-
protocol: 'ring_media_server' | unknown;
|
|
700
|
-
now: number;
|
|
701
|
-
video_jitter_buffer_ms: number;
|
|
702
|
-
audio_jitter_buffer_ms: number;
|
|
703
|
-
data: {
|
|
704
|
-
session_id: string;
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
699
|
export interface AuthTokenResponse {
|
|
708
700
|
access_token: string;
|
|
709
701
|
expires_in: number;
|
package/package.json
CHANGED
package/lib/api/rtp-utils.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { DingKind } from './ring-types';
|
|
2
|
-
export interface LiveCallSession {
|
|
3
|
-
alexa_port: 18443;
|
|
4
|
-
app_session_token: string;
|
|
5
|
-
availability_zone: 'availability-zone';
|
|
6
|
-
custom_timer: {
|
|
7
|
-
max_sec: number;
|
|
8
|
-
};
|
|
9
|
-
ding_id: string;
|
|
10
|
-
ding_kind: DingKind;
|
|
11
|
-
doorbot_id: number;
|
|
12
|
-
exp: number;
|
|
13
|
-
ip: string;
|
|
14
|
-
port: number;
|
|
15
|
-
private_ip: string;
|
|
16
|
-
rms_fqdn: string;
|
|
17
|
-
rms_version: string;
|
|
18
|
-
rsp_port: number;
|
|
19
|
-
rtsp_port: number;
|
|
20
|
-
session_id: string;
|
|
21
|
-
sip_port: number;
|
|
22
|
-
webrtc_port: number;
|
|
23
|
-
webrtc_url: string;
|
|
24
|
-
wwr_port: number;
|
|
25
|
-
}
|
|
26
|
-
export declare function parseLiveCallSession(sessionId: string): LiveCallSession;
|
package/lib/api/rtp-utils.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseLiveCallSession = void 0;
|
|
4
|
-
function parseLiveCallSession(sessionId) {
|
|
5
|
-
const encodedSession = sessionId.split('.')[1], buff = Buffer.from(encodedSession, 'base64'), text = buff.toString('ascii');
|
|
6
|
-
return JSON.parse(text);
|
|
7
|
-
}
|
|
8
|
-
exports.parseLiveCallSession = parseLiveCallSession;
|