ring-client-api 9.25.0-beta.0 → 10.0.0-beta.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.
@@ -1,29 +1,26 @@
1
- /// <reference types="node" />
2
- import { RtpSplitter, SrtpOptions } from '@homebridge/camera-utils';
3
- export interface RtpStreamOptions extends SrtpOptions {
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;
4
14
  port: number;
5
- rtcpPort: 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;
6
25
  }
7
- export interface RtpOptions {
8
- audio: RtpStreamOptions;
9
- video: RtpStreamOptions;
10
- }
11
- export interface RtpStreamDescription extends RtpStreamOptions {
12
- ssrc?: number;
13
- iceUFrag?: string;
14
- icePwd?: string;
15
- }
16
- export interface RtpDescription {
17
- address: string;
18
- audio: RtpStreamDescription;
19
- video: RtpStreamDescription;
20
- }
21
- export declare function isStunMessage(message: Buffer): boolean;
22
- export declare function sendStunBindingRequest({ rtpDescription, rtpSplitter, rtcpSplitter, localUfrag, type, }: {
23
- rtpSplitter: RtpSplitter;
24
- rtcpSplitter: RtpSplitter;
25
- rtpDescription: RtpDescription;
26
- localUfrag?: string;
27
- type: 'video' | 'audio';
28
- }): void;
29
- export declare function createStunResponder(rtpSplitter: RtpSplitter): void;
26
+ export declare function parseLiveCallSession(sessionId: string): LiveCallSession;
@@ -1,56 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStunResponder = exports.sendStunBindingRequest = exports.isStunMessage = void 0;
4
- const util_1 = require("./util");
5
- const stun = require('stun');
6
- const stunMagicCookie = 0x2112a442; // https://tools.ietf.org/html/rfc5389#section-6
7
- function isStunMessage(message) {
8
- return message.length > 8 && message.readInt32BE(4) === stunMagicCookie;
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);
9
7
  }
10
- exports.isStunMessage = isStunMessage;
11
- function sendStunBindingRequest({ rtpDescription, rtpSplitter, rtcpSplitter, localUfrag, type, }) {
12
- const message = stun.createMessage(1), remoteDescription = rtpDescription[type], { address } = rtpDescription, { iceUFrag, icePwd, port, rtcpPort } = remoteDescription;
13
- if (iceUFrag && icePwd && localUfrag) {
14
- // Full ICE supported. Send as formal stun request
15
- message.addUsername(iceUFrag + ':' + localUfrag);
16
- message.addMessageIntegrity(icePwd);
17
- stun
18
- .request(`${address}:${port}`, {
19
- socket: rtpSplitter.socket,
20
- message,
21
- })
22
- .then(() => (0, util_1.logDebug)(`${type} stun complete`))
23
- .catch((e) => {
24
- (0, util_1.logError)(`${type} stun error`);
25
- (0, util_1.logError)(e);
26
- });
27
- }
28
- else {
29
- // ICE not supported. Fire and forget the stun request for RTP and RTCP
30
- const encodedMessage = stun.encode(message);
31
- rtpSplitter.send(encodedMessage, { address, port }).catch(util_1.logError);
32
- rtcpSplitter
33
- .send(encodedMessage, { address, port: rtcpPort })
34
- .catch(util_1.logError);
35
- }
36
- }
37
- exports.sendStunBindingRequest = sendStunBindingRequest;
38
- function createStunResponder(rtpSplitter) {
39
- return rtpSplitter.addMessageHandler(({ message, info }) => {
40
- if (!isStunMessage(message)) {
41
- return null;
42
- }
43
- try {
44
- const decodedMessage = stun.decode(message), response = stun.createMessage(stun.constants.STUN_BINDING_RESPONSE, decodedMessage.transactionId);
45
- response.addXorAddress(info.address, info.port);
46
- rtpSplitter.send(stun.encode(response), info).catch(util_1.logError);
47
- }
48
- catch (e) {
49
- (0, util_1.logDebug)('Failed to Decode STUN Message');
50
- (0, util_1.logDebug)(message.toString('hex'));
51
- (0, util_1.logDebug)(e);
52
- }
53
- return null;
54
- });
55
- }
56
- exports.createStunResponder = createStunResponder;
8
+ exports.parseLiveCallSession = parseLiveCallSession;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ring-client-api",
3
- "version": "9.25.0-beta.0",
3
+ "version": "10.0.0-beta.1",
4
4
  "description": "Unofficial API for Ring doorbells, cameras, security alarm system and smart lighting",
