ringcentral-softphone 1.3.2 → 1.3.3

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.
Files changed (98) hide show
  1. package/README.md +1 -1
  2. package/dist/call-session/inbound.cjs +93 -0
  3. package/dist/call-session/inbound.js +64 -0
  4. package/dist/call-session/index.cjs +270 -0
  5. package/dist/{esm/call-session → call-session}/index.d.ts +3 -3
  6. package/dist/call-session/index.js +244 -0
  7. package/dist/call-session/outbound.cjs +100 -0
  8. package/dist/call-session/outbound.js +71 -0
  9. package/dist/call-session/streamer.cjs +112 -0
  10. package/dist/call-session/streamer.js +83 -0
  11. package/dist/codec.cjs +85 -0
  12. package/dist/codec.js +66 -0
  13. package/dist/dtmf.cjs +65 -0
  14. package/dist/dtmf.js +46 -0
  15. package/dist/index.cjs +258 -0
  16. package/dist/{cjs/index.d.ts → index.d.ts} +3 -3
  17. package/dist/index.js +240 -0
  18. package/dist/sip-message/inbound/index.cjs +51 -0
  19. package/dist/sip-message/inbound/index.js +22 -0
  20. package/dist/sip-message/index.cjs +49 -0
  21. package/dist/sip-message/index.js +12 -0
  22. package/dist/sip-message/outbound/index.cjs +41 -0
  23. package/dist/sip-message/outbound/index.js +12 -0
  24. package/dist/sip-message/outbound/request.cjs +62 -0
  25. package/dist/sip-message/outbound/request.js +33 -0
  26. package/dist/sip-message/outbound/response.cjs +55 -0
  27. package/dist/sip-message/outbound/response.js +26 -0
  28. package/dist/sip-message/response-codes.cjs +102 -0
  29. package/dist/sip-message/response-codes.js +83 -0
  30. package/dist/sip-message/sip-message.cjs +53 -0
  31. package/dist/sip-message/sip-message.js +34 -0
  32. package/dist/types.cjs +15 -0
  33. package/dist/types.js +0 -0
  34. package/dist/utils.cjs +80 -0
  35. package/dist/{cjs/utils.d.ts → utils.d.ts} +2 -2
  36. package/dist/utils.js +41 -0
  37. package/package.json +19 -13
  38. package/dist/cjs/call-session/inbound.js +0 -57
  39. package/dist/cjs/call-session/index.d.ts +0 -44
  40. package/dist/cjs/call-session/index.js +0 -239
  41. package/dist/cjs/call-session/outbound.js +0 -66
  42. package/dist/cjs/call-session/streamer.d.ts +0 -17
  43. package/dist/cjs/call-session/streamer.js +0 -76
  44. package/dist/cjs/codec.js +0 -65
  45. package/dist/cjs/dtmf.js +0 -45
  46. package/dist/cjs/index.js +0 -209
  47. package/dist/cjs/sip-message/inbound/index.js +0 -22
  48. package/dist/cjs/sip-message/index.d.ts +0 -5
  49. package/dist/cjs/sip-message/index.js +0 -16
  50. package/dist/cjs/sip-message/outbound/index.js +0 -14
  51. package/dist/cjs/sip-message/outbound/request.js +0 -28
  52. package/dist/cjs/sip-message/outbound/response.js +0 -25
  53. package/dist/cjs/sip-message/response-codes.js +0 -83
  54. package/dist/cjs/sip-message/sip-message.js +0 -34
  55. package/dist/cjs/types.js +0 -2
  56. package/dist/cjs/utils.js +0 -40
  57. package/dist/esm/call-session/inbound.d.ts +0 -8
  58. package/dist/esm/call-session/inbound.js +0 -52
  59. package/dist/esm/call-session/index.js +0 -234
  60. package/dist/esm/call-session/outbound.d.ts +0 -11
  61. package/dist/esm/call-session/outbound.js +0 -61
  62. package/dist/esm/call-session/streamer.js +0 -71
  63. package/dist/esm/codec.d.ts +0 -15
  64. package/dist/esm/codec.js +0 -63
  65. package/dist/esm/dtmf.d.ts +0 -8
  66. package/dist/esm/dtmf.js +0 -43
  67. package/dist/esm/index.d.ts +0 -28
  68. package/dist/esm/index.js +0 -204
  69. package/dist/esm/sip-message/inbound/index.d.ts +0 -5
  70. package/dist/esm/sip-message/inbound/index.js +0 -17
  71. package/dist/esm/sip-message/index.js +0 -5
  72. package/dist/esm/sip-message/outbound/index.d.ts +0 -5
  73. package/dist/esm/sip-message/outbound/index.js +0 -9
  74. package/dist/esm/sip-message/outbound/request.d.ts +0 -7
  75. package/dist/esm/sip-message/outbound/request.js +0 -23
  76. package/dist/esm/sip-message/outbound/response.d.ts +0 -6
  77. package/dist/esm/sip-message/outbound/response.js +0 -20
  78. package/dist/esm/sip-message/response-codes.d.ts +0 -4
  79. package/dist/esm/sip-message/response-codes.js +0 -81
  80. package/dist/esm/sip-message/sip-message.d.ts +0 -11
  81. package/dist/esm/sip-message/sip-message.js +0 -32
  82. package/dist/esm/types.d.ts +0 -9
  83. package/dist/esm/types.js +0 -1
  84. package/dist/esm/utils.d.ts +0 -8
  85. package/dist/esm/utils.js +0 -28
  86. package/dist/{cjs/call-session → call-session}/inbound.d.ts +2 -2
  87. package/dist/{cjs/call-session → call-session}/outbound.d.ts +2 -2
  88. package/dist/{esm/call-session → call-session}/streamer.d.ts +1 -1
  89. package/dist/{cjs/codec.d.ts → codec.d.ts} +0 -0
  90. package/dist/{cjs/dtmf.d.ts → dtmf.d.ts} +0 -0
  91. package/dist/{cjs/sip-message → sip-message}/inbound/index.d.ts +0 -0
  92. package/dist/{esm/sip-message → sip-message}/index.d.ts +2 -2
  93. package/dist/{cjs/sip-message → sip-message}/outbound/index.d.ts +0 -0
  94. package/dist/{cjs/sip-message → sip-message}/outbound/request.d.ts +0 -0
  95. package/dist/{cjs/sip-message → sip-message}/outbound/response.d.ts +1 -1
  96. /package/dist/{cjs/sip-message → sip-message}/response-codes.d.ts +0 -0
  97. /package/dist/{cjs/sip-message → sip-message}/sip-message.d.ts +0 -0
  98. /package/dist/{cjs/types.d.ts → types.d.ts} +0 -0
