ringcentral-softphone 1.3.2 → 1.3.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.
Files changed (99) 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 +274 -0
  5. package/dist/{esm/call-session → call-session}/index.d.ts +6 -4
  6. package/dist/call-session/index.js +248 -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/{esm/call-session → call-session}/streamer.d.ts +2 -2
  11. package/dist/call-session/streamer.js +83 -0
  12. package/dist/codec.cjs +85 -0
  13. package/dist/codec.js +66 -0
  14. package/dist/dtmf.cjs +66 -0
  15. package/dist/dtmf.d.ts +7 -0
  16. package/dist/dtmf.js +47 -0
  17. package/dist/index.cjs +260 -0
  18. package/dist/{cjs/index.d.ts → index.d.ts} +3 -3
  19. package/dist/index.js +242 -0
  20. package/dist/sip-message/inbound/index.cjs +51 -0
  21. package/dist/sip-message/inbound/index.js +22 -0
  22. package/dist/sip-message/index.cjs +49 -0
  23. package/dist/sip-message/index.js +12 -0
  24. package/dist/sip-message/outbound/index.cjs +41 -0
  25. package/dist/sip-message/outbound/index.js +12 -0
  26. package/dist/sip-message/outbound/request.cjs +62 -0
  27. package/dist/sip-message/outbound/request.js +33 -0
  28. package/dist/sip-message/outbound/response.cjs +55 -0
  29. package/dist/sip-message/outbound/response.js +26 -0
  30. package/dist/sip-message/response-codes.cjs +102 -0
  31. package/dist/sip-message/response-codes.js +83 -0
  32. package/dist/sip-message/sip-message.cjs +53 -0
  33. package/dist/sip-message/sip-message.js +34 -0
  34. package/dist/types.cjs +15 -0
  35. package/dist/types.js +0 -0
  36. package/dist/utils.cjs +80 -0
  37. package/dist/{cjs/utils.d.ts → utils.d.ts} +2 -2
  38. package/dist/utils.js +41 -0
  39. package/package.json +19 -13
  40. package/dist/cjs/call-session/inbound.js +0 -57
  41. package/dist/cjs/call-session/index.d.ts +0 -44
  42. package/dist/cjs/call-session/index.js +0 -239
  43. package/dist/cjs/call-session/outbound.js +0 -66
  44. package/dist/cjs/call-session/streamer.d.ts +0 -17
  45. package/dist/cjs/call-session/streamer.js +0 -76
  46. package/dist/cjs/codec.js +0 -65
  47. package/dist/cjs/dtmf.d.ts +0 -8
  48. package/dist/cjs/dtmf.js +0 -45
  49. package/dist/cjs/index.js +0 -209
  50. package/dist/cjs/sip-message/inbound/index.js +0 -22
  51. package/dist/cjs/sip-message/index.d.ts +0 -5
  52. package/dist/cjs/sip-message/index.js +0 -16
  53. package/dist/cjs/sip-message/outbound/index.js +0 -14
  54. package/dist/cjs/sip-message/outbound/request.js +0 -28
  55. package/dist/cjs/sip-message/outbound/response.js +0 -25
  56. package/dist/cjs/sip-message/response-codes.js +0 -83
  57. package/dist/cjs/sip-message/sip-message.js +0 -34
  58. package/dist/cjs/types.js +0 -2
  59. package/dist/cjs/utils.js +0 -40
  60. package/dist/esm/call-session/inbound.d.ts +0 -8
  61. package/dist/esm/call-session/inbound.js +0 -52
  62. package/dist/esm/call-session/index.js +0 -234
  63. package/dist/esm/call-session/outbound.d.ts +0 -11
  64. package/dist/esm/call-session/outbound.js +0 -61
  65. package/dist/esm/call-session/streamer.js +0 -71
  66. package/dist/esm/codec.d.ts +0 -15
  67. package/dist/esm/codec.js +0 -63
  68. package/dist/esm/dtmf.d.ts +0 -8
  69. package/dist/esm/dtmf.js +0 -43
  70. package/dist/esm/index.d.ts +0 -28
  71. package/dist/esm/index.js +0 -204
  72. package/dist/esm/sip-message/inbound/index.d.ts +0 -5
  73. package/dist/esm/sip-message/inbound/index.js +0 -17
  74. package/dist/esm/sip-message/index.js +0 -5
  75. package/dist/esm/sip-message/outbound/index.d.ts +0 -5
  76. package/dist/esm/sip-message/outbound/index.js +0 -9
  77. package/dist/esm/sip-message/outbound/request.d.ts +0 -7
  78. package/dist/esm/sip-message/outbound/request.js +0 -23
  79. package/dist/esm/sip-message/outbound/response.d.ts +0 -6
  80. package/dist/esm/sip-message/outbound/response.js +0 -20
  81. package/dist/esm/sip-message/response-codes.d.ts +0 -4
  82. package/dist/esm/sip-message/response-codes.js +0 -81
  83. package/dist/esm/sip-message/sip-message.d.ts +0 -11
  84. package/dist/esm/sip-message/sip-message.js +0 -32
  85. package/dist/esm/types.d.ts +0 -9
  86. package/dist/esm/types.js +0 -1
  87. package/dist/esm/utils.d.ts +0 -8
  88. package/dist/esm/utils.js +0 -28
  89. package/dist/{cjs/call-session → call-session}/inbound.d.ts +2 -2
  90. package/dist/{cjs/call-session → call-session}/outbound.d.ts +2 -2
  91. package/dist/{cjs/codec.d.ts → codec.d.ts} +0 -0
  92. package/dist/{cjs/sip-message → sip-message}/inbound/index.d.ts +0 -0
  93. package/dist/{esm/sip-message → sip-message}/index.d.ts +2 -2
  94. package/dist/{cjs/sip-message → sip-message}/outbound/index.d.ts +0 -0
  95. package/dist/{cjs/sip-message → sip-message}/outbound/request.d.ts +0 -0
  96. package/dist/{cjs/sip-message → sip-message}/outbound/response.d.ts +1 -1
  97. /package/dist/{cjs/sip-message → sip-message}/response-codes.d.ts +0 -0
  98. /package/dist/{cjs/sip-message → sip-message}/sip-message.d.ts +0 -0
  99. /package/dist/{cjs/types.d.ts → types.d.ts} +0 -0