5
5
  "main": "lib/api/index.js",
6
6
  "bin": {
@@ -14,14 +14,16 @@
14
14
  "watch:tests": "jest --watch",
15
15
  "lint": "eslint '**/*.ts' --fix",
16
16
  "build": "rm -rf lib && tsc --declaration",
17
- "example": "npm run build && node ./lib/examples/example.js",
18
- "api-example": "npm run build && node ./lib/examples/api-example.js",
19
- "record-example": "npm run build && node ./lib/examples/record-example.js",
20
- "stream-example": "npm run build && node ./lib/examples/stream-example.js",
21
- "browser-example": "npm run build && node ./lib/examples/browser-example.js",
22
- "auth-cli": "npm run build && ./ring-auth-cli.js",
23
- "device-data-cli": "npm run build && ./ring-device-data-cli.js",
24
- "hb": "npm run build && ./build/package-homebridge.sh && homebridge -P ./release-homebridge -U ./.homebridge",
17
+ "build-quick": "rm -rf lib && esbuild ./{api,examples,homebridge}/*.ts --target=es2017 --format=cjs --outdir=lib",
18
+ "example": "npm run build-quick && node ./lib/examples/example.js",
19
+ "api-example": "npm run build-quick && node ./lib/examples/api-example.js",
20
+ "record-example": "npm run build-quick && node ./lib/examples/record-example.js",
21
+ "return-audio-example": "npm run build-quick && node ./lib/examples/return-audio-example.js",
22
+ "stream-example": "npm run build-quick && node ./lib/examples/stream-example.js",
23
+ "browser-example": "npm run build-quick && node ./lib/examples/browser-example.js",
24
+ "auth-cli": "npm run build-quick && ./ring-auth-cli.js",
25
+ "device-data-cli": "npm run build-quick && ./ring-device-data-cli.js",
26
+ "hb": "npm run build-quick && ./build/package-homebridge.sh && homebridge -P ./release-homebridge -U ./.homebridge",
25
27
  "prepare-npm-packages": "./build/package-api.sh && ./build/package-homebridge.sh",
26
28
  "push-with-tags": "git push --follow-tags && node ./build/github-releaser.js",
27
29
  "deploy": "git pull -r && standard-version && npm publish ./release-api && npm publish ./release-homebridge && npm run push-with-tags",
@@ -53,29 +55,31 @@
53
55
  "author": "dgreif",
54
56
  "license": "MIT",
55
57
  "dependencies": {
56
- "@homebridge/camera-utils": "2.0.4",
58
+ "@homebridge/camera-utils": "2.1.0",
57
59
  "@homebridge/plugin-ui-utils": "0.0.19",
60
+ "@koush/werift": "0.14.5-beta7",
58
61
  "@types/socket.io-client": "1.4.36",
59
62
  "colors": "1.4.0",
60
63
  "debug": "4.3.3",
61
64
  "got": "11.8.3",
62
65
  "rxjs": "7.5.2",
63
- "sdp": "3.0.3",
64
66
  "socket.io-client": "2.4.0",
65
- "stun": "2.1.0",
66
67
  "systeminformation": "5.10.7",
67
- "uuid": "8.3.2"
68
+ "uuid": "8.3.2",
69
+ "ws": "8.4.2"
68
70
  },
69
71
  "devDependencies": {
70
72
  "@types/debug": "4.1.7",
71
73
  "@types/jest": "27.4.0",
72
74
  "@types/node": "17.0.10",
73
75
  "@types/uuid": "8.3.4",
76
+ "@types/ws": "^8.2.2",
74
77
  "@typescript-eslint/eslint-plugin": "5.10.0",
75
78
  "@typescript-eslint/parser": "5.10.0",
76
79
  "concurrently": "^7.0.0",
77
80
  "conventional-github-releaser": "3.1.5",
78
81
  "dotenv": "14.2.0",
82
+ "esbuild": "^0.14.19",
79
83
  "eslint": "8.7.0",
80
84
  "eslint-config-prettier": "8.3.0",
81
85
  "eslint-plugin-jest": "25.7.0",
@@ -91,8 +95,8 @@
91
95
  "typescript": "4.5.5"
92
96
  },
93
97
  "engines": {
94
- "node": "^10 || ^12.20 || ^14 || ^16",
95
- "homebridge": ">=1.0.0"
98
+ "node": "^12.20 || ^14 || ^16",
99
+ "homebridge": ">=1.4.0"
96
100
  },
97
101
  "bugs": {
98
102
  "url": "https://github.com/dgreif/ring/issues"
@@ -1,76 +0,0 @@
1
- import { Subject } from 'rxjs';
2
- import { RtpDescription, RtpOptions } from './rtp-utils';
3
- export declare const expiredDingError: Error;
4
- interface UriOptions {
5
- name?: string;
6
- uri: string;
7
- params?: {
8
- tag?: string;
9
- };
10
- }
11
- interface SipHeaders {
12
- [name: string]: string | any;
13
- cseq: {
14
- seq: number;
15
- method: string;
16
- };
17
- to: UriOptions;
18
- from: UriOptions;
19
- contact?: UriOptions[];
20
- via?: UriOptions[];
21
- }
22
- export interface SipRequest {
23
- uri: UriOptions | string;
24
- method: string;
25
- headers: SipHeaders;
26
- content: string;
27
- }
28
- export interface SipResponse {
29
- status: number;
30
- reason: string;
31
- headers: SipHeaders;
32
- content: string;
33
- }
34
- export interface SipClient {
35
- send: (request: SipRequest | SipResponse, handler?: (response: SipResponse) => void) => void;
36
- destroy: () => void;
37
- makeResponse: (response: SipRequest, status: number, method: string) => SipResponse;
38
- }
39
- export interface SipOptions {
40
- to: string;
41
- from: string;
42
- dingId: string;
43
- localIp: string;
44
- }
45
- export declare class SipCall {
46
- private sipOptions;
47
- private seq;
48
- private fromParams;
49
- private toParams;
50
- private callId;
51
- private sipClient;
52
- readonly onEndedByRemote: Subject<unknown>;
53
- private destroyed;
54
- private cameraConnected?;
55
- private cameraConnectedPromise;
56
- readonly sdp: string;
57
- readonly audioUfrag: string;
58
- readonly videoUfrag: string;
59
- constructor(sipOptions: SipOptions, rtpOptions: RtpOptions, tlsPort: number);
60
- request({ method, headers, content, seq, }: {
61
- method: string;
62
- headers?: Partial<SipHeaders>;
63
- content?: string;
64
- seq?: number;
65
- }): Promise<SipResponse>;
66
- private ackWithInfo;
67
- sendDtmf(key: string): Promise<SipResponse>;
68
- private sendKeyFrameRequest;
69
- invite(): Promise<RtpDescription>;
70
- requestKeyFrame(): Promise<void>;
71
- private speakerActivated;
72
- activateCameraSpeaker(): Promise<void>;
73
- sendBye(): Promise<void | SipResponse>;
74
- destroy(): void;
75
- }
76
- export {};
@@ -1,242 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.SipCall = exports.expiredDingError = void 0;
13
- const rxjs_1 = require("rxjs");
14
- const util_1 = require("./util");
15
- const camera_utils_1 = require("@homebridge/camera-utils");
16
- const sip = require('./sip.js'), sdp = require('sdp');
17
- exports.expiredDingError = new Error('Ding expired, received 480');
18
- function getRandomId() {
19
- return Math.floor(Math.random() * 1e6).toString();
20
- }
21
- function getRtpDescription(sections, mediaType) {
22
- var _a, _b, _c, _d;
23
- try {
24
- const section = sections.find((s) => s.startsWith('m=' + mediaType)), { port } = sdp.parseMLine(section), lines = sdp.splitLines(section), rtcpLine = lines.find((l) => l.startsWith('a=rtcp:')), cryptoLine = lines.find((l) => l.startsWith('a=crypto')), ssrcLine = lines.find((l) => l.startsWith('a=ssrc')), iceUFragLine = lines.find((l) => l.startsWith('a=ice-ufrag')), icePwdLine = lines.find((l) => l.startsWith('a=ice-pwd')), encodedCrypto = cryptoLine.match(/inline:(\S*)/)[1];
25
- return Object.assign({ port, rtcpPort: (rtcpLine && Number((_a = rtcpLine.match(/rtcp:(\S*)/)) === null || _a === void 0 ? void 0 : _a[1])) || port, ssrc: (ssrcLine && Number((_b = ssrcLine.match(/ssrc:(\S*)/)) === null || _b === void 0 ? void 0 : _b[1])) || undefined, iceUFrag: (iceUFragLine && ((_c = iceUFragLine.match(/ice-ufrag:(\S*)/)) === null || _c === void 0 ? void 0 : _c[1])) ||
26
- undefined, icePwd: (icePwdLine && ((_d = icePwdLine.match(/ice-pwd:(\S*)/)) === null || _d === void 0 ? void 0 : _d[1])) || undefined }, (0, camera_utils_1.decodeSrtpOptions)(encodedCrypto));
27
- }
28
- catch (e) {
29
- (0, util_1.logError)('Failed to parse SDP from Ring');
30
- (0, util_1.logError)(sections.join('\r\n'));
31
- throw e;
32
- }
33
- }
34
- function parseRtpDescription(inviteResponse) {
35
- const sections = sdp.splitSections(inviteResponse.content), lines = sdp.splitLines(sections[0]), cLine = lines.find((line) => line.startsWith('c='));
36
- return {
37
- address: cLine.match(/c=IN IP4 (\S*)/)[1],
38
- audio: getRtpDescription(sections, 'audio'),
39
- video: getRtpDescription(sections, 'video'),
40
- };
41
- }
42
- class SipCall {
43
- constructor(sipOptions, rtpOptions, tlsPort) {
44
- this.sipOptions = sipOptions;
45
- this.seq = 20;
46
- this.fromParams = { tag: getRandomId() };
47
- this.toParams = {};
48
- this.callId = getRandomId();
49
- this.onEndedByRemote = new rxjs_1.Subject();
50
- this.destroyed = false;
51
- this.cameraConnectedPromise = new Promise((resolve) => {
52
- this.cameraConnected = resolve;
53
- });
54
- this.audioUfrag = (0, util_1.randomString)(16);
55
- this.videoUfrag = (0, util_1.randomString)(16);
56
- this.speakerActivated = false;
57
- const { audio, video } = rtpOptions, { from } = this.sipOptions, host = this.sipOptions.localIp;
58
- this.sipClient = sip.create({
59
- host,
60
- hostname: host,
61
- tls_port: tlsPort,
62
- tls: {
63
- rejectUnauthorized: false,
64
- },
65
- tcp: false,
66
- udp: false,
67
- }, (request) => {
68
- var _a;
69
- if (request.method === 'BYE') {
70
- (0, util_1.logDebug)('received BYE from ring server');
71
- this.sipClient.send(this.sipClient.makeResponse(request, 200, 'Ok'));
72
- if (this.destroyed) {
73
- this.onEndedByRemote.next(null);
74
- }
75
- }
76
- else if (request.method === 'MESSAGE' &&
77
- request.content === 'event=camera_connected') {
78
- (0, util_1.logDebug)('camera connected to ring server');
79
- (_a = this.cameraConnected) === null || _a === void 0 ? void 0 : _a.call(this);
80
- }
81
- });
82
- this.sdp = [
83
- 'v=0',
84
- `o=${from.split(':')[1].split('@')[0]} 3747 461 IN IP4 ${host}`,
85
- 's=Talk',
86
- `c=IN IP4 ${host}`,
87
- 'b=AS:380',
88
- 't=0 0',
89
- `m=audio ${audio.port} RTP/SAVPF 0`,
90
- 'a=rtpmap:0 PCMU/8000',
91
- (0, camera_utils_1.createCryptoLine)(audio),
92
- 'a=rtcp-mux',
93
- 'a=rtcp-fb:* trr-int 5',
94
- 'a=rtcp-fb:* ccm tmmbr',
95
- `a=ice-ufrag:${this.audioUfrag}`,
96
- `a=ice-pwd:${(0, util_1.randomString)(22)}`,
97
- `a=candidate:${(0, util_1.randomInteger)()} 1 udp ${(0, util_1.randomInteger)()} ${host} ${audio.port} typ host generation 0 network-id 1 network-cost 50`,
98
- `m=video ${video.port} RTP/SAVPF 99`,
99
- 'a=rtpmap:99 H264/90000',
100
- 'a=fmtp:99 profile-level-id=42801F',
101
- (0, camera_utils_1.createCryptoLine)(video),
102
- 'a=rtcp-mux',
103
- 'a=rtcp-fb:* trr-int 5',
104
- 'a=rtcp-fb:* ccm tmmbr',
105
- 'a=rtcp-fb:99 nack pli',
106
- 'a=rtcp-fb:99 ccm tstr',
107
- 'a=rtcp-fb:99 ccm fir',
108
- `a=ice-ufrag:${this.videoUfrag}`,
109
- `a=ice-pwd:${(0, util_1.randomString)(22)}`,
110
- `a=candidate:${(0, util_1.randomInteger)()} 1 udp ${(0, util_1.randomInteger)()} ${host} ${video.port} typ host generation 0 network-id 1 network-cost 50`,
111
- ]
112
- .filter((l) => l)
113
- .join('\r\n');
114
- }
115
- request({ method, headers, content, seq, }) {
116
- if (this.destroyed) {
117
- return Promise.reject(new Error('SIP request made after call was destroyed'));
118
- }
119
- return new Promise((resolve, reject) => {
120
- seq = seq || this.seq++;
121
- this.sipClient.send({
122
- method,
123
- uri: this.sipOptions.to,
124
- headers: Object.assign({ to: {
125
- name: '"FS Doorbot"',
126
- uri: this.sipOptions.to,
127
- params: this.toParams,
128
- }, from: {
129
- uri: this.sipOptions.from,
130
- params: this.fromParams,
131
- }, 'max-forwards': 70, 'call-id': this.callId, 'X-Ding': this.sipOptions.dingId, 'X-Authorization': '', 'User-Agent': 'Android/3.23.0 (belle-sip/1.6.3)', cseq: { seq, method } }, headers),
132
- content: content || '',
133
- }, (response) => {
134
- if (response.headers.to.params && response.headers.to.params.tag) {
135
- this.toParams.tag = response.headers.to.params.tag;
136
- }
137
- if (response.status >= 300) {
138
- if (response.status === 480 && method === 'INVITE') {
139
- const { dingId } = this.sipOptions;
140
- (0, util_1.logInfo)(`Ding ${dingId} is expired (${response.status}). Fetching a new ding and trying video stream again`);
141
- reject(exports.expiredDingError);
142
- return;
143
- }
144
- if (response.status !== 408 || method !== 'BYE') {
145
- (0, util_1.logError)(`sip ${method} request failed with status ` + response.status);
146
- }
147
- reject(new Error(`sip ${method} request failed with status ` + response.status));
148
- }
149
- else if (response.status < 200) {
150
- // call made progress, do nothing and wait for another response
151
- // console.log('call progress status ' + response.status)
152
- }
153
- else {
154
- if (method === 'INVITE') {
155
- // The ACK must be sent with every OK to keep the connection alive.
156
- this.ackWithInfo(seq).catch((e) => {
157
- (0, util_1.logError)('Failed to send SDP ACK and INFO');
158
- (0, util_1.logError)(e);
159
- });
160
- }
161
- resolve(response);
162
- }
163
- });
164
- });
165
- }
166
- ackWithInfo(seq) {
167
- return __awaiter(this, void 0, void 0, function* () {
168
- // Don't wait for ack, it won't ever come back.
169
- this.request({
170
- method: 'ACK',
171
- seq, // The ACK must have the original sequence number.
172
- }).catch(rxjs_1.noop);
173
- // SIP session will be terminated after 60 seconds if these aren't sent
174
- yield this.sendDtmf('2');
175
- yield this.sendKeyFrameRequest();
176
- });
177
- }
178
- sendDtmf(key) {
179
- return this.request({
180
- method: 'INFO',
181
- headers: {
182
- 'Content-Type': 'application/dtmf-relay',
183
- },
184
- content: `Signal=${key}\r\nDuration=250`,
185
- });
186
- }
187
- sendKeyFrameRequest() {
188
- return this.request({
189
- method: 'INFO',
190
- headers: {
191
- 'Content-Type': 'application/media_control+xml',
192
- },
193
- content: '<?xml version="1.0" encoding="utf-8" ?><media_control> <vc_primitive> <to_encoder> <picture_fast_update></picture_fast_update> </to_encoder> </vc_primitive></media_control>',
194
- });
195
- }
196
- invite() {
197
- return __awaiter(this, void 0, void 0, function* () {
198
- const { from } = this.sipOptions, inviteResponse = yield this.request({
199
- method: 'INVITE',
200
- headers: {
201
- supported: 'replaces, outbound',
202
- allow: 'INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE',
203
- 'content-type': 'application/sdp',
204
- contact: [{ uri: from }],
205
- },
206
- content: this.sdp,
207
- });
208
- return parseRtpDescription(inviteResponse);
209
- });
210
- }
211
- requestKeyFrame() {
212
- return __awaiter(this, void 0, void 0, function* () {
213
- // camera connected event doesn't always happen if cam is already streaming. 2 second fallback
214
- yield Promise.race([this.cameraConnectedPromise, (0, util_1.delay)(2000)]);
215
- (0, util_1.logDebug)('requesting key frame');
216
- yield this.sendKeyFrameRequest();
217
- });
218
- }
219
- activateCameraSpeaker() {
220
- return __awaiter(this, void 0, void 0, function* () {
221
- if (this.speakerActivated) {
222
- return;
223
- }
224
- this.speakerActivated = true;
225
- (0, util_1.logDebug)('Activating camera speaker');
226
- yield this.sendDtmf('1').catch((e) => {
227
- (0, util_1.logError)('Failed to activate camera speaker');
228
- (0, util_1.logError)(e);
229
- });
230
- });
231
- }
232
- sendBye() {
233
- return this.request({ method: 'BYE' }).catch(() => {
234
- // Don't care if we get an exception here.
235
- });
236
- }
237
- destroy() {
238
- this.destroyed = true;
239
- this.sipClient.destroy();
240
- }
241
- }
242
- exports.SipCall = SipCall;
@@ -1,41 +0,0 @@
1
- import { RtpDescription, RtpOptions } from './rtp-utils';
2
- import { RtpSplitter } from '@homebridge/camera-utils';
3
- import { SipCall, SipOptions } from './sip-call';
4
- import { RingCamera } from './ring-camera';
5
- import { Subscribed } from './subscribed';
6
- declare type SpawnInput = string | number;
7
- export interface FfmpegOptions {
8
- input?: SpawnInput[];
9
- video?: SpawnInput[] | false;
10
- audio?: SpawnInput[];
11
- output: SpawnInput[];
12
- }
13
- export declare class SipSession extends Subscribed {
14
- readonly sipOptions: SipOptions;
15
- readonly rtpOptions: RtpOptions;
16
- readonly audioSplitter: RtpSplitter;
17
- audioRtcpSplitter: RtpSplitter;
18
- readonly videoSplitter: RtpSplitter;
19
- videoRtcpSplitter: RtpSplitter;
20
- private readonly tlsPort;
21
- readonly camera: RingCamera;
22
- private hasStarted;
23
- private hasCallEnded;
24
- private onCallEndedSubject;
25
- private sipCall;
26
- onCallEnded: import("rxjs").Observable<unknown>;
27
- constructor(sipOptions: SipOptions, rtpOptions: RtpOptions, audioSplitter: RtpSplitter, audioRtcpSplitter: RtpSplitter, videoSplitter: RtpSplitter, videoRtcpSplitter: RtpSplitter, tlsPort: number, camera: RingCamera);
28
- createSipCall(sipOptions: SipOptions): SipCall;
29
- start(ffmpegOptions?: FfmpegOptions): Promise<RtpDescription>;
30
- prepareTranscoder(transcodeVideoStream: boolean, ffmpegInputOptions: SpawnInput[] | undefined, remoteRtpOptions: RtpOptions, audioPort: number, videoPort: number, sdpInput: string): {
31
- ffmpegInputArguments: SpawnInput[];
32
- inputSdpLines: string[];
33
- };
34
- private startTranscoder;
35
- reservePort(bufferPorts?: number): Promise<number>;
36
- requestKeyFrame(): Promise<void>;
37
- activateCameraSpeaker(): Promise<void>;
38
- private callEnded;
39
- stop(): void;
40
- }
41
- export {};