ringcentral-softphone 1.1.2 → 1.1.4
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/dist/cjs/call-session/inbound.d.ts +3 -3
- package/dist/cjs/call-session/inbound.js +40 -93
- package/dist/cjs/call-session/index.d.ts +3 -3
- package/dist/cjs/call-session/index.js +105 -172
- package/dist/cjs/call-session/outbound.d.ts +3 -3
- package/dist/cjs/call-session/outbound.js +37 -103
- package/dist/cjs/call-session/streamer.d.ts +1 -1
- package/dist/cjs/call-session/streamer.js +30 -50
- package/dist/cjs/codec.js +28 -23
- package/dist/cjs/dtmf.js +13 -16
- package/dist/cjs/index.d.ts +5 -5
- package/dist/cjs/index.js +145 -243
- package/dist/cjs/sip-message/inbound/index.d.ts +1 -1
- package/dist/cjs/sip-message/inbound/index.js +11 -31
- package/dist/cjs/sip-message/index.d.ts +5 -5
- package/dist/cjs/sip-message/index.js +10 -10
- package/dist/cjs/sip-message/outbound/index.d.ts +1 -1
- package/dist/cjs/sip-message/outbound/index.js +7 -28
- package/dist/cjs/sip-message/outbound/request.d.ts +1 -1
- package/dist/cjs/sip-message/outbound/request.js +16 -48
- package/dist/cjs/sip-message/outbound/response.d.ts +2 -2
- package/dist/cjs/sip-message/outbound/response.js +10 -42
- package/dist/cjs/sip-message/response-codes.js +1 -1
- package/dist/cjs/sip-message/sip-message.js +12 -23
- package/dist/cjs/utils.d.ts +1 -1
- package/dist/cjs/utils.js +18 -20
- package/dist/esm/call-session/inbound.d.ts +3 -3
- package/dist/esm/call-session/inbound.js +39 -92
- package/dist/esm/call-session/index.d.ts +3 -3
- package/dist/esm/call-session/index.js +100 -167
- package/dist/esm/call-session/outbound.d.ts +3 -3
- package/dist/esm/call-session/outbound.js +37 -103
- package/dist/esm/call-session/streamer.d.ts +1 -1
- package/dist/esm/call-session/streamer.js +27 -47
- package/dist/esm/codec.js +26 -21
- package/dist/esm/dtmf.js +12 -15
- package/dist/esm/index.d.ts +5 -5
- package/dist/esm/index.js +142 -240
- package/dist/esm/sip-message/inbound/index.d.ts +1 -1
- package/dist/esm/sip-message/inbound/index.js +10 -30
- package/dist/esm/sip-message/index.d.ts +5 -5
- package/dist/esm/sip-message/index.js +5 -5
- package/dist/esm/sip-message/outbound/index.d.ts +1 -1
- package/dist/esm/sip-message/outbound/index.js +7 -28
- package/dist/esm/sip-message/outbound/request.d.ts +1 -1
- package/dist/esm/sip-message/outbound/request.js +16 -48
- package/dist/esm/sip-message/outbound/response.d.ts +2 -2
- package/dist/esm/sip-message/outbound/response.js +10 -42
- package/dist/esm/sip-message/response-codes.js +1 -1
- package/dist/esm/sip-message/sip-message.js +12 -23
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.js +18 -20
- package/package.json +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import CallSession from "./index";
|
|
2
|
-
import { type InboundMessage } from "../sip-message/index";
|
|
3
|
-
import type Softphone from "../index";
|
|
1
|
+
import CallSession from "./index.js";
|
|
2
|
+
import { type InboundMessage } from "../sip-message/index.js";
|
|
3
|
+
import type Softphone from "../index.js";
|
|
4
4
|
declare class InboundCallSession extends CallSession {
|
|
5
5
|
constructor(softphone: Softphone, inviteMessage: InboundMessage);
|
|
6
6
|
answer(): Promise<void>;
|
|
@@ -1,100 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
18
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
19
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
20
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
21
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
22
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
23
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
27
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
28
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
29
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
30
|
-
function step(op) {
|
|
31
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
32
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
33
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
34
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
35
|
-
switch (op[0]) {
|
|
36
|
-
case 0: case 1: t = op; break;
|
|
37
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
38
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
39
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
40
|
-
default:
|
|
41
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
42
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
43
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
44
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
45
|
-
if (t[2]) _.ops.pop();
|
|
46
|
-
_.trys.pop(); continue;
|
|
47
|
-
}
|
|
48
|
-
op = body.call(thisArg, _);
|
|
49
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
50
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
54
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
55
4
|
};
|
|
56
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
6
|
+
const index_js_1 = __importDefault(require("./index.js"));
|
|
7
|
+
const index_js_2 = require("../sip-message/index.js");
|
|
8
|
+
const utils_js_1 = require("../utils.js");
|
|
9
|
+
class InboundCallSession extends index_js_1.default {
|
|
10
|
+
constructor(softphone, inviteMessage) {
|
|
11
|
+
super(softphone, inviteMessage);
|
|
12
|
+
this.localPeer = inviteMessage.headers.To;
|
|
13
|
+
this.remotePeer = inviteMessage.headers.From;
|
|
14
|
+
this.remoteKey = inviteMessage.body.match(/AES_CM_128_HMAC_SHA1_80 inline:([\w+/]+)/)[1];
|
|
15
|
+
}
|
|
16
|
+
async answer() {
|
|
17
|
+
const answerSDP = `
|
|
18
|
+
v=0
|
|
19
|
+
o=- ${Date.now()} 0 IN IP4 ${this.softphone.client.localAddress}
|
|
20
|
+
s=rc-softphone-ts
|
|
21
|
+
c=IN IP4 ${this.softphone.client.localAddress}
|
|
22
|
+
t=0 0
|
|
23
|
+
m=audio ${(0, utils_js_1.randomInt)()} RTP/SAVP ${this.softphone.codec.id} 101
|
|
24
|
+
a=rtpmap:${this.softphone.codec.id} ${this.softphone.codec.name}
|
|
25
|
+
a=rtpmap:101 telephone-event/8000
|
|
26
|
+
a=fmtp:101 0-15
|
|
27
|
+
a=sendrecv
|
|
28
|
+
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:${utils_js_1.localKey}
|
|
29
|
+
`.trim();
|
|
30
|
+
const newMessage = new index_js_2.OutboundMessage("SIP/2.0 200 OK", {
|
|
31
|
+
Via: this.sipMessage.headers.Via,
|
|
32
|
+
"Call-ID": this.sipMessage.headers["Call-ID"],
|
|
33
|
+
From: this.sipMessage.headers.From,
|
|
34
|
+
To: this.sipMessage.headers.To,
|
|
35
|
+
CSeq: this.sipMessage.headers.CSeq,
|
|
36
|
+
Contact: `<sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,
|
|
37
|
+
Allow: "PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS",
|
|
38
|
+
Supported: "replaces, 100rel, timer, norefersub",
|
|
39
|
+
"Session-Expires": "14400;refresher=uac",
|
|
40
|
+
Require: "timer",
|
|
41
|
+
"Content-Type": "application/sdp",
|
|
42
|
+
}, answerSDP);
|
|
43
|
+
await this.softphone.send(newMessage);
|
|
44
|
+
this.startLocalServices();
|
|
68
45
|
}
|
|
69
|
-
|
|
70
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
71
|
-
var answerSDP, newMessage;
|
|
72
|
-
return __generator(this, function (_a) {
|
|
73
|
-
switch (_a.label) {
|
|
74
|
-
case 0:
|
|
75
|
-
answerSDP = "\nv=0\no=- ".concat(Date.now(), " 0 IN IP4 ").concat(this.softphone.client.localAddress, "\ns=rc-softphone-ts\nc=IN IP4 ").concat(this.softphone.client.localAddress, "\nt=0 0\nm=audio ").concat((0, utils_1.randomInt)(), " RTP/SAVP ").concat(this.softphone.codec.id, " 101\na=rtpmap:").concat(this.softphone.codec.id, " ").concat(this.softphone.codec.name, "\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-15\na=sendrecv\na=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:").concat(utils_1.localKey, "\n").trim();
|
|
76
|
-
newMessage = new index_2.OutboundMessage("SIP/2.0 200 OK", {
|
|
77
|
-
Via: this.sipMessage.headers.Via,
|
|
78
|
-
"Call-ID": this.sipMessage.headers["Call-ID"],
|
|
79
|
-
From: this.sipMessage.headers.From,
|
|
80
|
-
To: this.sipMessage.headers.To,
|
|
81
|
-
CSeq: this.sipMessage.headers.CSeq,
|
|
82
|
-
Contact: "<sip:".concat(this.softphone.sipInfo.username, "@").concat(this.softphone.client.localAddress, ":").concat(this.softphone.client.localPort, ";transport=TLS;ob>"),
|
|
83
|
-
Allow: "PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS",
|
|
84
|
-
Supported: "replaces, 100rel, timer, norefersub",
|
|
85
|
-
"Session-Expires": "14400;refresher=uac",
|
|
86
|
-
Require: "timer",
|
|
87
|
-
"Content-Type": "application/sdp",
|
|
88
|
-
}, answerSDP);
|
|
89
|
-
return [4 /*yield*/, this.softphone.send(newMessage)];
|
|
90
|
-
case 1:
|
|
91
|
-
_a.sent();
|
|
92
|
-
this.startLocalServices();
|
|
93
|
-
return [2 /*return*/];
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
};
|
|
98
|
-
return InboundCallSession;
|
|
99
|
-
}(index_1.default));
|
|
46
|
+
}
|
|
100
47
|
exports.default = InboundCallSession;
|
|
@@ -2,9 +2,9 @@ import dgram from "node:dgram";
|
|
|
2
2
|
import EventEmitter from "node:events";
|
|
3
3
|
import { Buffer } from "node:buffer";
|
|
4
4
|
import { RtpPacket, SrtpSession } from "werift-rtp";
|
|
5
|
-
import { type InboundMessage } from "../sip-message/index";
|
|
6
|
-
import type Softphone from "../index";
|
|
7
|
-
import Streamer from "./streamer";
|
|
5
|
+
import { type InboundMessage } from "../sip-message/index.js";
|
|
6
|
+
import type Softphone from "../index.js";
|
|
7
|
+
import Streamer from "./streamer.js";
|
|
8
8
|
declare abstract class CallSession extends EventEmitter {
|
|
9
9
|
softphone: Softphone;
|
|
10
10
|
sipMessage: InboundMessage;
|
|
@@ -1,135 +1,73 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
18
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
19
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
20
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
21
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
22
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
23
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
27
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
28
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
29
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
30
|
-
function step(op) {
|
|
31
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
32
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
33
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
34
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
35
|
-
switch (op[0]) {
|
|
36
|
-
case 0: case 1: t = op; break;
|
|
37
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
38
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
39
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
40
|
-
default:
|
|
41
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
42
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
43
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
44
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
45
|
-
if (t[2]) _.ops.pop();
|
|
46
|
-
_.trys.pop(); continue;
|
|
47
|
-
}
|
|
48
|
-
op = body.call(thisArg, _);
|
|
49
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
50
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
54
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
55
4
|
};
|
|
56
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
6
|
+
const node_dgram_1 = __importDefault(require("node:dgram"));
|
|
7
|
+
const node_events_1 = __importDefault(require("node:events"));
|
|
8
|
+
const node_buffer_1 = require("node:buffer");
|
|
9
|
+
const werift_rtp_1 = require("werift-rtp");
|
|
10
|
+
const dtmf_js_1 = __importDefault(require("../dtmf.js"));
|
|
11
|
+
const index_js_1 = require("../sip-message/index.js");
|
|
12
|
+
const utils_js_1 = require("../utils.js");
|
|
13
|
+
const streamer_js_1 = __importDefault(require("./streamer.js"));
|
|
14
|
+
class CallSession extends node_events_1.default {
|
|
15
|
+
softphone;
|
|
16
|
+
sipMessage;
|
|
17
|
+
socket;
|
|
18
|
+
localPeer;
|
|
19
|
+
remotePeer;
|
|
20
|
+
remoteIP;
|
|
21
|
+
remotePort;
|
|
22
|
+
disposed = false;
|
|
23
|
+
srtpSession;
|
|
24
|
+
encoder;
|
|
25
|
+
decoder;
|
|
26
|
+
// for audio streaming
|
|
27
|
+
ssrc = (0, utils_js_1.randomInt)();
|
|
28
|
+
sequenceNumber = (0, utils_js_1.randomInt)();
|
|
29
|
+
timestamp = (0, utils_js_1.randomInt)();
|
|
30
|
+
constructor(softphone, sipMessage) {
|
|
31
|
+
super();
|
|
32
|
+
this.softphone = softphone;
|
|
33
|
+
this.encoder = softphone.codec.createEncoder();
|
|
34
|
+
this.decoder = softphone.codec.createDecoder();
|
|
35
|
+
this.sipMessage = sipMessage;
|
|
36
|
+
this.remoteIP = this.sipMessage.body.match(/c=IN IP4 ([\d.]+)/)[1];
|
|
37
|
+
this.remotePort = parseInt(this.sipMessage.body.match(/m=audio (\d+) /)[1], 10);
|
|
38
|
+
}
|
|
39
|
+
set remoteKey(key) {
|
|
40
|
+
const localKeyBuffer = node_buffer_1.Buffer.from(utils_js_1.localKey, "base64");
|
|
41
|
+
const remoteKeyBuffer = node_buffer_1.Buffer.from(key, "base64");
|
|
42
|
+
this.srtpSession = new werift_rtp_1.SrtpSession({
|
|
43
|
+
profile: 0x0001,
|
|
44
|
+
keys: {
|
|
45
|
+
localMasterKey: localKeyBuffer.subarray(0, 16),
|
|
46
|
+
localMasterSalt: localKeyBuffer.subarray(16, 30),
|
|
47
|
+
remoteMasterKey: remoteKeyBuffer.subarray(0, 16),
|
|
48
|
+
remoteMasterSalt: remoteKeyBuffer.subarray(16, 30),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
get callId() {
|
|
53
|
+
return this.sipMessage.headers["Call-ID"];
|
|
81
54
|
}
|
|
82
|
-
|
|
83
|
-
set: function (key) {
|
|
84
|
-
var localKeyBuffer = node_buffer_1.Buffer.from(utils_1.localKey, "base64");
|
|
85
|
-
var remoteKeyBuffer = node_buffer_1.Buffer.from(key, "base64");
|
|
86
|
-
this.srtpSession = new werift_rtp_1.SrtpSession({
|
|
87
|
-
profile: 0x0001,
|
|
88
|
-
keys: {
|
|
89
|
-
localMasterKey: localKeyBuffer.subarray(0, 16),
|
|
90
|
-
localMasterSalt: localKeyBuffer.subarray(16, 30),
|
|
91
|
-
remoteMasterKey: remoteKeyBuffer.subarray(0, 16),
|
|
92
|
-
remoteMasterSalt: remoteKeyBuffer.subarray(16, 30),
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
},
|
|
96
|
-
enumerable: false,
|
|
97
|
-
configurable: true
|
|
98
|
-
});
|
|
99
|
-
Object.defineProperty(CallSession.prototype, "callId", {
|
|
100
|
-
get: function () {
|
|
101
|
-
return this.sipMessage.headers["Call-ID"];
|
|
102
|
-
},
|
|
103
|
-
enumerable: false,
|
|
104
|
-
configurable: true
|
|
105
|
-
});
|
|
106
|
-
CallSession.prototype.send = function (data) {
|
|
55
|
+
send(data) {
|
|
107
56
|
this.socket.send(data, this.remotePort, this.remoteIP);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
requestMessage = new index_1.RequestMessage("BYE sip:".concat(this.softphone.sipInfo.domain, " SIP/2.0"), {
|
|
116
|
-
"Call-ID": this.callId,
|
|
117
|
-
From: this.localPeer,
|
|
118
|
-
To: this.remotePeer,
|
|
119
|
-
Via: "SIP/2.0/TLS ".concat(this.softphone.fakeDomain, ";branch=").concat((0, utils_1.branch)()),
|
|
120
|
-
});
|
|
121
|
-
return [4 /*yield*/, this.softphone.send(requestMessage)];
|
|
122
|
-
case 1:
|
|
123
|
-
_a.sent();
|
|
124
|
-
return [2 /*return*/];
|
|
125
|
-
}
|
|
126
|
-
});
|
|
57
|
+
}
|
|
58
|
+
async hangup() {
|
|
59
|
+
const requestMessage = new index_js_1.RequestMessage(`BYE sip:${this.softphone.sipInfo.domain} SIP/2.0`, {
|
|
60
|
+
"Call-ID": this.callId,
|
|
61
|
+
From: this.localPeer,
|
|
62
|
+
To: this.remotePeer,
|
|
63
|
+
Via: `SIP/2.0/TLS ${this.softphone.fakeDomain};branch=${(0, utils_js_1.branch)()}`,
|
|
127
64
|
});
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
65
|
+
await this.softphone.send(requestMessage);
|
|
66
|
+
}
|
|
67
|
+
sendDTMF(char) {
|
|
68
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
69
|
+
let sequenceNumber = timestamp % 65536;
|
|
70
|
+
const rtpHeader = new werift_rtp_1.RtpHeader({
|
|
133
71
|
version: 2,
|
|
134
72
|
padding: false,
|
|
135
73
|
paddingSize: 0,
|
|
@@ -137,50 +75,48 @@ var CallSession = /** @class */ (function (_super) {
|
|
|
137
75
|
marker: false,
|
|
138
76
|
payloadOffset: 12,
|
|
139
77
|
payloadType: 101,
|
|
140
|
-
sequenceNumber
|
|
141
|
-
timestamp
|
|
142
|
-
ssrc: (0,
|
|
78
|
+
sequenceNumber,
|
|
79
|
+
timestamp,
|
|
80
|
+
ssrc: (0, utils_js_1.randomInt)(),
|
|
143
81
|
csrcLength: 0,
|
|
144
82
|
csrc: [],
|
|
145
83
|
extensionProfile: 48862,
|
|
146
84
|
extensionLength: undefined,
|
|
147
85
|
extensions: [],
|
|
148
86
|
});
|
|
149
|
-
for (
|
|
150
|
-
var payload = _a[_i];
|
|
87
|
+
for (const payload of dtmf_js_1.default.charToPayloads(char)) {
|
|
151
88
|
rtpHeader.sequenceNumber = sequenceNumber++;
|
|
152
|
-
|
|
89
|
+
const rtpPacket = new werift_rtp_1.RtpPacket(rtpHeader, payload);
|
|
153
90
|
this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
|
|
154
91
|
}
|
|
155
|
-
}
|
|
92
|
+
}
|
|
156
93
|
// buffer is the content of a audio file, it is supposed to be uncompressed PCM data
|
|
157
94
|
// The audio should be playable by command: play -t raw -b 16 -r 16000 -e signed-integer test.wav
|
|
158
|
-
|
|
159
|
-
|
|
95
|
+
streamAudio(input) {
|
|
96
|
+
const streamer = new streamer_js_1.default(this, input);
|
|
160
97
|
streamer.start();
|
|
161
98
|
return streamer;
|
|
162
|
-
}
|
|
99
|
+
}
|
|
163
100
|
// send a single rtp packet
|
|
164
|
-
|
|
101
|
+
sendPacket(rtpPacket) {
|
|
165
102
|
if (this.disposed) {
|
|
166
103
|
return;
|
|
167
104
|
}
|
|
168
105
|
this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
var _this = this;
|
|
106
|
+
}
|
|
107
|
+
startLocalServices() {
|
|
172
108
|
this.socket = node_dgram_1.default.createSocket("udp4");
|
|
173
|
-
this.socket.on("message",
|
|
174
|
-
|
|
175
|
-
|
|
109
|
+
this.socket.on("message", (message) => {
|
|
110
|
+
const rtpPacket = werift_rtp_1.RtpPacket.deSerialize(this.srtpSession.decrypt(message));
|
|
111
|
+
this.emit("rtpPacket", rtpPacket);
|
|
176
112
|
if (rtpPacket.header.payloadType === 101) {
|
|
177
|
-
|
|
178
|
-
|
|
113
|
+
this.emit("dtmfPacket", rtpPacket);
|
|
114
|
+
const char = dtmf_js_1.default.payloadToChar(rtpPacket.payload);
|
|
179
115
|
if (char) {
|
|
180
|
-
|
|
116
|
+
this.emit("dtmf", char);
|
|
181
117
|
}
|
|
182
118
|
}
|
|
183
|
-
else if (rtpPacket.header.payloadType ===
|
|
119
|
+
else if (rtpPacket.header.payloadType === this.softphone.codec.id) {
|
|
184
120
|
if (rtpPacket.payload.length === 4 &&
|
|
185
121
|
rtpPacket.payload[0] >= 0x00 &&
|
|
186
122
|
rtpPacket.payload[0] < 0x0c &&
|
|
@@ -193,10 +129,10 @@ var CallSession = /** @class */ (function (_super) {
|
|
|
193
129
|
return; // ignore it
|
|
194
130
|
}
|
|
195
131
|
try {
|
|
196
|
-
rtpPacket.payload =
|
|
197
|
-
|
|
132
|
+
rtpPacket.payload = this.decoder.decode(rtpPacket.payload);
|
|
133
|
+
this.emit("audioPacket", rtpPacket);
|
|
198
134
|
}
|
|
199
|
-
catch
|
|
135
|
+
catch {
|
|
200
136
|
console.error("opus decode failed", rtpPacket);
|
|
201
137
|
}
|
|
202
138
|
}
|
|
@@ -206,56 +142,53 @@ var CallSession = /** @class */ (function (_super) {
|
|
|
206
142
|
this.socket.bind(); // random port
|
|
207
143
|
// send a message to remote server so that it knows where to reply
|
|
208
144
|
this.send("hello");
|
|
209
|
-
|
|
210
|
-
if (inboundMessage.headers["Call-ID"] !==
|
|
145
|
+
const byeHandler = (inboundMessage) => {
|
|
146
|
+
if (inboundMessage.headers["Call-ID"] !== this.callId) {
|
|
211
147
|
return;
|
|
212
148
|
}
|
|
213
149
|
if (inboundMessage.headers.CSeq.endsWith(" BYE")) {
|
|
214
|
-
|
|
215
|
-
|
|
150
|
+
this.softphone.off("message", byeHandler);
|
|
151
|
+
this.dispose();
|
|
216
152
|
}
|
|
217
153
|
};
|
|
218
154
|
this.softphone.on("message", byeHandler);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
var _a, _b;
|
|
155
|
+
}
|
|
156
|
+
dispose() {
|
|
222
157
|
this.disposed = true;
|
|
223
158
|
this.emit("disposed");
|
|
224
159
|
this.removeAllListeners();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
Via: "SIP/2.0/TLS ".concat(this.softphone.client.localAddress, ":").concat(this.softphone.client.localPort, ";rport;branch=").concat((0, utils_1.branch)(), ";alias"),
|
|
160
|
+
this.socket?.removeAllListeners();
|
|
161
|
+
this.socket?.close();
|
|
162
|
+
}
|
|
163
|
+
transfer(transferTo) {
|
|
164
|
+
const requestMessage = new index_js_1.RequestMessage(`REFER sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.outboundProxy};transport=tls SIP/2.0`, {
|
|
165
|
+
Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${(0, utils_js_1.branch)()};alias`,
|
|
232
166
|
"Max-Forwards": 70,
|
|
233
167
|
From: this.localPeer,
|
|
234
168
|
To: this.remotePeer,
|
|
235
|
-
Contact:
|
|
169
|
+
Contact: `<sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,
|
|
236
170
|
"Call-ID": this.callId,
|
|
237
171
|
Event: "refer",
|
|
238
172
|
Expires: 600,
|
|
239
173
|
Supported: "replaces, 100rel, timer, norefersub",
|
|
240
174
|
Accept: "message/sipfrag;version=2.0",
|
|
241
175
|
"Allow-Events": "presence, message-summary, refer",
|
|
242
|
-
"Refer-To":
|
|
243
|
-
"Referred-By":
|
|
176
|
+
"Refer-To": `sip:${transferTo}@${this.softphone.sipInfo.domain}`,
|
|
177
|
+
"Referred-By": `<sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.domain}>`,
|
|
244
178
|
});
|
|
245
179
|
this.softphone.send(requestMessage);
|
|
246
180
|
// reply to those NOTIFY messages
|
|
247
|
-
|
|
181
|
+
const notifyHandler = (inboundMessage) => {
|
|
248
182
|
if (!inboundMessage.subject.startsWith("NOTIFY ")) {
|
|
249
183
|
return;
|
|
250
184
|
}
|
|
251
|
-
|
|
252
|
-
|
|
185
|
+
const responseMessage = new index_js_1.ResponseMessage(inboundMessage, 200);
|
|
186
|
+
this.softphone.send(responseMessage);
|
|
253
187
|
if (inboundMessage.body.trim() === "SIP/2.0 200 OK") {
|
|
254
|
-
|
|
188
|
+
this.softphone.off("message", notifyHandler);
|
|
255
189
|
}
|
|
256
190
|
};
|
|
257
191
|
this.softphone.on("message", notifyHandler);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
}(node_events_1.default));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
261
194
|
exports.default = CallSession;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import CallSession from "./index";
|
|
2
|
-
import { type InboundMessage } from "../sip-message/index";
|
|
3
|
-
import type Softphone from "../index";
|
|
1
|
+
import CallSession from "./index.js";
|
|
2
|
+
import { type InboundMessage } from "../sip-message/index.js";
|
|
3
|
+
import type Softphone from "../index.js";
|
|
4
4
|
declare class OutboundCallSession extends CallSession {
|
|
5
5
|
constructor(softphone: Softphone, answerMessage: InboundMessage);
|
|
6
6
|
init(): void;
|