@@ -0,0 +1,244 @@
1
+ import { Buffer } from "node:buffer";
2
+ import dgram from "node:dgram";
3
+ import EventEmitter from "node:events";
4
+ import waitFor from "wait-for-async";
5
+ import { RtpHeader, RtpPacket, SrtpSession } from "werift-rtp";
6
+ import DTMF from "../dtmf.js";
7
+ import {
8
+ RequestMessage,
9
+ ResponseMessage
10
+ } from "../sip-message/index.js";
11
+ import { branch, extractAddress, localKey, randomInt } from "../utils.js";
12
+ import Streamer from "./streamer.js";
13
+ class CallSession extends EventEmitter {
14
+ softphone;
15
+ sipMessage;
16
+ socket;
17
+ localPeer;
18
+ remotePeer;
19
+ remoteIP;
20
+ remotePort;
21
+ disposed = false;
22
+ srtpSession;
23
+ encoder;
24
+ decoder;
25
+ sdp;
26
+ // for audio streaming
27
+ ssrc = randomInt();
28
+ sequenceNumber = randomInt();
29
+ timestamp = 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
+ if (this.sipMessage.body.length > 0) {
37
+ this.remoteIP = this.sipMessage.body.match(/c=IN IP4 ([\d.]+)/)[1];
38
+ this.remotePort = parseInt(
39
+ this.sipMessage.body.match(/m=audio (\d+) /)[1],
40
+ 10
41
+ );
42
+ }
43
+ }
44
+ set remoteKey(key) {
45
+ const localKeyBuffer = Buffer.from(localKey, "base64");
46
+ const remoteKeyBuffer = Buffer.from(key, "base64");
47
+ this.srtpSession = new SrtpSession({
48
+ profile: 1,
49
+ keys: {
50
+ localMasterKey: localKeyBuffer.subarray(0, 16),
51
+ localMasterSalt: localKeyBuffer.subarray(16, 30),
52
+ remoteMasterKey: remoteKeyBuffer.subarray(0, 16),
53
+ remoteMasterSalt: remoteKeyBuffer.subarray(16, 30)
54
+ }
55
+ });
56
+ }
57
+ get callId() {
58
+ return this.sipMessage.getHeader("Call-ID");
59
+ }
60
+ send(data) {
61
+ this.socket.send(data, this.remotePort, this.remoteIP);
62
+ }
63
+ async hangup() {
64
+ const requestMessage = new RequestMessage(
65
+ `BYE sip:${this.softphone.sipInfo.domain} SIP/2.0`,
66
+ {
67
+ "Call-ID": this.callId,
68
+ From: this.localPeer,
69
+ To: this.remotePeer,
70
+ Via: `SIP/2.0/TLS ${this.softphone.fakeDomain};branch=${branch()}`
71
+ }
72
+ );
73
+ await this.softphone.send(requestMessage);
74
+ }
75
+ sendDTMF(char) {
76
+ const payloads = DTMF.charToPayloads(char);
77
+ const timestamp = this.timestamp;
78
+ let first = true;
79
+ for (const payload of payloads) {
80
+ const rtpHeader = new RtpHeader({
81
+ version: 2,
82
+ padding: false,
83
+ paddingSize: 0,
84
+ extension: false,
85
+ marker: first,
86
+ payloadOffset: 12,
87
+ payloadType: 101,
88
+ sequenceNumber: this.sequenceNumber,
89
+ timestamp,
90
+ ssrc: this.ssrc,
91
+ csrcLength: 0,
92
+ csrc: [],
93
+ extensionProfile: 48862,
94
+ extensionLength: void 0,
95
+ extensions: []
96
+ });
97
+ const rtpPacket = new RtpPacket(rtpHeader, payload);
98
+ this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
99
+ this.sequenceNumber = (this.sequenceNumber + 1) % 65536;
100
+ first = false;
101
+ }
102
+ this.timestamp += 800;
103
+ }
104
+ async sendDTMFs(s, delay = 500) {
105
+ for (const c of s) {
106
+ this.sendDTMF(c);
107
+ await waitFor({ interval: delay });
108
+ }
109
+ }
110
+ // buffer is the content of a audio file, it is supposed to be uncompressed PCM data
111
+ // The audio should be playable by command: play -t raw -b 16 -r 16000 -e signed-integer test.wav
112
+ streamAudio(input) {
113
+ const streamer = new Streamer(this, input);
114
+ streamer.start();
115
+ return streamer;
116
+ }
117
+ // send a single rtp packet
118
+ sendPacket(rtpPacket) {
119
+ if (this.disposed) {
120
+ return;
121
+ }
122
+ this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
123
+ }
124
+ startLocalServices() {
125
+ this.socket = dgram.createSocket("udp4");
126
+ this.socket.on("message", (message) => {
127
+ const rtpPacket = RtpPacket.deSerialize(
128
+ this.srtpSession.decrypt(message)
129
+ );
130
+ this.emit("rtpPacket", rtpPacket);
131
+ if (rtpPacket.header.payloadType === 101) {
132
+ this.emit("dtmfPacket", rtpPacket);
133
+ const char = DTMF.payloadToChar(rtpPacket.payload);
134
+ if (char) {
135
+ this.emit("dtmf", char);
136
+ }
137
+ } else if (rtpPacket.header.payloadType === this.softphone.codec.id) {
138
+ if (rtpPacket.payload.length === 4 && rtpPacket.payload[0] >= 0 && rtpPacket.payload[0] < 12 && rtpPacket.payload[1] === 138 && rtpPacket.payload[2] === 3 && rtpPacket.payload[3] === 192) {
139
+ return;
140
+ }
141
+ try {
142
+ rtpPacket.payload = this.decoder.decode(rtpPacket.payload);
143
+ this.emit("audioPacket", rtpPacket);
144
+ } catch {
145
+ console.error("Audio packet decode failed", rtpPacket);
146
+ }
147
+ }
148
+ });
149
+ this.socket.bind();
150
+ this.send("hello");
151
+ const byeHandler = (inboundMessage) => {
152
+ if (inboundMessage.getHeader("Call-ID") !== this.callId) {
153
+ return;
154
+ }
155
+ if (inboundMessage.headers.CSeq.endsWith(" BYE")) {
156
+ this.softphone.off("message", byeHandler);
157
+ this.dispose();
158
+ }
159
+ };
160
+ this.softphone.on("message", byeHandler);
161
+ }
162
+ dispose() {
163
+ this.disposed = true;
164
+ this.emit("disposed");
165
+ this.removeAllListeners();
166
+ this.socket?.removeAllListeners();
167
+ this.socket?.close();
168
+ }
169
+ async transfer(transferTo) {
170
+ const requestMessage = new RequestMessage(
171
+ `REFER sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.outboundProxy};transport=tls SIP/2.0`,
172
+ {
173
+ Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${branch()};alias`,
174
+ "Max-Forwards": 70,
175
+ From: this.localPeer,
176
+ To: this.remotePeer,
177
+ Contact: `<sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,
178
+ "Call-ID": this.callId,
179
+ Event: "refer",
180
+ Expires: 600,
181
+ Supported: "replaces, 100rel, timer, norefersub",
182
+ Accept: "message/sipfrag;version=2.0",
183
+ "Allow-Events": "presence, message-summary, refer",
184
+ "Refer-To": `sip:${transferTo}@${this.softphone.sipInfo.domain}`,
185
+ "Referred-By": `<sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.domain}>`
186
+ }
187
+ );
188
+ await this.softphone.send(requestMessage);
189
+ return new Promise((resolve) => {
190
+ const notifyHandler = (inboundMessage) => {
191
+ if (!inboundMessage.subject.startsWith("NOTIFY ")) {
192
+ return;
193
+ }
194
+ const responseMessage = new ResponseMessage(inboundMessage, 200);
195
+ this.softphone.send(responseMessage);
196
+ if (inboundMessage.body.trim() === "SIP/2.0 200 OK") {
197
+ this.softphone.off("message", notifyHandler);
198
+ resolve();
199
+ }
200
+ };
201
+ this.softphone.on("message", notifyHandler);
202
+ });
203
+ }
204
+ async toggleReceive(toReceive) {
205
+ let newSDP = this.sdp;
206
+ if (!toReceive) {
207
+ newSDP = newSDP.replace(/a=sendrecv/, "a=sendonly");
208
+ }
209
+ const requestMessage = new RequestMessage(
210
+ `INVITE ${extractAddress(this.remotePeer)} SIP/2.0`,
211
+ {
212
+ "Call-Id": this.callId,
213
+ From: this.localPeer,
214
+ To: this.remotePeer,
215
+ Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${branch()};alias`,
216
+ "Content-Type": "application/sdp",
217
+ Contact: ` <sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`
218
+ },
219
+ newSDP
220
+ );
221
+ const replyMessage = await this.softphone.send(requestMessage, true);
222
+ const ackMessage = new RequestMessage(
223
+ `ACK ${extractAddress(this.remotePeer)} SIP/2.0`,
224
+ {
225
+ "Call-Id": this.callId,
226
+ From: this.localPeer,
227
+ To: this.remotePeer,
228
+ Via: replyMessage.headers.Via,
229
+ CSeq: replyMessage.headers.CSeq.replace(" INVITE", " ACK")
230
+ }
231
+ );
232
+ await this.softphone.send(ackMessage);
233
+ }
234
+ async hold() {
235
+ return this.toggleReceive(false);
236
+ }
237
+ async unhold() {
238
+ return this.toggleReceive(true);
239
+ }
240
+ }
241
+ var call_session_default = CallSession;
242
+ export {
243
+ call_session_default as default
244
+ };
@@ -0,0 +1,100 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var outbound_exports = {};
29
+ __export(outbound_exports, {
30
+ default: () => outbound_default
31
+ });
32
+ module.exports = __toCommonJS(outbound_exports);
33
+ var import_sip_message = require("../sip-message/index.js");
34
+ var import_utils = require("../utils.js");
35
+ var import_index = __toESM(require("./index.js"), 1);
36
+ class OutboundCallSession extends import_index.default {
37
+ constructor(softphone, answerMessage) {
38
+ super(softphone, answerMessage);
39
+ this.localPeer = answerMessage.headers.From;
40
+ this.remotePeer = answerMessage.headers.To;
41
+ this.remoteKey = answerMessage.body.match(
42
+ /AES_CM_128_HMAC_SHA1_80 inline:([\w+/]+)/
43
+ )[1];
44
+ this.init();
45
+ }
46
+ init() {
47
+ const answerHandler = (message) => {
48
+ if (message.headers.CSeq !== this.sipMessage.headers.CSeq) {
49
+ return;
50
+ }
51
+ if (message.subject.startsWith("SIP/2.0 486")) {
52
+ this.softphone.off("message", answerHandler);
53
+ this.emit("busy");
54
+ this.dispose();
55
+ return;
56
+ }
57
+ if (message.subject.startsWith("SIP/2.0 200")) {
58
+ this.softphone.off("message", answerHandler);
59
+ this.emit("answered");
60
+ const ackMessage = new import_sip_message.RequestMessage(
61
+ `ACK ${(0, import_utils.extractAddress)(this.remotePeer)} SIP/2.0`,
62
+ {
63
+ "Call-ID": this.callId,
64
+ From: this.localPeer,
65
+ To: this.remotePeer,
66
+ Via: this.sipMessage.headers.Via,
67
+ CSeq: this.sipMessage.headers.CSeq.replace(" INVITE", " ACK")
68
+ }
69
+ );
70
+ this.softphone.send(ackMessage);
71
+ }
72
+ };
73
+ this.softphone.on("message", answerHandler);
74
+ this.once("answered", () => this.startLocalServices());
75
+ }
76
+ async cancel() {
77
+ const requestMessage = new import_sip_message.RequestMessage(
78
+ `CANCEL ${(0, import_utils.extractAddress)(this.remotePeer)} SIP/2.0`,
79
+ {
80
+ "Call-ID": this.callId,
81
+ From: this.localPeer,
82
+ To: (0, import_utils.withoutTag)(this.remotePeer),
83
+ Via: this.sipMessage.headers.Via,
84
+ CSeq: this.sipMessage.headers.CSeq.replace(" INVITE", " CANCEL")
85
+ }
86
+ );
87
+ await this.softphone.send(requestMessage);
88
+ }
89
+ get sessionId() {
90
+ const header = this.sipMessage.headers["p-rc-api-ids"];
91
+ const match = header.match(/party-id=([^;]+);session-id=([^;]+)/);
92
+ return match[2];
93
+ }
94
+ get partyId() {
95
+ const header = this.sipMessage.headers["p-rc-api-ids"];
96
+ const match = header.match(/party-id=([^;]+);session-id=([^;]+)/);
97
+ return match[1];
98
+ }
99
+ }
100
+ var outbound_default = OutboundCallSession;
@@ -0,0 +1,71 @@
1
+ import { RequestMessage } from "../sip-message/index.js";
2
+ import { extractAddress, withoutTag } from "../utils.js";
3
+ import CallSession from "./index.js";
4
+ class OutboundCallSession extends CallSession {
5
+ constructor(softphone, answerMessage) {
6
+ super(softphone, answerMessage);
7
+ this.localPeer = answerMessage.headers.From;
8
+ this.remotePeer = answerMessage.headers.To;
9
+ this.remoteKey = answerMessage.body.match(
10
+ /AES_CM_128_HMAC_SHA1_80 inline:([\w+/]+)/
11
+ )[1];
12
+ this.init();
13
+ }
14
+ init() {
15
+ const answerHandler = (message) => {
16
+ if (message.headers.CSeq !== this.sipMessage.headers.CSeq) {
17
+ return;
18
+ }
19
+ if (message.subject.startsWith("SIP/2.0 486")) {
20
+ this.softphone.off("message", answerHandler);
21
+ this.emit("busy");
22
+ this.dispose();
23
+ return;
24
+ }
25
+ if (message.subject.startsWith("SIP/2.0 200")) {
26
+ this.softphone.off("message", answerHandler);
27
+ this.emit("answered");
28
+ const ackMessage = new RequestMessage(
29
+ `ACK ${extractAddress(this.remotePeer)} SIP/2.0`,
30
+ {
31
+ "Call-ID": this.callId,
32
+ From: this.localPeer,
33
+ To: this.remotePeer,
34
+ Via: this.sipMessage.headers.Via,
35
+ CSeq: this.sipMessage.headers.CSeq.replace(" INVITE", " ACK")
36
+ }
37
+ );
38
+ this.softphone.send(ackMessage);
39
+ }
40
+ };
41
+ this.softphone.on("message", answerHandler);
42
+ this.once("answered", () => this.startLocalServices());
43
+ }
44
+ async cancel() {
45
+ const requestMessage = new RequestMessage(
46
+ `CANCEL ${extractAddress(this.remotePeer)} SIP/2.0`,
47
+ {
48
+ "Call-ID": this.callId,
49
+ From: this.localPeer,
50
+ To: withoutTag(this.remotePeer),
51
+ Via: this.sipMessage.headers.Via,
52
+ CSeq: this.sipMessage.headers.CSeq.replace(" INVITE", " CANCEL")
53
+ }
54
+ );
55
+ await this.softphone.send(requestMessage);
56
+ }
57
+ get sessionId() {
58
+ const header = this.sipMessage.headers["p-rc-api-ids"];
59
+ const match = header.match(/party-id=([^;]+);session-id=([^;]+)/);
60
+ return match[2];
61
+ }
62
+ get partyId() {
63
+ const header = this.sipMessage.headers["p-rc-api-ids"];
64
+ const match = header.match(/party-id=([^;]+);session-id=([^;]+)/);
65
+ return match[1];
66
+ }
67
+ }
68
+ var outbound_default = OutboundCallSession;
69
+ export {
70
+ outbound_default as default
71
+ };
@@ -0,0 +1,112 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var streamer_exports = {};
29
+ __export(streamer_exports, {
30
+ default: () => streamer_default
31
+ });
32
+ module.exports = __toCommonJS(streamer_exports);
33
+ var import_node_buffer = require("node:buffer");
34
+ var import_node_events = __toESM(require("node:events"), 1);
35
+ var import_werift_rtp = require("werift-rtp");
36
+ class Streamer extends import_node_events.default {
37
+ paused = false;
38
+ callSession;
39
+ buffer;
40
+ originalBuffer;
41
+ constructor(callSesstion, buffer) {
42
+ super();
43
+ this.callSession = callSesstion;
44
+ this.buffer = buffer;
45
+ this.originalBuffer = buffer;
46
+ }
47
+ start() {
48
+ this.buffer = this.originalBuffer;
49
+ this.paused = false;
50
+ this.sendPacket();
51
+ }
52
+ stop() {
53
+ this.buffer = import_node_buffer.Buffer.alloc(0);
54
+ }
55
+ pause() {
56
+ this.paused = true;
57
+ }
58
+ resume() {
59
+ this.paused = false;
60
+ this.sendPacket();
61
+ }
62
+ get finished() {
63
+ return this.callSession.disposed || this.buffer.length < this.callSession.softphone.codec.packetSize;
64
+ }
65
+ sendPacket() {
66
+ if (!this.paused && !this.finished) {
67
+ const temp = this.callSession.encoder.encode(
68
+ this.buffer.subarray(0, this.callSession.softphone.codec.packetSize)
69
+ );
70
+ const rtpPacket = new import_werift_rtp.RtpPacket(
71
+ new import_werift_rtp.RtpHeader({
72
+ version: 2,
73
+ padding: false,
74
+ paddingSize: 0,
75
+ extension: false,
76
+ marker: false,
77
+ payloadOffset: 12,
78
+ payloadType: this.callSession.softphone.codec.id,
79
+ sequenceNumber: this.callSession.sequenceNumber,
80
+ timestamp: this.callSession.timestamp,
81
+ ssrc: this.callSession.ssrc,
82
+ csrcLength: 0,
83
+ csrc: [],
84
+ extensionProfile: 48862,
85
+ extensionLength: void 0,
86
+ extensions: []
87
+ }),
88
+ temp
89
+ );
90
+ this.callSession.send(
91
+ this.callSession.srtpSession.encrypt(
92
+ rtpPacket.payload,
93
+ rtpPacket.header
94
+ )
95
+ );
96
+ this.callSession.sequenceNumber += 1;
97
+ if (this.callSession.sequenceNumber > 65535) {
98
+ this.callSession.sequenceNumber = 0;
99
+ }
100
+ this.callSession.timestamp += this.callSession.softphone.codec.timestampInterval;
101
+ this.buffer = this.buffer.subarray(
102
+ this.callSession.softphone.codec.packetSize
103
+ );
104
+ if (this.finished) {
105
+ this.emit("finished");
106
+ } else {
107
+ setTimeout(() => this.sendPacket(), 20);
108
+ }
109
+ }
110
+ }
111
+ }
112
+ var streamer_default = Streamer;
@@ -0,0 +1,83 @@
1
+ import { Buffer } from "node:buffer";
2
+ import EventEmitter from "node:events";
3
+ import { RtpHeader, RtpPacket } from "werift-rtp";
4
+ class Streamer extends EventEmitter {
5
+ paused = false;
6
+ callSession;
7
+ buffer;
8
+ originalBuffer;
9
+ constructor(callSesstion, buffer) {
10
+ super();
11
+ this.callSession = callSesstion;
12
+ this.buffer = buffer;
13
+ this.originalBuffer = buffer;
14
+ }
15
+ start() {
16
+ this.buffer = this.originalBuffer;
17
+ this.paused = false;
18
+ this.sendPacket();
19
+ }
20
+ stop() {
21
+ this.buffer = Buffer.alloc(0);
22
+ }
23
+ pause() {
24
+ this.paused = true;
25
+ }
26
+ resume() {
27
+ this.paused = false;
28
+ this.sendPacket();
29
+ }
30
+ get finished() {
31
+ return this.callSession.disposed || this.buffer.length < this.callSession.softphone.codec.packetSize;
32
+ }
33
+ sendPacket() {
34
+ if (!this.paused && !this.finished) {
35
+ const temp = this.callSession.encoder.encode(
36
+ this.buffer.subarray(0, this.callSession.softphone.codec.packetSize)
37
+ );
38
+ const rtpPacket = new RtpPacket(
39
+ new RtpHeader({
40
+ version: 2,
41
+ padding: false,
42
+ paddingSize: 0,
43
+ extension: false,
44
+ marker: false,
45
+ payloadOffset: 12,
46
+ payloadType: this.callSession.softphone.codec.id,
47
+ sequenceNumber: this.callSession.sequenceNumber,
48
+ timestamp: this.callSession.timestamp,
49
+ ssrc: this.callSession.ssrc,
50
+ csrcLength: 0,
51
+ csrc: [],
52
+ extensionProfile: 48862,
53
+ extensionLength: void 0,
54
+ extensions: []
55
+ }),
56
+ temp
57
+ );
58
+ this.callSession.send(
59
+ this.callSession.srtpSession.encrypt(
60
+ rtpPacket.payload,
61
+ rtpPacket.header
62
+ )
63
+ );
64
+ this.callSession.sequenceNumber += 1;
65
+ if (this.callSession.sequenceNumber > 65535) {
66
+ this.callSession.sequenceNumber = 0;
67
+ }
68
+ this.callSession.timestamp += this.callSession.softphone.codec.timestampInterval;
69
+ this.buffer = this.buffer.subarray(
70
+ this.callSession.softphone.codec.packetSize
71
+ );
72
+ if (this.finished) {
73
+ this.emit("finished");
74
+ } else {
75
+ setTimeout(() => this.sendPacket(), 20);
76
+ }
77
+ }
78
+ }
79
+ }
80
+ var streamer_default = Streamer;
81
+ export {
82
+ streamer_default as default
83
+ };
package/dist/codec.cjs ADDED
@@ -0,0 +1,85 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var codec_exports = {};
19
+ __export(codec_exports, {
20
+ default: () => codec_default
21
+ });
22
+ module.exports = __toCommonJS(codec_exports);
23
+ var import_node_buffer = require("node:buffer");
24
+ var import_opus = require("@evan/opus");
25
+ class Codec {
26
+ id;
27
+ name;
28
+ packetSize;
29
+ timestampInterval;
30
+ createEncoder;
31
+ createDecoder;
32
+ constructor(name) {
33
+ this.name = name;
34
+ switch (name) {
35
+ case "OPUS/16000": {
36
+ this.createEncoder = () => {
37
+ const encoder = new import_opus.Encoder({ channels: 1, sample_rate: 16e3 });
38
+ return { encode: (pcm) => import_node_buffer.Buffer.from(encoder.encode(pcm)) };
39
+ };
40
+ this.createDecoder = () => {
41
+ const decoder = new import_opus.Decoder({ channels: 1, sample_rate: 16e3 });
42
+ return {
43
+ decode: (opus) => import_node_buffer.Buffer.from(decoder.decode(opus))
44
+ };
45
+ };
46
+ this.id = 109;
47
+ this.packetSize = 640;
48
+ this.timestampInterval = 320;
49
+ break;
50
+ }
51
+ case "OPUS/48000/2": {
52
+ this.createEncoder = () => {
53
+ const encoder = new import_opus.Encoder({ channels: 2, sample_rate: 48e3 });
54
+ return { encode: (pcm) => import_node_buffer.Buffer.from(encoder.encode(pcm)) };
55
+ };
56
+ this.createDecoder = () => {
57
+ const decoder = new import_opus.Decoder({ channels: 2, sample_rate: 48e3 });
58
+ return {
59
+ decode: (opus) => import_node_buffer.Buffer.from(decoder.decode(opus))
60
+ };
61
+ };
62
+ this.id = 111;
63
+ this.packetSize = 3840;
64
+ this.timestampInterval = 960;
65
+ break;
66
+ }
67
+ case "PCMU/8000": {
68
+ this.createEncoder = () => {
69
+ return { encode: (pcm) => pcm };
70
+ };
71
+ this.createDecoder = () => {
72
+ return { decode: (audio) => audio };
73
+ };
74
+ this.id = 0;
75
+ this.packetSize = 160;
76
+ this.timestampInterval = 160;
77
+ break;
78
+ }
79
+ default: {
80
+ throw new Error(`unsupported codec: ${name}`);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ var codec_default = Codec;