@camera.ui/camera-ui-ring 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 ADDED
@@ -0,0 +1,8 @@
1
+ All notable changes to this project will be documented in this file.
2
+
3
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
4
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## [1.0.0] - 2019-08-06
7
+
8
+ - Initial Release
package/LICENSE.md ADDED
File without changes
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # camera-ui-ring
@@ -0,0 +1,21 @@
1
+ /// <reference types="pouchdb-core" />
2
+ /// <reference types="node" />
3
+ import { WebSocketServer } from 'ws';
4
+ import type { RingCamera } from 'ring-client-api';
5
+ import type { PluginLogger } from '@camera.ui/types';
6
+ import type { Config } from './types';
7
+ export declare class WebRtcConnection {
8
+ ws?: WebSocketServer;
9
+ private camera;
10
+ private call?;
11
+ private receiver?;
12
+ private pc?;
13
+ private config;
14
+ private logger;
15
+ constructor(camera: RingCamera, config: Config, logger: PluginLogger);
16
+ connect(): void;
17
+ close(): void;
18
+ snapshot(): Promise<Buffer | undefined>;
19
+ private cleanUp;
20
+ private createPeerCoonection;
21
+ }
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebRtcConnection = void 0;
4
+ const ws_1 = require("ws");
5
+ const peer_1 = require("./peer");
6
+ const werift_1 = require("werift");
7
+ class WebRtcConnection {
8
+ ws;
9
+ camera;
10
+ call;
11
+ receiver;
12
+ pc;
13
+ config;
14
+ logger;
15
+ constructor(camera, config, logger) {
16
+ this.config = config;
17
+ this.logger = logger;
18
+ this.camera = camera;
19
+ this.connect();
20
+ }
21
+ connect() {
22
+ this.ws = new ws_1.WebSocketServer({ noServer: true });
23
+ let info;
24
+ if (this.config.server.username && this.config.server.password) {
25
+ info = '?username=<redacted>&password=<redacted>';
26
+ }
27
+ this.logger.log(`${this.camera.name} is listening on ws://localhost:${this.config.server.listen}/${this.camera.name}${info} (webrtc)`);
28
+ this.logger.log(`${this.camera.name} is listening on http://localhost:${this.config.server.listen}/${this.camera.name}${info} (snapshot)`);
29
+ this.ws.on('connection', (socket) => {
30
+ this.cleanUp();
31
+ this.receiver = new peer_1.CustomPeerConnection();
32
+ const audioTrack = new werift_1.MediaStreamTrack({ kind: 'audio' });
33
+ this.receiver.onAudioRtp.subscribe((rtp) => {
34
+ audioTrack.writeRtp(rtp);
35
+ });
36
+ const videoTrack = new werift_1.MediaStreamTrack({ kind: 'video' });
37
+ this.receiver.onVideoRtp.subscribe((rtp) => {
38
+ videoTrack.writeRtp(rtp);
39
+ });
40
+ this.pc = this.createPeerCoonection();
41
+ this.pc.iceConnectionStateChange.subscribe(async (ev) => {
42
+ this.logger.debug(`${this.camera.name}: iceConnectionStateChange: ${ev}`);
43
+ if (ev === 'disconnected' || ev === 'failed' || ev === 'closed') {
44
+ this.cleanUp();
45
+ }
46
+ });
47
+ this.pc.onTrack.subscribe((track) => {
48
+ if (track.kind === 'audio') {
49
+ track.onReceiveRtp.subscribe((rtp) => {
50
+ this.receiver.returnAudioTrack.writeRtp(rtp);
51
+ });
52
+ }
53
+ });
54
+ this.pc.addTransceiver(videoTrack, { direction: 'sendonly' });
55
+ this.pc.addTransceiver(audioTrack, { direction: 'sendonly' });
56
+ socket.on('message', async (data) => {
57
+ try {
58
+ const go2rtcMsg = JSON.parse(data);
59
+ switch (go2rtcMsg.type) {
60
+ case 'webrtc/offer':
61
+ // console.log('OFFER', go2rtcMsg.value);
62
+ this.call = await this.camera.startLiveCall({
63
+ createPeerConnection: () => this.receiver,
64
+ });
65
+ this.call.onCallEnded.subscribe(() => {
66
+ this.logger.debug(`${this.camera.name}: Live Call ended`);
67
+ });
68
+ if (!this.call.cameraSpeakerActivated) {
69
+ this.call.activateCameraSpeaker();
70
+ }
71
+ this.logger.debug(`${this.camera.name}: Live Call started`);
72
+ await this.pc.setRemoteDescription(new werift_1.RTCSessionDescription(go2rtcMsg.value, 'offer'));
73
+ const answer = await this.pc.createAnswer();
74
+ await this.pc.setLocalDescription(answer);
75
+ // console.log('ANSWER', answer.sdp);
76
+ const answerMsg = { type: 'webrtc/answer', value: answer.sdp };
77
+ socket.send(JSON.stringify(answerMsg));
78
+ break;
79
+ case 'webrtc/candidate':
80
+ await this.pc?.addIceCandidate({
81
+ candidate: go2rtcMsg.value,
82
+ });
83
+ break;
84
+ }
85
+ }
86
+ catch (error) {
87
+ this.logger.error(this.camera.name, error.message);
88
+ this.logger.log(error.stack);
89
+ }
90
+ });
91
+ });
92
+ }
93
+ close() {
94
+ this.cleanUp();
95
+ this.ws?.removeAllListeners();
96
+ this.ws?.close();
97
+ this.ws = undefined;
98
+ }
99
+ async snapshot() {
100
+ try {
101
+ return await this.camera.getSnapshot();
102
+ }
103
+ catch (error) {
104
+ this.logger.error(this.camera.name, error.message);
105
+ }
106
+ }
107
+ cleanUp() {
108
+ this.receiver?.close();
109
+ this.receiver = undefined;
110
+ this.call?.stop();
111
+ this.call?.onCallEnded.unsubscribe();
112
+ this.call = undefined;
113
+ this.pc?.iceConnectionStateChange.allUnsubscribe();
114
+ this.pc?.onTrack.allUnsubscribe();
115
+ this.pc?.removeAllListeners();
116
+ this.pc?.close();
117
+ this.pc = undefined;
118
+ }
119
+ createPeerCoonection() {
120
+ return new werift_1.RTCPeerConnection({
121
+ codecs: {
122
+ video: [
123
+ new werift_1.RTCRtpCodecParameters({
124
+ mimeType: 'video/H264',
125
+ clockRate: 90000,
126
+ payloadType: 96,
127
+ rtcpFeedback: [{ type: 'transport-cc' }, { type: 'ccm', parameter: 'fir' }, { type: 'nack' }, { type: 'nack', parameter: 'pli' }, { type: 'goog-remb' }],
128
+ parameters: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f',
129
+ }),
130
+ new werift_1.RTCRtpCodecParameters({
131
+ mimeType: 'video/H264',
132
+ clockRate: 90000,
133
+ payloadType: 97,
134
+ rtcpFeedback: [{ type: 'transport-cc' }, { type: 'ccm', parameter: 'fir' }, { type: 'nack' }, { type: 'nack', parameter: 'pli' }, { type: 'goog-remb' }],
135
+ parameters: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f',
136
+ }),
137
+ new werift_1.RTCRtpCodecParameters({
138
+ mimeType: 'video/H264',
139
+ clockRate: 90000,
140
+ payloadType: 98,
141
+ rtcpFeedback: [{ type: 'transport-cc' }, { type: 'ccm', parameter: 'fir' }, { type: 'nack' }, { type: 'nack', parameter: 'pli' }, { type: 'goog-remb' }],
142
+ parameters: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032',
143
+ }),
144
+ ],
145
+ audio: [
146
+ new werift_1.RTCRtpCodecParameters({
147
+ mimeType: 'audio/opus',
148
+ clockRate: 48000,
149
+ payloadType: 101,
150
+ channels: 2,
151
+ parameters: 'minptime=10;useinbandfec=1',
152
+ }),
153
+ new werift_1.RTCRtpCodecParameters({
154
+ mimeType: 'audio/PCMU',
155
+ clockRate: 8000,
156
+ channels: 1,
157
+ payloadType: 0,
158
+ }),
159
+ new werift_1.RTCRtpCodecParameters({
160
+ mimeType: 'audio/PCMA',
161
+ clockRate: 8000,
162
+ channels: 1,
163
+ payloadType: 8,
164
+ }),
165
+ ],
166
+ },
167
+ });
168
+ }
169
+ }
170
+ exports.WebRtcConnection = WebRtcConnection;
171
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { PluginContract } from '@camera.ui/types';
2
+ export declare const pluginContract: PluginContract;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pluginContract = void 0;
4
+ exports.pluginContract = {
5
+ displayName: 'Ring',
6
+ cameraSpecific: false,
7
+ dependencies: [],
8
+ permissions: [],
9
+ };
10
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":";;;AAEa,QAAA,cAAc,GAAmB;IAC5C,WAAW,EAAE,MAAM;IACnB,cAAc,EAAE,KAAK;IACrB,YAAY,EAAE,EAAE;IAChB,WAAW,EAAE,EAAE;CAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { API } from '@camera.ui/types';
2
+ declare const _default: (api: API) => void;
3
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const ring_client_api_1 = require("ring-client-api");
7
+ const rest_client_1 = require("ring-client-api/rest-client");
8
+ const types_1 = require("@camera.ui/types");
9
+ const url_1 = __importDefault(require("url"));
10
+ const http_1 = __importDefault(require("http"));
11
+ const schema_1 = require("./schema");
12
+ const contract_1 = require("./contract");
13
+ const settings_1 = require("./settings");
14
+ const connection_1 = require("./connection");
15
+ exports.default = (api) => {
16
+ api.registerPlugin(settings_1.PLUGIN_SETTINGS.NAME, settings_1.PLUGIN_SETTINGS.PLUGIN_NAME, RingPlugin, contract_1.pluginContract);
17
+ };
18
+ class RingPlugin extends types_1.BasePlugin {
19
+ server;
20
+ restClient;
21
+ ringConnections = new Map();
22
+ ringCameraConnections = new Map();
23
+ sendingSnapshot = false;
24
+ config;
25
+ constructor(log, configService, api) {
26
+ super(log, configService, api);
27
+ this.config = this.configService.all();
28
+ this.config.server = this.configService.get('server', {}, (value) => Object.prototype.toString.call(value) === '[object Object]');
29
+ this.config.server.listen = this.configService.get('server.listen', 9999, (value) => typeof value === 'number');
30
+ this.config.homes = this.configService.get('homes', [], (value) => Array.isArray(value));
31
+ this.api.on('finishLaunching', this.start.bind(this));
32
+ this.api.on('shutdown', this.stop.bind(this));
33
+ }
34
+ start() {
35
+ if (!this.config.server?.username || !this.config.server?.password) {
36
+ this.logger.warn('Stream endpoints are not protected, please set username and password in config.json');
37
+ }
38
+ this.server = http_1.default.createServer().listen(this.config.server.listen, 'localhost');
39
+ this.server.on('upgrade', async (request, socket, head) => {
40
+ if (request.url) {
41
+ const parsedUrl = url_1.default.parse(request.url);
42
+ const pathname = parsedUrl.pathname;
43
+ if (parsedUrl.query) {
44
+ const data = this.queryToData(parsedUrl.query);
45
+ if (this.config.server.username &&
46
+ this.config.server.password &&
47
+ (this.config.server.username !== data.username || this.config.server.password !== data.password)) {
48
+ socket.destroy();
49
+ return;
50
+ }
51
+ }
52
+ if (pathname) {
53
+ const decodedPathname = decodeURIComponent(pathname);
54
+ const cameraName = decodedPathname.split('/')[1];
55
+ let cameraConnection;
56
+ for (const [info, connection] of this.ringCameraConnections.entries()) {
57
+ if (info.cameraName === cameraName) {
58
+ cameraConnection = connection;
59
+ }
60
+ }
61
+ if (cameraConnection && cameraConnection.ws) {
62
+ cameraConnection.ws.handleUpgrade(request, socket, head, (ws) => cameraConnection?.ws?.emit('connection', ws));
63
+ return;
64
+ }
65
+ }
66
+ }
67
+ socket.destroy();
68
+ });
69
+ this.server.on('request', async (request, response) => {
70
+ if (request.url) {
71
+ const parsedUrl = url_1.default.parse(request.url);
72
+ const pathname = parsedUrl.pathname;
73
+ if (pathname) {
74
+ const decodedPathname = decodeURIComponent(pathname);
75
+ const cameraName = decodedPathname.split('/')[1];
76
+ let cameraConnection;
77
+ for (const [info, connection] of this.ringCameraConnections.entries()) {
78
+ if (info.cameraName === cameraName) {
79
+ cameraConnection = connection;
80
+ }
81
+ }
82
+ if (cameraConnection) {
83
+ if (!this.sendingSnapshot) {
84
+ this.sendingSnapshot = true;
85
+ this.logger.debug(`${cameraName}: Sending snapshot...`);
86
+ const buffer = await cameraConnection.snapshot();
87
+ this.logger.debug(`${cameraName} DONE`);
88
+ setTimeout(() => {
89
+ this.sendingSnapshot = false;
90
+ }, 100);
91
+ response.writeHead(200, { 'Content-Type': 'image/jpeg' });
92
+ response.end(buffer);
93
+ return;
94
+ }
95
+ }
96
+ }
97
+ }
98
+ response.writeHead(404, { 'Content-Type': 'text/plain' });
99
+ response.end('404 Not Found');
100
+ });
101
+ this.connect();
102
+ }
103
+ stop() {
104
+ this.ringCameraConnections.forEach((connection) => connection.close());
105
+ this.ringConnections.forEach((ringApi) => ringApi.disconnect());
106
+ }
107
+ async connect() {
108
+ for (const home of this.config.homes) {
109
+ this.connectHome(home);
110
+ }
111
+ }
112
+ async connectHome(home) {
113
+ try {
114
+ if (home.token) {
115
+ const api = new ring_client_api_1.RingApi({ refreshToken: home.token });
116
+ this.ringConnections.set(home.name, api);
117
+ api.onRefreshTokenUpdated.subscribe(async (refreshToken) => {
118
+ home = this.setRefreshToken(home, refreshToken.newRefreshToken);
119
+ });
120
+ const ringCameras = await api.getCameras();
121
+ for (const camera of ringCameras) {
122
+ const connection = new connection_1.WebRtcConnection(camera, this.config, this.logger);
123
+ const ringInfo = {
124
+ cameraName: camera.name,
125
+ pathName: `/${camera.name}`,
126
+ streamSource: `webrtc:ws://localhost:${this.config.server.listen}/${camera.name}`,
127
+ snapshotSource: `http://localhost:${this.config.server.listen}/${camera.name}`,
128
+ };
129
+ if (this.config.server.username && this.config.server.password) {
130
+ ringInfo.streamSource += `?username=${this.config.server.username}&password=${this.config.server.password}`;
131
+ ringInfo.snapshotSource += `?username=${this.config.server.username}&password=${this.config.server.password}`;
132
+ }
133
+ this.ringCameraConnections.set(ringInfo, connection);
134
+ if (!this.devices.has(camera.name)) {
135
+ this.logger.log('Adding camera', camera.name);
136
+ const newCamera = await this.api.deviceManager.createDevice({
137
+ _id: camera.id.toString(),
138
+ name: camera.name,
139
+ model: 'Ring Camera',
140
+ pluginId: settings_1.PLUGIN_SETTINGS.PLUGIN_NAME,
141
+ disabled: false,
142
+ sources: [
143
+ {
144
+ name: 'main',
145
+ roles: ['stream'],
146
+ urls: [ringInfo.streamSource],
147
+ },
148
+ {
149
+ name: 'snapshot',
150
+ roles: ['snapshot'],
151
+ urls: [ringInfo.snapshotSource],
152
+ },
153
+ ],
154
+ recording: {
155
+ enabled: true,
156
+ },
157
+ motion: {
158
+ enabled: true,
159
+ zones: [],
160
+ },
161
+ ui: {
162
+ streamingModes: ['webrtc', 'mse'],
163
+ },
164
+ });
165
+ this.devices.set(camera.name, newCamera);
166
+ }
167
+ }
168
+ }
169
+ else {
170
+ this.logger.warn(home.name, 'No refresh token, please login again!');
171
+ }
172
+ }
173
+ catch (error) {
174
+ if (error.message?.includes('Refresh token is not valid')) {
175
+ this.logger.warn(home.name, 'Invalid refresh token, please login again!');
176
+ }
177
+ else {
178
+ this.logger.error(home.name, error.message ?? error);
179
+ }
180
+ }
181
+ }
182
+ async getPluginSchema() {
183
+ return schema_1.schema;
184
+ }
185
+ async setPluginConfig(config) {
186
+ this.logger.log('setPluginConfig', config);
187
+ }
188
+ async onSubmit(actionId, home) {
189
+ switch (actionId) {
190
+ case 'onLogin':
191
+ if (home.pin) {
192
+ try {
193
+ const response = await this.generateToken({
194
+ email: home.email,
195
+ password: home.password,
196
+ code: home.pin,
197
+ });
198
+ if (response?.refreshToken) {
199
+ this.restClient = undefined;
200
+ home = this.setRefreshToken(home, response.refreshToken);
201
+ this.connectHome(home);
202
+ return { toast: 'Logged in' };
203
+ }
204
+ else {
205
+ throw new Error('Failed to Login');
206
+ }
207
+ }
208
+ catch (e) {
209
+ this.logger.error(e.message, 'Failed to Link Account');
210
+ return { toast: 'Failed to Link Account' };
211
+ }
212
+ }
213
+ // token was not valid, login again
214
+ try {
215
+ const response = (await this.generateCode({
216
+ email: home.email,
217
+ password: home.password,
218
+ }));
219
+ if ('refreshToken' in response) {
220
+ // didn't need 2fa, return token without asking for code
221
+ this.restClient = undefined;
222
+ home = this.setRefreshToken(home, response.refreshToken);
223
+ this.connectHome(home);
224
+ return { toast: 'Logged in' };
225
+ }
226
+ else {
227
+ return { toast: response.codePrompt };
228
+ }
229
+ }
230
+ catch (error) {
231
+ this.logger.error(error.message, 'Ring Login Failed');
232
+ }
233
+ break;
234
+ default:
235
+ this.logger.warn('Unknown actionId', actionId);
236
+ }
237
+ return {};
238
+ }
239
+ async generateCode({ email, password }) {
240
+ this.logger.log(`Logging in with email '${email}'`);
241
+ this.restClient = new rest_client_1.RingRestClient({
242
+ email,
243
+ password,
244
+ });
245
+ try {
246
+ const { refresh_token } = await this.restClient.getCurrentAuth();
247
+ // If we get here, 2fa was not required. I'm not sure this is possible anymore, but it's here just in case
248
+ return { refreshToken: refresh_token };
249
+ }
250
+ catch (error) {
251
+ if (this.restClient.promptFor2fa) {
252
+ this.logger.log(this.restClient.promptFor2fa);
253
+ return { codePrompt: this.restClient.promptFor2fa };
254
+ }
255
+ this.logger.error(error.message);
256
+ }
257
+ }
258
+ async generateToken({ email, password, code }) {
259
+ // use the existing restClient to avoid sending a token again
260
+ this.restClient = this.restClient || new rest_client_1.RingRestClient({ email, password });
261
+ this.logger.log(`Getting token for ${email} with code ${code}`);
262
+ try {
263
+ const authResponse = await this.restClient.getAuth(code);
264
+ return { refreshToken: authResponse.refresh_token };
265
+ }
266
+ catch (error) {
267
+ this.logger.error('Incorrect 2fa Code. Please check the code and try again', error.message);
268
+ }
269
+ }
270
+ setRefreshToken(home, refreshToken) {
271
+ const newHome = {
272
+ ...home,
273
+ token: refreshToken,
274
+ };
275
+ this.configService.replaceOrAddItem('homes', 'name', home.name, {
276
+ name: home.name,
277
+ token: refreshToken,
278
+ }, true);
279
+ return newHome;
280
+ }
281
+ configureDevices(devices) {
282
+ this.logger.log('configureDevices', devices);
283
+ for (const device of devices) {
284
+ this.devices.set(device.name, device);
285
+ }
286
+ }
287
+ queryToData(query) {
288
+ const params = new URLSearchParams(query);
289
+ const result = {};
290
+ params.forEach((value, key) => {
291
+ if (value === 'true' || value === 'false' || value === '') {
292
+ result[key] = value === 'true' || value === '';
293
+ }
294
+ else if (value === 'null') {
295
+ result[key] = null;
296
+ }
297
+ else if (value === 'undefined') {
298
+ result[key] = undefined;
299
+ }
300
+ else if (!isNaN(Number(value))) {
301
+ result[key] = Number(value);
302
+ }
303
+ else {
304
+ result[key] = value;
305
+ }
306
+ });
307
+ return result;
308
+ }
309
+ }
310
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/peer.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { ConnectionState, MediaStreamTrack, RTCIceCandidate, RtcpPacket, RtpPacket } from 'werift';
2
+ import { ReplaySubject, Subject, Observable } from 'rxjs';
3
+ interface BasicPeerConnection {
4
+ createOffer(): Promise<{
5
+ sdp: string;
6
+ }>;
7
+ acceptAnswer(answer: {
8
+ type: 'answer';
9
+ sdp: string;
10
+ }): Promise<void>;
11
+ addIceCandidate(candidate: Partial<RTCIceCandidate>): Promise<void>;
12
+ onIceCandidate: Observable<RTCIceCandidate>;
13
+ onConnectionState: Observable<ConnectionState>;
14
+ close(): void;
15
+ requestKeyFrame?: () => void;
16
+ }
17
+ export declare class CustomPeerConnection implements BasicPeerConnection {
18
+ private pc;
19
+ private onRequestKeyFrame;
20
+ onAudioRtp: Subject<RtpPacket>;
21
+ onAudioRtcp: Subject<RtcpPacket>;
22
+ onVideoRtp: Subject<RtpPacket>;
23
+ onVideoRtcp: Subject<RtcpPacket>;
24
+ onIceCandidate: Subject<RTCIceCandidate>;
25
+ onConnectionState: ReplaySubject<"closed" | "failed" | "disconnected" | "new" | "connecting" | "connected">;
26
+ returnAudioTrack: MediaStreamTrack;
27
+ constructor();
28
+ createOffer(): Promise<import("werift").RTCSessionDescription>;
29
+ acceptAnswer(answer: {
30
+ type: 'answer';
31
+ sdp: string;
32
+ }): Promise<void>;
33
+ addIceCandidate(candidate: RTCIceCandidate): Promise<void>;
34
+ requestKeyFrame(): void;
35
+ close(): void;
36
+ }
37
+ export {};
package/dist/peer.js ADDED
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomPeerConnection = void 0;
4
+ const werift_1 = require("werift");
5
+ const rxjs_1 = require("rxjs");
6
+ const ringIceServers = [
7
+ 'stun:stun.kinesisvideo.us-east-1.amazonaws.com:443',
8
+ 'stun:stun.kinesisvideo.us-east-2.amazonaws.com:443',
9
+ 'stun:stun.kinesisvideo.us-west-2.amazonaws.com:443',
10
+ 'stun:stun.l.google.com:19302',
11
+ 'stun:stun1.l.google.com:19302',
12
+ 'stun:stun2.l.google.com:19302',
13
+ 'stun:stun3.l.google.com:19302',
14
+ 'stun:stun4.l.google.com:19302',
15
+ ];
16
+ class CustomPeerConnection {
17
+ pc;
18
+ onRequestKeyFrame = new rxjs_1.Subject();
19
+ onAudioRtp = new rxjs_1.Subject();
20
+ onAudioRtcp = new rxjs_1.Subject();
21
+ onVideoRtp = new rxjs_1.Subject();
22
+ onVideoRtcp = new rxjs_1.Subject();
23
+ onIceCandidate = new rxjs_1.Subject();
24
+ onConnectionState = new rxjs_1.ReplaySubject(1);
25
+ returnAudioTrack = new werift_1.MediaStreamTrack({ kind: 'audio' });
26
+ constructor() {
27
+ const pc = (this.pc = new werift_1.RTCPeerConnection({
28
+ codecs: {
29
+ audio: [
30
+ new werift_1.RTCRtpCodecParameters({
31
+ mimeType: 'audio/opus',
32
+ clockRate: 48000,
33
+ channels: 2,
34
+ }),
35
+ new werift_1.RTCRtpCodecParameters({
36
+ mimeType: 'audio/PCMU',
37
+ clockRate: 8000,
38
+ channels: 1,
39
+ payloadType: 0,
40
+ }),
41
+ ],
42
+ video: [
43
+ new werift_1.RTCRtpCodecParameters({
44
+ mimeType: 'video/H264',
45
+ clockRate: 90000,
46
+ rtcpFeedback: [{ type: 'transport-cc' }, { type: 'ccm', parameter: 'fir' }, { type: 'nack' }, { type: 'nack', parameter: 'pli' }, { type: 'goog-remb' }],
47
+ parameters: 'packetization-mode=1;profile-level-id=640029;level-asymmetry-allowed=1',
48
+ }),
49
+ new werift_1.RTCRtpCodecParameters({
50
+ mimeType: 'video/rtx',
51
+ clockRate: 90000,
52
+ }),
53
+ ],
54
+ },
55
+ iceServers: ringIceServers.map((server) => ({ urls: server })),
56
+ iceTransportPolicy: 'all',
57
+ bundlePolicy: 'disable',
58
+ }));
59
+ const audioTransceiver = pc.addTransceiver(this.returnAudioTrack, {
60
+ direction: 'sendrecv',
61
+ });
62
+ const videoTransceiver = pc.addTransceiver('video', {
63
+ direction: 'recvonly',
64
+ });
65
+ audioTransceiver.onTrack.subscribe((track) => {
66
+ track.onReceiveRtp.subscribe((rtp) => {
67
+ this.onAudioRtp.next(rtp);
68
+ });
69
+ track.onReceiveRtcp.subscribe((rtcp) => {
70
+ this.onAudioRtcp.next(rtcp);
71
+ });
72
+ });
73
+ videoTransceiver.onTrack.subscribe((track) => {
74
+ track.onReceiveRtp.subscribe((rtp) => {
75
+ this.onVideoRtp.next(rtp);
76
+ });
77
+ track.onReceiveRtcp.subscribe((rtcp) => {
78
+ this.onVideoRtcp.next(rtcp);
79
+ });
80
+ track.onReceiveRtp.once(() => {
81
+ setInterval(() => videoTransceiver.receiver.sendRtcpPLI(track.ssrc), 4000);
82
+ });
83
+ });
84
+ this.pc.onIceCandidate.subscribe((iceCandidate) => {
85
+ this.onIceCandidate.next(iceCandidate);
86
+ });
87
+ pc.iceConnectionStateChange.subscribe(() => {
88
+ if (pc.iceConnectionState === 'closed') {
89
+ this.onConnectionState.next('closed');
90
+ }
91
+ });
92
+ pc.connectionStateChange.subscribe(() => {
93
+ this.onConnectionState.next(pc.connectionState);
94
+ });
95
+ }
96
+ async createOffer() {
97
+ const offer = await this.pc.createOffer();
98
+ await this.pc.setLocalDescription(offer);
99
+ return offer;
100
+ }
101
+ async acceptAnswer(answer) {
102
+ await this.pc.setRemoteDescription(answer);
103
+ }
104
+ addIceCandidate(candidate) {
105
+ return this.pc.addIceCandidate(candidate);
106
+ }
107
+ requestKeyFrame() {
108
+ this.onRequestKeyFrame.next();
109
+ }
110
+ close() {
111
+ this.pc.close().catch((e) => console.log(e));
112
+ }
113
+ }
114
+ exports.CustomPeerConnection = CustomPeerConnection;
115
+ //# sourceMappingURL=peer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer.js","sourceRoot":"","sources":["../src/peer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { JsonSchemaObject } from '@camera.ui/types';
2
+ export declare const schema: JsonSchemaObject;
package/dist/schema.js ADDED
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schema = void 0;
4
+ exports.schema = {
5
+ type: 'object',
6
+ properties: {
7
+ server: {
8
+ type: 'object',
9
+ properties: {
10
+ listen: {
11
+ type: 'number',
12
+ key: 'listen',
13
+ label: 'Server Port',
14
+ description: 'Port to listen on for incoming connections',
15
+ required: true,
16
+ readonly: false,
17
+ },
18
+ username: {
19
+ type: 'string',
20
+ key: 'username',
21
+ label: 'Server Username',
22
+ description: 'Username for the server',
23
+ required: true,
24
+ readonly: false,
25
+ },
26
+ password: {
27
+ type: 'string',
28
+ key: 'password',
29
+ format: 'password',
30
+ label: 'Server Password',
31
+ description: 'Password for the server',
32
+ required: true,
33
+ readonly: false,
34
+ },
35
+ },
36
+ key: 'server',
37
+ label: 'Server Settings',
38
+ description: 'Settings for the server',
39
+ required: true,
40
+ readonly: false,
41
+ },
42
+ homes: {
43
+ type: 'array',
44
+ items: {
45
+ type: 'object',
46
+ properties: {
47
+ name: {
48
+ type: 'string',
49
+ required: true,
50
+ label: 'Home Name',
51
+ description: 'Name of the home',
52
+ readonly: false,
53
+ },
54
+ email: {
55
+ type: 'string',
56
+ required: false,
57
+ label: 'Login Email',
58
+ description: 'Email for the login',
59
+ format: 'email',
60
+ readonly: false,
61
+ },
62
+ password: {
63
+ type: 'string',
64
+ required: false,
65
+ label: 'Login Password',
66
+ format: 'password',
67
+ description: 'Password for the login',
68
+ readonly: false,
69
+ },
70
+ pin: {
71
+ type: 'string',
72
+ required: false,
73
+ label: '2FA Pin',
74
+ description: '2FA Pin for the login',
75
+ readonly: false,
76
+ },
77
+ token: {
78
+ type: 'string',
79
+ label: 'Refresh Token',
80
+ description: 'Refresh Token',
81
+ hidden: true,
82
+ },
83
+ },
84
+ label: 'Home',
85
+ description: 'Ring Home',
86
+ required: true,
87
+ readonly: false,
88
+ buttons: [
89
+ {
90
+ label: 'Login',
91
+ onSubmit: 'onLogin',
92
+ },
93
+ ],
94
+ },
95
+ key: 'homes',
96
+ label: 'Homes',
97
+ description: 'Ring Homes',
98
+ required: true,
99
+ readonly: false,
100
+ },
101
+ },
102
+ };
103
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":";;;AAEa,QAAA,MAAM,GAAqB;IACtC,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,QAAQ;oBACb,KAAK,EAAE,aAAa;oBACpB,WAAW,EAAE,4CAA4C;oBACzD,QAAQ,EAAE,IAAI;oBACd,QAAQ,EAAE,KAAK;iBAChB;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,UAAU;oBACf,KAAK,EAAE,iBAAiB;oBACxB,WAAW,EAAE,yBAAyB;oBACtC,QAAQ,EAAE,IAAI;oBACd,QAAQ,EAAE,KAAK;iBAChB;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,UAAU;oBACf,MAAM,EAAE,UAAU;oBAClB,KAAK,EAAE,iBAAiB;oBACxB,WAAW,EAAE,yBAAyB;oBACtC,QAAQ,EAAE,IAAI;oBACd,QAAQ,EAAE,KAAK;iBAChB;aACF;YACD,GAAG,EAAE,QAAQ;YACb,KAAK,EAAE,iBAAiB;YACxB,WAAW,EAAE,yBAAyB;YACtC,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,KAAK;SAChB;QACD,KAAK,EAAE;YACL,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,WAAW;wBAClB,WAAW,EAAE,kBAAkB;wBAC/B,QAAQ,EAAE,KAAK;qBAChB;oBACD,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,KAAK;wBACf,KAAK,EAAE,aAAa;wBACpB,WAAW,EAAE,qBAAqB;wBAClC,MAAM,EAAE,OAAO;wBACf,QAAQ,EAAE,KAAK;qBAChB;oBACD,QAAQ,EAAE;wBACR,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,KAAK;wBACf,KAAK,EAAE,gBAAgB;wBACvB,MAAM,EAAE,UAAU;wBAClB,WAAW,EAAE,wBAAwB;wBACrC,QAAQ,EAAE,KAAK;qBAChB;oBACD,GAAG,EAAE;wBACH,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,KAAK;wBACf,KAAK,EAAE,SAAS;wBAChB,WAAW,EAAE,uBAAuB;wBACpC,QAAQ,EAAE,KAAK;qBAChB;oBACD,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,eAAe;wBACtB,WAAW,EAAE,eAAe;wBAC5B,MAAM,EAAE,IAAI;qBACb;iBACF;gBACD,KAAK,EAAE,MAAM;gBACb,WAAW,EAAE,WAAW;gBACxB,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE;oBACP;wBACE,KAAK,EAAE,OAAO;wBACd,QAAQ,EAAE,SAAS;qBACpB;iBACF;aACF;YACD,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,OAAO;YACd,WAAW,EAAE,YAAY;YACzB,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,KAAK;SAChB;KACF;CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const PLUGIN_SETTINGS: {
2
+ NAME: string;
3
+ PLUGIN_NAME: string;
4
+ };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLUGIN_SETTINGS = void 0;
4
+ exports.PLUGIN_SETTINGS = {
5
+ NAME: 'Ring',
6
+ PLUGIN_NAME: '@seydx/camera-ui-ring',
7
+ };
8
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG;IAC7B,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,uBAAuB;CACrC,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface RingInfo {
2
+ cameraName: string;
3
+ streamSource: string;
4
+ snapshotSource: string;
5
+ pathName: string;
6
+ }
7
+ export interface RingHome {
8
+ name: string;
9
+ email: string;
10
+ password: string;
11
+ pin?: string;
12
+ token?: string;
13
+ }
14
+ export interface Config {
15
+ server: {
16
+ listen: number;
17
+ username?: string;
18
+ password?: string;
19
+ };
20
+ homes: RingHome[];
21
+ }
22
+ export interface LoginRequest {
23
+ email: string;
24
+ password: string;
25
+ }
26
+ export interface TokenRequest {
27
+ email: string;
28
+ password: string;
29
+ code: string;
30
+ }
31
+ export interface Go2RtcMsg {
32
+ type: 'webrtc/offer' | 'webrtc/candidate';
33
+ value: string;
34
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ {
2
+ "test": "test",
3
+ "server": {
4
+ "listen": 9999,
5
+ "username": "camera.ui",
6
+ "password": "camera.ui"
7
+ },
8
+ "homes": [
9
+ {
10
+ "test": {
11
+ "username": "test",
12
+ "password": "test",
13
+ "pin": "123"
14
+ }
15
+ }
16
+ ]
17
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@camera.ui/camera-ui-ring",
3
+ "version": "0.0.1",
4
+ "description": "camera.ui ring plugin",
5
+ "author": "seydx (https://github.com/seydx/camera.ui)",
6
+ "main": "./dist/index.js",
7
+ "scripts": {
8
+ "build": "rimraf dist && tsc",
9
+ "format": "prettier --write 'src/' --ignore-unknown --no-error-on-unmatched-pattern",
10
+ "lint": "eslint --fix --ext .js,.ts .",
11
+ "update": "updates --update ./",
12
+ "install-updates": "npm i --save",
13
+ "prepublishOnly": "npm run lint && npm run format && npm run build"
14
+ },
15
+ "dependencies": {
16
+ "ring-client-api": "^12.0.1",
17
+ "updates": "^15.0.4",
18
+ "werift": "^0.18.13",
19
+ "ws": "^8.14.2"
20
+ },
21
+ "devDependencies": {
22
+ "@camera.ui/types": "0.0.1",
23
+ "@rushstack/eslint-patch": "^1.6.0",
24
+ "@types/node": "^20.10.0",
25
+ "@types/ws": "^8.5.10",
26
+ "@typescript-eslint/eslint-plugin": "^6.13.1",
27
+ "@typescript-eslint/parser": "^6.13.1",
28
+ "concurrently": "^8.2.2",
29
+ "eslint": "^8.54.0",
30
+ "eslint-config-prettier": "^9.0.0",
31
+ "eslint-plugin-prettier": "^5.0.1",
32
+ "prettier": "^3.1.0",
33
+ "rimraf": "^5.0.5",
34
+ "typescript": "^5.3.2"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/seydx/camera.ui/issues"
38
+ },
39
+ "engines": {
40
+ "camera.ui": ">=3.0.0-alpha.0",
41
+ "node": ">=18.12.0"
42
+ },
43
+ "homepage": "https://github.com/seydx/camera.ui#readme",
44
+ "keywords": [
45
+ "camera-ui-plugin",
46
+ "ring",
47
+ "webrtc"
48
+ ],
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/seydx/camera.ui.git"
53
+ }
54
+ }