@@ -1,239 +0,0 @@
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 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
- const wait_for_async_1 = __importDefault(require("wait-for-async"));
15
- class CallSession extends node_events_1.default {
16
- softphone;
17
- sipMessage;
18
- socket;
19
- localPeer;
20
- remotePeer;
21
- remoteIP;
22
- remotePort;
23
- disposed = false;
24
- srtpSession;
25
- encoder;
26
- decoder;
27
- sdp;
28
- // for audio streaming
29
- ssrc = (0, utils_js_1.randomInt)();
30
- sequenceNumber = (0, utils_js_1.randomInt)();
31
- timestamp = (0, utils_js_1.randomInt)();
32
- constructor(softphone, sipMessage) {
33
- super();
34
- this.softphone = softphone;
35
- this.encoder = softphone.codec.createEncoder();
36
- this.decoder = softphone.codec.createDecoder();
37
- this.sipMessage = sipMessage;
38
- // inbound call from call queue, invite message may not have body
39
- if (this.sipMessage.body.length > 0) {
40
- this.remoteIP = this.sipMessage.body.match(/c=IN IP4 ([\d.]+)/)[1];
41
- this.remotePort = parseInt(this.sipMessage.body.match(/m=audio (\d+) /)[1], 10);
42
- }
43
- }
44
- set remoteKey(key) {
45
- const localKeyBuffer = node_buffer_1.Buffer.from(utils_js_1.localKey, "base64");
46
- const remoteKeyBuffer = node_buffer_1.Buffer.from(key, "base64");
47
- this.srtpSession = new werift_rtp_1.SrtpSession({
48
- profile: 0x0001,
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 index_js_1.RequestMessage(`BYE sip:${this.softphone.sipInfo.domain} SIP/2.0`, {
65
- "Call-ID": this.callId,
66
- From: this.localPeer,
67
- To: this.remotePeer,
68
- Via: `SIP/2.0/TLS ${this.softphone.fakeDomain};branch=${(0, utils_js_1.branch)()}`,
69
- });
70
- await this.softphone.send(requestMessage);
71
- }
72
- sendDTMF(char) {
73
- const payloads = dtmf_js_1.default.charToPayloads(char);
74
- const timestamp = this.timestamp;
75
- let first = true;
76
- for (const payload of payloads) {
77
- const rtpHeader = new werift_rtp_1.RtpHeader({
78
- version: 2,
79
- padding: false,
80
- paddingSize: 0,
81
- extension: false,
82
- marker: first,
83
- payloadOffset: 12,
84
- payloadType: 101,
85
- sequenceNumber: this.sequenceNumber,
86
- timestamp,
87
- ssrc: this.ssrc,
88
- csrcLength: 0,
89
- csrc: [],
90
- extensionProfile: 48862,
91
- extensionLength: undefined,
92
- extensions: [],
93
- });
94
- const rtpPacket = new werift_rtp_1.RtpPacket(rtpHeader, payload);
95
- this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
96
- this.sequenceNumber = (this.sequenceNumber + 1) % 65536;
97
- first = false;
98
- }
99
- this.timestamp += 800;
100
- }
101
- async sendDTMFs(s, delay = 500) {
102
- for (const c of s) {
103
- this.sendDTMF(c);
104
- await (0, wait_for_async_1.default)({ interval: delay });
105
- }
106
- }
107
- // buffer is the content of a audio file, it is supposed to be uncompressed PCM data
108
- // The audio should be playable by command: play -t raw -b 16 -r 16000 -e signed-integer test.wav
109
- streamAudio(input) {
110
- const streamer = new streamer_js_1.default(this, input);
111
- streamer.start();
112
- return streamer;
113
- }
114
- // send a single rtp packet
115
- sendPacket(rtpPacket) {
116
- if (this.disposed) {
117
- return;
118
- }
119
- this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
120
- }
121
- startLocalServices() {
122
- this.socket = node_dgram_1.default.createSocket("udp4");
123
- this.socket.on("message", (message) => {
124
- const rtpPacket = werift_rtp_1.RtpPacket.deSerialize(this.srtpSession.decrypt(message));
125
- this.emit("rtpPacket", rtpPacket);
126
- if (rtpPacket.header.payloadType === 101) {
127
- this.emit("dtmfPacket", rtpPacket);
128
- const char = dtmf_js_1.default.payloadToChar(rtpPacket.payload);
129
- if (char) {
130
- this.emit("dtmf", char);
131
- }
132
- }
133
- else if (rtpPacket.header.payloadType === this.softphone.codec.id) {
134
- if (rtpPacket.payload.length === 4 &&
135
- rtpPacket.payload[0] >= 0x00 &&
136
- rtpPacket.payload[0] < 0x0c &&
137
- rtpPacket.payload[1] === 0x8a &&
138
- rtpPacket.payload[2] === 0x03 &&
139
- rtpPacket.payload[3] === 0xc0) {
140
- // special DTMF packet in audio format
141
- // first byte 0x00 to 0x0c means DTMF 0 to 9, *, #
142
- // we ignore it since DTMF is handled by `if (rtpPacket.header.payloadType === 101) {`
143
- return; // ignore it
144
- }
145
- try {
146
- rtpPacket.payload = this.decoder.decode(rtpPacket.payload);
147
- this.emit("audioPacket", rtpPacket);
148
- }
149
- catch {
150
- console.error("Audio packet decode failed", rtpPacket);
151
- }
152
- }
153
- });
154
- // as I tested, we can use a random port here and it still works
155
- // but it seems that in SDP we need to tell remote our local IP Address, not 127.0.0.1
156
- this.socket.bind(); // random port
157
- // send a message to remote server so that it knows where to reply
158
- this.send("hello");
159
- const byeHandler = (inboundMessage) => {
160
- if (inboundMessage.getHeader("Call-ID") !== this.callId) {
161
- return;
162
- }
163
- if (inboundMessage.headers.CSeq.endsWith(" BYE")) {
164
- this.softphone.off("message", byeHandler);
165
- this.dispose();
166
- }
167
- };
168
- this.softphone.on("message", byeHandler);
169
- }
170
- dispose() {
171
- this.disposed = true;
172
- this.emit("disposed");
173
- this.removeAllListeners();
174
- this.socket?.removeAllListeners();
175
- this.socket?.close();
176
- }
177
- async transfer(transferTo) {
178
- const requestMessage = new index_js_1.RequestMessage(`REFER sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.outboundProxy};transport=tls SIP/2.0`, {
179
- Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${(0, utils_js_1.branch)()};alias`,
180
- "Max-Forwards": 70,
181
- From: this.localPeer,
182
- To: this.remotePeer,
183
- Contact: `<sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,
184
- "Call-ID": this.callId,
185
- Event: "refer",
186
- Expires: 600,
187
- Supported: "replaces, 100rel, timer, norefersub",
188
- Accept: "message/sipfrag;version=2.0",
189
- "Allow-Events": "presence, message-summary, refer",
190
- "Refer-To": `sip:${transferTo}@${this.softphone.sipInfo.domain}`,
191
- "Referred-By": `<sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.domain}>`,
192
- });
193
- await this.softphone.send(requestMessage);
194
- return new Promise((resolve) => {
195
- const notifyHandler = (inboundMessage) => {
196
- if (!inboundMessage.subject.startsWith("NOTIFY ")) {
197
- return;
198
- }
199
- const responseMessage = new index_js_1.ResponseMessage(inboundMessage, 200);
200
- this.softphone.send(responseMessage);
201
- if (inboundMessage.body.trim() === "SIP/2.0 200 OK") {
202
- this.softphone.off("message", notifyHandler);
203
- resolve();
204
- }
205
- };
206
- this.softphone.on("message", notifyHandler);
207
- });
208
- }
209
- async toggleReceive(toReceive) {
210
- let newSDP = this.sdp;
211
- if (!toReceive) {
212
- newSDP = newSDP.replace(/a=sendrecv/, "a=sendonly");
213
- }
214
- const requestMessage = new index_js_1.RequestMessage(`INVITE ${(0, utils_js_1.extractAddress)(this.remotePeer)} SIP/2.0`, {
215
- "Call-Id": this.callId,
216
- From: this.localPeer,
217
- To: this.remotePeer,
218
- Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${(0, utils_js_1.branch)()};alias`,
219
- "Content-Type": "application/sdp",
220
- Contact: ` <sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,
221
- }, newSDP);
222
- const replyMessage = await this.softphone.send(requestMessage, true);
223
- const ackMessage = new index_js_1.RequestMessage(`ACK ${(0, utils_js_1.extractAddress)(this.remotePeer)} SIP/2.0`, {
224
- "Call-Id": this.callId,
225
- From: this.localPeer,
226
- To: this.remotePeer,
227
- Via: replyMessage.headers.Via,
228
- CSeq: replyMessage.headers.CSeq.replace(" INVITE", " ACK"),
229
- });
230
- await this.softphone.send(ackMessage);
231
- }
232
- async hold() {
233
- return this.toggleReceive(false);
234
- }
235
- async unhold() {
236
- return this.toggleReceive(true);
237
- }
238
- }
239
- exports.default = CallSession;
@@ -1,66 +0,0 @@
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 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 OutboundCallSession extends index_js_1.default {
10
- constructor(softphone, answerMessage) {
11
- super(softphone, answerMessage);
12
- this.localPeer = answerMessage.headers.From;
13
- this.remotePeer = answerMessage.headers.To;
14
- this.remoteKey = answerMessage.body.match(/AES_CM_128_HMAC_SHA1_80 inline:([\w+/]+)/)[1];
15
- this.init();
16
- }
17
- init() {
18
- // wait for user to answer the call
19
- const answerHandler = (message) => {
20
- if (message.headers.CSeq !== this.sipMessage.headers.CSeq) {
21
- return;
22
- }
23
- if (message.subject.startsWith("SIP/2.0 486")) {
24
- this.softphone.off("message", answerHandler);
25
- this.emit("busy");
26
- this.dispose();
27
- return;
28
- }
29
- if (message.subject.startsWith("SIP/2.0 200")) {
30
- this.softphone.off("message", answerHandler);
31
- this.emit("answered");
32
- const ackMessage = new index_js_2.RequestMessage(`ACK ${(0, utils_js_1.extractAddress)(this.remotePeer)} SIP/2.0`, {
33
- "Call-ID": this.callId,
34
- From: this.localPeer,
35
- To: this.remotePeer,
36
- Via: this.sipMessage.headers.Via,
37
- CSeq: this.sipMessage.headers.CSeq.replace(" INVITE", " ACK"),
38
- });
39
- this.softphone.send(ackMessage);
40
- }
41
- };
42
- this.softphone.on("message", answerHandler);
43
- this.once("answered", () => this.startLocalServices());
44
- }
45
- async cancel() {
46
- const requestMessage = new index_js_2.RequestMessage(`CANCEL ${(0, utils_js_1.extractAddress)(this.remotePeer)} SIP/2.0`, {
47
- "Call-ID": this.callId,
48
- From: this.localPeer,
49
- To: (0, utils_js_1.withoutTag)(this.remotePeer),
50
- Via: this.sipMessage.headers.Via,
51
- CSeq: this.sipMessage.headers.CSeq.replace(" INVITE", " CANCEL"),
52
- });
53
- await this.softphone.send(requestMessage);
54
- }
55
- get sessionId() {
56
- const header = this.sipMessage.headers["p-rc-api-ids"];
57
- let match = header.match(/party-id=([^;]+);session-id=([^;]+)/);
58
- return match[2];
59
- }
60
- get partyId() {
61
- const header = this.sipMessage.headers["p-rc-api-ids"];
62
- let match = header.match(/party-id=([^;]+);session-id=([^;]+)/);
63
- return match[1];
64
- }
65
- }
66
- exports.default = OutboundCallSession;
@@ -1,17 +0,0 @@
1
- import EventEmitter from "node:events";
2
- import { Buffer } from "node:buffer";
3
- import type CallSession from "./index.js";
4
- declare class Streamer extends EventEmitter {
5
- paused: boolean;
6
- private callSession;
7
- private buffer;
8
- private originalBuffer;
9
- constructor(callSesstion: CallSession, buffer: Buffer);
10
- start(): void;
11
- stop(): void;
12
- pause(): void;
13
- resume(): void;
14
- get finished(): boolean;
15
- private sendPacket;
16
- }
17
- export default Streamer;
@@ -1,76 +0,0 @@
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 node_events_1 = __importDefault(require("node:events"));
7
- const node_buffer_1 = require("node:buffer");
8
- const werift_rtp_1 = require("werift-rtp");
9
- class Streamer extends node_events_1.default {
10
- paused = false;
11
- callSession;
12
- buffer;
13
- originalBuffer;
14
- constructor(callSesstion, buffer) {
15
- super();
16
- this.callSession = callSesstion;
17
- this.buffer = buffer;
18
- this.originalBuffer = buffer;
19
- }
20
- start() {
21
- this.buffer = this.originalBuffer;
22
- this.paused = false;
23
- this.sendPacket();
24
- }
25
- stop() {
26
- this.buffer = node_buffer_1.Buffer.alloc(0);
27
- }
28
- pause() {
29
- this.paused = true;
30
- }
31
- resume() {
32
- this.paused = false;
33
- this.sendPacket();
34
- }
35
- get finished() {
36
- return this.callSession.disposed ||
37
- this.buffer.length < this.callSession.softphone.codec.packetSize;
38
- }
39
- sendPacket() {
40
- if (!this.paused && !this.finished) {
41
- const temp = this.callSession.encoder.encode(this.buffer.subarray(0, this.callSession.softphone.codec.packetSize));
42
- const rtpPacket = new werift_rtp_1.RtpPacket(new werift_rtp_1.RtpHeader({
43
- version: 2,
44
- padding: false,
45
- paddingSize: 0,
46
- extension: false,
47
- marker: false,
48
- payloadOffset: 12,
49
- payloadType: this.callSession.softphone.codec.id,
50
- sequenceNumber: this.callSession.sequenceNumber,
51
- timestamp: this.callSession.timestamp,
52
- ssrc: this.callSession.ssrc,
53
- csrcLength: 0,
54
- csrc: [],
55
- extensionProfile: 48862,
56
- extensionLength: undefined,
57
- extensions: [],
58
- }), temp);
59
- this.callSession.send(this.callSession.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
60
- this.callSession.sequenceNumber += 1;
61
- if (this.callSession.sequenceNumber > 65535) {
62
- this.callSession.sequenceNumber = 0;
63
- }
64
- this.callSession.timestamp +=
65
- this.callSession.softphone.codec.timestampInterval;
66
- this.buffer = this.buffer.subarray(this.callSession.softphone.codec.packetSize);
67
- if (this.finished) {
68
- this.emit("finished");
69
- }
70
- else {
71
- setTimeout(() => this.sendPacket(), 20);
72
- }
73
- }
74
- }
75
- }
76
- exports.default = Streamer;
package/dist/cjs/codec.js DELETED
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const node_buffer_1 = require("node:buffer");
4
- const opus_1 = require("@evan/opus");
5
- class Codec {
6
- id;
7
- name;
8
- packetSize;
9
- timestampInterval;
10
- createEncoder;
11
- createDecoder;
12
- constructor(name) {
13
- this.name = name;
14
- switch (name) {
15
- case "OPUS/16000": {
16
- this.createEncoder = () => {
17
- const encoder = new opus_1.Encoder({ channels: 1, sample_rate: 16000 });
18
- return { encode: (pcm) => node_buffer_1.Buffer.from(encoder.encode(pcm)) };
19
- };
20
- this.createDecoder = () => {
21
- const decoder = new opus_1.Decoder({ channels: 1, sample_rate: 16000 });
22
- return {
23
- decode: (opus) => node_buffer_1.Buffer.from(decoder.decode(opus)),
24
- };
25
- };
26
- this.id = 109;
27
- this.packetSize = 640;
28
- this.timestampInterval = 320;
29
- break;
30
- }
31
- case "OPUS/48000/2": {
32
- this.createEncoder = () => {
33
- const encoder = new opus_1.Encoder({ channels: 2, sample_rate: 48000 });
34
- return { encode: (pcm) => node_buffer_1.Buffer.from(encoder.encode(pcm)) };
35
- };
36
- this.createDecoder = () => {
37
- const decoder = new opus_1.Decoder({ channels: 2, sample_rate: 48000 });
38
- return {
39
- decode: (opus) => node_buffer_1.Buffer.from(decoder.decode(opus)),
40
- };
41
- };
42
- this.id = 111;
43
- this.packetSize = 3840;
44
- this.timestampInterval = 960;
45
- break;
46
- }
47
- case "PCMU/8000": {
48
- this.createEncoder = () => {
49
- return { encode: (pcm) => pcm };
50
- };
51
- this.createDecoder = () => {
52
- return { decode: (audio) => audio };
53
- };
54
- this.id = 0;
55
- this.packetSize = 160;
56
- this.timestampInterval = 160;
57
- break;
58
- }
59
- default: {
60
- throw new Error(`unsupported codec: ${name}`);
61
- }
62
- }
63
- }
64
- }
65
- exports.default = Codec;
@@ -1,8 +0,0 @@
1
- import { Buffer } from "node:buffer";
2
- declare class DTMF {
3
- static readonly phoneChars: string[];
4
- private static readonly payloads;
5
- static charToPayloads: (char: string) => Buffer<ArrayBuffer>[];
6
- static payloadToChar: (payload: Buffer) => string;
7
- }
8
- export default DTMF;
package/dist/cjs/dtmf.js DELETED
@@ -1,45 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const node_buffer_1 = require("node:buffer");
4
- class DTMF {
5
- static phoneChars = [
6
- "0",
7
- "1",
8
- "2",
9
- "3",
10
- "4",
11
- "5",
12
- "6",
13
- "7",
14
- "8",
15
- "9",
16
- "*",
17
- "#",
18
- ];
19
- static payloads = [
20
- 0x00060000,
21
- 0x000600a0,
22
- 0x00060140,
23
- 0x00860320,
24
- 0x00860320,
25
- 0x00860320,
26
- ];
27
- static charToPayloads = (char) => {
28
- const index = DTMF.phoneChars.indexOf(char[0]);
29
- if (index === -1) {
30
- throw new Error("invalid phone char");
31
- }
32
- return DTMF.payloads.map((payload) => {
33
- const temp = payload + index * 0x01000000;
34
- const buffer = node_buffer_1.Buffer.alloc(4);
35
- buffer.writeIntBE(temp, 0, 4);
36
- return buffer;
37
- });
38
- };
39
- static payloadToChar = (payload) => {
40
- const intBE = payload.readIntBE(0, 4);
41
- const index = (intBE - 0x00060000) / 0x01000000;
42
- return DTMF.phoneChars[index];
43
- };
44
- }
45
- exports.default = DTMF;