ringcentral-softphone 1.0.7 → 1.1.0

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 (158) hide show
  1. package/README.md +107 -34
  2. package/dist/{src → cjs}/call-session/inbound.d.ts +3 -3
  3. package/dist/cjs/call-session/inbound.js +96 -0
  4. package/dist/cjs/call-session/inbound.js.map +1 -0
  5. package/dist/{src → cjs}/call-session/index.d.ts +13 -8
  6. package/dist/cjs/call-session/index.js +268 -0
  7. package/dist/cjs/call-session/index.js.map +1 -0
  8. package/dist/{src → cjs}/call-session/outbound.d.ts +3 -3
  9. package/dist/cjs/call-session/outbound.js +125 -0
  10. package/dist/cjs/call-session/outbound.js.map +1 -0
  11. package/dist/{src → cjs}/call-session/streamer.d.ts +2 -2
  12. package/dist/cjs/call-session/streamer.js +151 -0
  13. package/dist/cjs/call-session/streamer.js.map +1 -0
  14. package/dist/cjs/codec.d.ts +14 -0
  15. package/dist/cjs/codec.js +60 -0
  16. package/dist/cjs/codec.js.map +1 -0
  17. package/dist/cjs/dtmf.js +48 -0
  18. package/dist/cjs/dtmf.js.map +1 -0
  19. package/dist/cjs/index.d.ts +28 -0
  20. package/dist/cjs/index.js +299 -0
  21. package/dist/cjs/index.js.map +1 -0
  22. package/dist/{src → cjs}/sip-message/inbound/index.d.ts +1 -1
  23. package/dist/cjs/sip-message/inbound/index.js +43 -0
  24. package/dist/cjs/sip-message/inbound/index.js.map +1 -0
  25. package/dist/cjs/sip-message/index.d.ts +5 -0
  26. package/dist/{src → cjs}/sip-message/index.js +10 -10
  27. package/dist/cjs/sip-message/index.js.map +1 -0
  28. package/dist/{src → cjs}/sip-message/outbound/index.d.ts +1 -1
  29. package/dist/cjs/sip-message/outbound/index.js +36 -0
  30. package/dist/cjs/sip-message/outbound/index.js.map +1 -0
  31. package/dist/{src → cjs}/sip-message/outbound/request.d.ts +1 -1
  32. package/dist/cjs/sip-message/outbound/request.js +61 -0
  33. package/dist/cjs/sip-message/outbound/request.js.map +1 -0
  34. package/dist/{src → cjs}/sip-message/outbound/response.d.ts +2 -2
  35. package/dist/cjs/sip-message/outbound/response.js +53 -0
  36. package/dist/cjs/sip-message/outbound/response.js.map +1 -0
  37. package/dist/cjs/sip-message/response-codes.js +84 -0
  38. package/dist/{src → cjs}/sip-message/response-codes.js.map +1 -1
  39. package/dist/cjs/sip-message/sip-message.js +40 -0
  40. package/dist/cjs/sip-message/sip-message.js.map +1 -0
  41. package/dist/cjs/types.d.ts +8 -0
  42. package/dist/cjs/types.js +3 -0
  43. package/dist/cjs/types.js.map +1 -0
  44. package/dist/{src → cjs}/utils.d.ts +2 -2
  45. package/dist/cjs/utils.js +43 -0
  46. package/dist/cjs/utils.js.map +1 -0
  47. package/dist/esm/call-session/inbound.d.ts +8 -0
  48. package/dist/esm/call-session/inbound.js +91 -0
  49. package/dist/esm/call-session/inbound.js.map +1 -0
  50. package/dist/esm/call-session/index.d.ts +38 -0
  51. package/dist/esm/call-session/index.js +263 -0
  52. package/dist/esm/call-session/index.js.map +1 -0
  53. package/dist/esm/call-session/outbound.d.ts +9 -0
  54. package/dist/esm/call-session/outbound.js +120 -0
  55. package/dist/esm/call-session/outbound.js.map +1 -0
  56. package/dist/esm/call-session/streamer.d.ts +16 -0
  57. package/dist/esm/call-session/streamer.js +146 -0
  58. package/dist/esm/call-session/streamer.js.map +1 -0
  59. package/dist/esm/codec.d.ts +14 -0
  60. package/dist/esm/codec.js +58 -0
  61. package/dist/esm/codec.js.map +1 -0
  62. package/dist/esm/dtmf.d.ts +7 -0
  63. package/dist/esm/dtmf.js +46 -0
  64. package/dist/esm/dtmf.js.map +1 -0
  65. package/dist/esm/index.d.ts +28 -0
  66. package/dist/esm/index.js +294 -0
  67. package/dist/esm/index.js.map +1 -0
  68. package/dist/esm/sip-message/inbound/index.d.ts +5 -0
  69. package/dist/esm/sip-message/inbound/index.js +38 -0
  70. package/dist/esm/sip-message/inbound/index.js.map +1 -0
  71. package/dist/esm/sip-message/index.d.ts +5 -0
  72. package/dist/esm/sip-message/index.js +6 -0
  73. package/dist/esm/sip-message/index.js.map +1 -0
  74. package/dist/esm/sip-message/outbound/index.d.ts +5 -0
  75. package/dist/esm/sip-message/outbound/index.js +31 -0
  76. package/dist/esm/sip-message/outbound/index.js.map +1 -0
  77. package/dist/esm/sip-message/outbound/request.d.ts +7 -0
  78. package/dist/esm/sip-message/outbound/request.js +56 -0
  79. package/dist/esm/sip-message/outbound/request.js.map +1 -0
  80. package/dist/esm/sip-message/outbound/response.d.ts +6 -0
  81. package/dist/esm/sip-message/outbound/response.js +48 -0
  82. package/dist/esm/sip-message/outbound/response.js.map +1 -0
  83. package/dist/esm/sip-message/response-codes.d.ts +4 -0
  84. package/dist/esm/sip-message/response-codes.js +82 -0
  85. package/dist/esm/sip-message/response-codes.js.map +1 -0
  86. package/dist/esm/sip-message/sip-message.d.ts +10 -0
  87. package/dist/esm/sip-message/sip-message.js +38 -0
  88. package/dist/esm/sip-message/sip-message.js.map +1 -0
  89. package/dist/esm/types.d.ts +8 -0
  90. package/dist/esm/types.js +2 -0
  91. package/dist/esm/types.js.map +1 -0
  92. package/dist/esm/utils.d.ts +8 -0
  93. package/dist/esm/utils.js +31 -0
  94. package/dist/esm/utils.js.map +1 -0
  95. package/package.json +26 -13
  96. package/.ackrc +0 -3
  97. package/.prettierignore +0 -1
  98. package/.vscode/settings.json +0 -32
  99. package/demos/inbound-call.ts +0 -77
  100. package/demos/outbound-call.ts +0 -79
  101. package/dist/demos/inbound-call.d.ts +0 -1
  102. package/dist/demos/inbound-call.js +0 -78
  103. package/dist/demos/inbound-call.js.map +0 -1
  104. package/dist/demos/outbound-call.d.ts +0 -1
  105. package/dist/demos/outbound-call.js +0 -81
  106. package/dist/demos/outbound-call.js.map +0 -1
  107. package/dist/src/call-session/inbound.js +0 -60
  108. package/dist/src/call-session/inbound.js.map +0 -1
  109. package/dist/src/call-session/index.js +0 -200
  110. package/dist/src/call-session/index.js.map +0 -1
  111. package/dist/src/call-session/outbound.js +0 -70
  112. package/dist/src/call-session/outbound.js.map +0 -1
  113. package/dist/src/call-session/streamer.js +0 -88
  114. package/dist/src/call-session/streamer.js.map +0 -1
  115. package/dist/src/codec.d.ts +0 -5
  116. package/dist/src/codec.js +0 -14
  117. package/dist/src/codec.js.map +0 -1
  118. package/dist/src/dtmf.js +0 -40
  119. package/dist/src/dtmf.js.map +0 -1
  120. package/dist/src/sip-message/inbound/index.js +0 -23
  121. package/dist/src/sip-message/inbound/index.js.map +0 -1
  122. package/dist/src/sip-message/index.d.ts +0 -5
  123. package/dist/src/sip-message/index.js.map +0 -1
  124. package/dist/src/sip-message/outbound/index.js +0 -15
  125. package/dist/src/sip-message/outbound/index.js.map +0 -1
  126. package/dist/src/sip-message/outbound/request.js +0 -29
  127. package/dist/src/sip-message/outbound/request.js.map +0 -1
  128. package/dist/src/sip-message/outbound/response.js +0 -21
  129. package/dist/src/sip-message/outbound/response.js.map +0 -1
  130. package/dist/src/sip-message/response-codes.js +0 -84
  131. package/dist/src/sip-message/sip-message.js +0 -26
  132. package/dist/src/sip-message/sip-message.js.map +0 -1
  133. package/dist/src/softphone.d.ts +0 -25
  134. package/dist/src/softphone.js +0 -208
  135. package/dist/src/softphone.js.map +0 -1
  136. package/dist/src/utils.js +0 -41
  137. package/dist/src/utils.js.map +0 -1
  138. package/eslint.config.mjs +0 -5
  139. package/prettier.config.mjs +0 -3
  140. package/src/call-session/inbound.ts +0 -55
  141. package/src/call-session/index.ts +0 -222
  142. package/src/call-session/outbound.ts +0 -65
  143. package/src/call-session/streamer.ts +0 -87
  144. package/src/codec.ts +0 -18
  145. package/src/dtmf.ts +0 -40
  146. package/src/sip-message/inbound/index.ts +0 -21
  147. package/src/sip-message/index.ts +0 -5
  148. package/src/sip-message/outbound/index.ts +0 -11
  149. package/src/sip-message/outbound/request.ts +0 -35
  150. package/src/sip-message/outbound/response.ts +0 -23
  151. package/src/sip-message/response-codes.ts +0 -84
  152. package/src/sip-message/sip-message.ts +0 -31
  153. package/src/softphone.ts +0 -237
  154. package/src/utils.ts +0 -52
  155. package/tsconfig.json +0 -10
  156. /package/dist/{src → cjs}/dtmf.d.ts +0 -0
  157. /package/dist/{src → cjs}/sip-message/response-codes.d.ts +0 -0
  158. /package/dist/{src → cjs}/sip-message/sip-message.d.ts +0 -0
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # RingCentral Softphone SDK for TypeScript
2
2
 
3
- This is a TypeScript SDK for RingCentral Softphone. It is a complete rewrite of the [RingCentral Softphone SDK for JavaScript](https://github.com/ringcentral/ringcentral-softphone-js)
3
+ This is a TypeScript SDK for RingCentral Softphone. It is a complete rewrite of
4
+ the
5
+ [RingCentral Softphone SDK for JavaScript](https://github.com/ringcentral/ringcentral-softphone-js)
4
6
 
5
7
  Users are recommended to use this SDK instead of the JavaScript SDK.
6
8
 
@@ -21,18 +23,23 @@ yarn install ringcentral-softphone
21
23
  5. if there is none, you need to create one. Check steps below for more details
22
24
  6. Click the "Set Up and Provision" button
23
25
  7. Click the link "Set up manually using SIP"
24
- 8. You will find "SIP Domain", "Outbound Proxy", "User Name", "Password" and "Authorization ID"
26
+ 8. You will find "SIP Domain", "Outbound Proxy", "User Name", "Password" and
27
+ "Authorization ID"
25
28
 
26
- Please note that, "SIP Domain" name should come without port number. I don't know why it shows a port number on the page.
27
- This SDK requires a "domain" which is "SIP Domain" but without the port number.
29
+ Please note that, "SIP Domain" name should come without port number. I don't
30
+ know why it shows a port number on the page. This SDK requires a "domain" which
31
+ is "SIP Domain" but without the port number.
28
32
 
29
33
  ### Programmatically
30
34
 
31
- Invoke this RESTful API: https://developers.ringcentral.com/api-reference/Devices/readDeviceSipInfo
35
+ Invoke this RESTful API:
36
+ https://developers.ringcentral.com/api-reference/Devices/readDeviceSipInfo
32
37
 
33
- Please note that, in order to invoke this API, you need to be familiar with RingCentral RESTful programmming.
38
+ Please note that, in order to invoke this API, you need to be familiar with
39
+ RingCentral RESTful programmming.
34
40
 
35
- Here is a demo: https://github.com/tylerlong/rc-get-device-info-demo/blob/main/src/demo.ts
41
+ Here is a demo:
42
+ https://github.com/tylerlong/rc-get-device-info-demo/blob/main/src/demo.ts
36
43
 
37
44
  The credentials data returned by that API is like this:
38
45
 
@@ -92,14 +99,14 @@ The credentials data returned by that API is like this:
92
99
  }
93
100
  ```
94
101
 
95
- You will need to choose a outboundProxy value based on your location.
96
- And please choose the `proxyTLS` value because this SDK uses TLS.
97
- For example if you live in north America, choose `sip10.ringcentral.com:5096`.
102
+ You will need to choose a outboundProxy value based on your location. And please
103
+ choose the `proxyTLS` value because this SDK uses TLS. For example if you live
104
+ in north America, choose `sip10.ringcentral.com:5096`.
98
105
 
99
106
  ## Usage
100
107
 
101
108
  ```ts
102
- import Softphone from 'ringcentral-softphone';
109
+ import Softphone from "ringcentral-softphone";
103
110
 
104
111
  const softphone = new Softphone({
105
112
  domain: process.env.SIP_INFO_DOMAIN,
@@ -125,16 +132,34 @@ For complete examples, see [demos/](demos/)
125
132
  - stream local audio to remote peer
126
133
  - call transfer
127
134
 
128
- ## Notes
135
+ ### Audio codec
129
136
 
130
- ### Audio formats
137
+ ### By default it is `OPUS/16000`
131
138
 
132
- The codec used between server and client is "OPUS/16000".
133
- This SDK will auto decode/encode the codec to/from "uncompressed PCM".
139
+ ### Other codecs
134
140
 
135
- Bit rate is 16, which means 16 bits per sample.
136
- Sample rate is 16000, which means 16000 samples per second.
137
- Encoding is "signed-integer".
141
+ There are two more codecs supported: `OPUS/48000/2` and `PCMU/8000`.
142
+
143
+ To use them, you will need to explicitly set them when creating the softphone
144
+ instance:
145
+
146
+ ```ts
147
+ import Softphone from "ringcentral-softphone";
148
+
149
+ const softphone = new Softphone({
150
+ // ...
151
+ codec: "PCMU/8000", // or "OPUS/48000/2" or "OPUS/16000"
152
+ // ...
153
+ });
154
+ ```
155
+
156
+ ### OPUS/16000
157
+
158
+ The codec used between server and client is "OPUS/16000". This SDK will auto
159
+ decode/encode the codec to/from "uncompressed PCM".
160
+
161
+ Bit rate is 16, which means 16 bits per sample. Sample rate is 16000, which
162
+ means 16000 samples per second. Encoding is "signed-integer".
138
163
 
139
164
  You may play saved audio by the following command:
140
165
 
@@ -142,7 +167,8 @@ You may play saved audio by the following command:
142
167
  play -t raw -b 16 -r 16000 -e signed-integer test.wav
143
168
  ```
144
169
 
145
- To stream an audio file to remote peer, you need to make sure that the audio file is playable by the command above.
170
+ To stream an audio file to remote peer, you need to make sure that the audio
171
+ file is playable by the command above.
146
172
 
147
173
  #### ffmpeg
148
174
 
@@ -160,36 +186,75 @@ On macOS:
160
186
  say "Hello world" -o test.wav --data-format=LEI16@16000
161
187
  ```
162
188
 
163
- For Linux and Windows, please do some investigation yourself. Audio file generation is out of scope of this SDK.
189
+ For Linux and Windows, please do some investigation yourself. Audio file
190
+ generation is out of scope of this SDK.
164
191
 
165
- ### Multiple instances with same credentials
192
+ ### PCMU/8000
166
193
 
167
- You can run multiple softphone instances with the same credentials without encountering any errors. However, only the most recent instance will receive inbound calls.
194
+ If you choose this codec, make sure audio is playable using the following
195
+ commands:
196
+
197
+ ```
198
+ play -b 8 -r 8000 -e mu-law test.raw
199
+ ```
168
200
 
169
- In the future, we may consider supporting multiple active instances using the same credentials. For now, we believe there is no demand for this functionality.
201
+ Please note that, if I name the file as *.wav, `play` will complain:
170
202
 
171
- ### Invalid callee number
203
+ ```
204
+ play FAIL formats: can't open input file `6fdbbf2f-74fe-437a-b5a7-80c0c546baf0.wav': WAVE: RIFF header not found
205
+ ```
172
206
 
173
- If you call an invalid number. The sip server will return "SIP/2.0 486 Busy Here".
207
+ Either you rename it to *.raw or use `ffplay` instead
208
+
209
+ ```
210
+ ffplay -autoexit -f mulaw -ar 8000 test.wav
211
+ ```
212
+
213
+ ### OPUS/48000/2
214
+
215
+ If you choose this codec, make sure audio is playable using the following
216
+ commands:
217
+
218
+ ```
219
+ play -t raw -b 16 -r 48000 -e signed-integer -c 2 test.wav
220
+ ```
221
+
222
+ I don't know how to use `ffplay` to play such an audio file. Please create a PR
223
+ if you know, thanks.
224
+
225
+ ## Multiple instances with same credentials
226
+
227
+ You can run multiple softphone instances with the same credentials without
228
+ encountering any errors. However, only the most recent instance will receive
229
+ inbound calls.
230
+
231
+ In the future, we may consider supporting multiple active instances using the
232
+ same credentials. For now, we believe there is no demand for this functionality.
233
+
234
+ ## Invalid callee number
235
+
236
+ If you call an invalid number. The sip server will return "SIP/2.0 486 Busy
237
+ Here".
174
238
 
175
239
  This SDK will emit a "busy" event for the call session and dispose it.
176
240
 
177
241
  You can detect such an event by:
178
242
 
179
243
  ```ts
180
- callSession.once('busy', () => {
181
- console.log('cannot reach the callee number');
244
+ callSession.once("busy", () => {
245
+ console.log("cannot reach the callee number");
182
246
  });
183
247
  ```
184
248
 
185
249
  ## Pipe a call session to another
186
250
 
187
- When you get audio from a call session, you may forward it to another call session:
251
+ When you get audio from a call session, you may forward it to another call
252
+ session:
188
253
 
189
254
  ```ts
190
- callSession1.on('rtpPacket', (rtpPacket: RtpPacket) => {
191
- if (rtpPacket.header.payloadType === 109) {
192
- // 109 is for opus audio packet
255
+ callSession1.on("rtpPacket", (rtpPacket: RtpPacket) => {
256
+ // if statement is to make sure that it is an audio packet
257
+ if (rtpPacket.header.payloadType === softphone.codec.id) {
193
258
  callSession2.sendPacket(rtpPacket);
194
259
  }
195
260
  });
@@ -203,8 +268,16 @@ callSession1.on('rtpPacket', (rtpPacket: RtpPacket) => {
203
268
 
204
269
  ## Dev Notes
205
270
 
206
- Content below is for the maintainer of this SDK.
271
+ Content below is for the maintainer/contributor of this SDK.
207
272
 
208
- - We don't need to explicitly tell remote server our local UDP port (for audio streaming) via SIP SDP message. We send a RTP message to the remote server first, so the remote server knows our IP and port. So, the port number in SDP message could be fake.
273
+ - We don't need to explicitly tell remote server our local UDP port (for audio
274
+ streaming) via SIP SDP message. We send a RTP message to the remote server
275
+ first, so the remote server knows our IP and port. So, the port number in SDP
276
+ message could be fake.
209
277
  - Ref: https://www.ietf.org/rfc/rfc3261.txt
210
- - Caller Id feature is not supported. `P-Asserted-Identity` doesn't work. I think it is by design, since hardphone cannot support it.
278
+ - Caller Id feature is not supported. `P-Asserted-Identity` doesn't work. I
279
+ think it is by design, since hardphone cannot support it.
280
+
281
+ #### Code style
282
+
283
+ We use `deno fmt` to format all code.
@@ -1,6 +1,6 @@
1
- import CallSession from '.';
2
- import { type InboundMessage } from '../sip-message';
3
- import type Softphone from '../softphone';
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>;
@@ -0,0 +1,96 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ var index_js_1 = __importDefault(require("./index.js"));
58
+ var index_js_2 = require("../sip-message/index.js");
59
+ var utils_js_1 = require("../utils.js");
60
+ var InboundCallSession = /** @class */ (function (_super) {
61
+ __extends(InboundCallSession, _super);
62
+ function InboundCallSession(softphone, inviteMessage) {
63
+ var _this = _super.call(this, softphone, inviteMessage) || this;
64
+ _this.localPeer = inviteMessage.headers.To;
65
+ _this.remotePeer = inviteMessage.headers.From;
66
+ _this.remoteKey = inviteMessage.body.match(/AES_CM_128_HMAC_SHA1_80 inline:([\w+/]+)/)[1];
67
+ return _this;
68
+ }
69
+ InboundCallSession.prototype.answer = function () {
70
+ return __awaiter(this, void 0, void 0, function () {
71
+ var answerSDP, newMessage;
72
+ return __generator(this, function (_a) {
73
+ 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_js_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_js_1.localKey, "\n").trim();
74
+ newMessage = new index_js_2.OutboundMessage("SIP/2.0 200 OK", {
75
+ Via: this.sipMessage.headers.Via,
76
+ "Call-ID": this.sipMessage.headers["Call-ID"],
77
+ From: this.sipMessage.headers.From,
78
+ To: this.sipMessage.headers.To,
79
+ CSeq: this.sipMessage.headers.CSeq,
80
+ Contact: "<sip:".concat(this.softphone.sipInfo.username, "@").concat(this.softphone.client.localAddress, ":").concat(this.softphone.client.localPort, ";transport=TLS;ob>"),
81
+ Allow: "PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS",
82
+ Supported: "replaces, 100rel, timer, norefersub",
83
+ "Session-Expires": "14400;refresher=uac",
84
+ Require: "timer",
85
+ "Content-Type": "application/sdp",
86
+ }, answerSDP);
87
+ this.softphone.send(newMessage);
88
+ this.startLocalServices();
89
+ return [2 /*return*/];
90
+ });
91
+ });
92
+ };
93
+ return InboundCallSession;
94
+ }(index_js_1.default));
95
+ exports.default = InboundCallSession;
96
+ //# sourceMappingURL=inbound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../../src/call-session/inbound.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,wDAAqC;AACrC,oDAA+E;AAE/E,wCAAkD;AAElD;IAAiC,sCAAW;IAC1C,4BAAmB,SAAoB,EAAE,aAA6B;QACpE,YAAA,MAAK,YAAC,SAAS,EAAE,aAAa,CAAC,SAAC;QAChC,KAAI,CAAC,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,KAAI,CAAC,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7C,KAAI,CAAC,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CACvC,0CAA0C,CAC1C,CAAC,CAAC,CAAC,CAAC;;IACR,CAAC;IAEY,mCAAM,GAAnB;;;;gBACQ,SAAS,GAAG,qBAEhB,IAAI,CAAC,GAAG,EAAE,uBAAa,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,YAAY,2CAEpD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,YAAY,8BAEnC,IAAA,oBAAS,GAAE,uBAAa,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,4BAC9C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,cAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,yHAInB,mBAAQ,OACnD,CAAC,IAAI,EAAE,CAAC;gBACC,UAAU,GAAG,IAAI,0BAAe,CACpC,gBAAgB,EAChB;oBACE,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG;oBAChC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC;oBAC7C,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI;oBAClC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;oBAC9B,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI;oBAClC,OAAO,EACL,eAAQ,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,cAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,YAAY,cAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,uBAAoB;oBACtI,KAAK,EACH,2FAA2F;oBAC7F,SAAS,EAAE,qCAAqC;oBAChD,iBAAiB,EAAE,qBAAqB;oBACxC,OAAO,EAAE,OAAO;oBAChB,cAAc,EAAE,iBAAiB;iBAClC,EACD,SAAS,CACV,CAAC;gBACF,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAEhC,IAAI,CAAC,kBAAkB,EAAE,CAAC;;;;KAC3B;IACH,yBAAC;AAAD,CAAC,AA/CD,CAAiC,kBAAW,GA+C3C;AAED,kBAAe,kBAAkB,CAAC"}
@@ -1,9 +1,9 @@
1
- import dgram from 'dgram';
2
- import EventEmitter from 'events';
3
- import { RtpPacket, SrtpSession } from 'werift-rtp';
4
- import { type InboundMessage } from '../sip-message';
5
- import type Softphone from '../softphone';
6
- import Streamer from './streamer';
1
+ import dgram from "node:dgram";
2
+ import EventEmitter from "node:events";
3
+ import { RtpPacket, SrtpSession } from "werift-rtp";
4
+ import { type InboundMessage } from "../sip-message/index.js";
5
+ import type Softphone from "../index.js";
6
+ import Streamer from "./streamer.js";
7
7
  declare abstract class CallSession extends EventEmitter {
8
8
  softphone: Softphone;
9
9
  sipMessage: InboundMessage;
@@ -14,7 +14,12 @@ declare abstract class CallSession extends EventEmitter {
14
14
  remotePort: number;
15
15
  disposed: boolean;
16
16
  srtpSession: SrtpSession;
17
- opus: import("../codec").Opus;
17
+ encoder: {
18
+ encode: (pcm: Buffer) => Buffer;
19
+ };
20
+ decoder: {
21
+ decode: (audio: Buffer) => Buffer;
22
+ };
18
23
  ssrc: number;
19
24
  sequenceNumber: number;
20
25
  timestamp: number;
@@ -23,7 +28,7 @@ declare abstract class CallSession extends EventEmitter {
23
28
  get callId(): string;
24
29
  send(data: string | Buffer): void;
25
30
  hangup(): Promise<void>;
26
- sendDTMF(char: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '*' | '#'): Promise<void>;
31
+ sendDTMF(char: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "*" | "#"): Promise<void>;
27
32
  streamAudio(input: Buffer): Streamer;
28
33
  sendPacket(rtpPacket: RtpPacket): void;
29
34
  protected startLocalServices(): Promise<void>;
@@ -0,0 +1,268 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ var node_dgram_1 = __importDefault(require("node:dgram"));
58
+ var node_events_1 = __importDefault(require("node:events"));
59
+ var werift_rtp_1 = require("werift-rtp");
60
+ var dtmf_js_1 = __importDefault(require("../dtmf.js"));
61
+ var index_js_1 = require("../sip-message/index.js");
62
+ var utils_js_1 = require("../utils.js");
63
+ var streamer_js_1 = __importDefault(require("./streamer.js"));
64
+ var CallSession = /** @class */ (function (_super) {
65
+ __extends(CallSession, _super);
66
+ function CallSession(softphone, sipMessage) {
67
+ var _this = _super.call(this) || this;
68
+ _this.disposed = false;
69
+ // for audio streaming
70
+ _this.ssrc = (0, utils_js_1.randomInt)();
71
+ _this.sequenceNumber = (0, utils_js_1.randomInt)();
72
+ _this.timestamp = (0, utils_js_1.randomInt)();
73
+ _this.softphone = softphone;
74
+ _this.encoder = softphone.codec.createEncoder();
75
+ _this.decoder = softphone.codec.createDecoder();
76
+ _this.sipMessage = sipMessage;
77
+ _this.remoteIP = _this.sipMessage.body.match(/c=IN IP4 ([\d.]+)/)[1];
78
+ _this.remotePort = parseInt(_this.sipMessage.body.match(/m=audio (\d+) /)[1], 10);
79
+ return _this;
80
+ }
81
+ Object.defineProperty(CallSession.prototype, "remoteKey", {
82
+ set: function (key) {
83
+ var localKeyBuffer = Buffer.from(utils_js_1.localKey, "base64");
84
+ var remoteKeyBuffer = Buffer.from(key, "base64");
85
+ this.srtpSession = new werift_rtp_1.SrtpSession({
86
+ profile: 0x0001,
87
+ keys: {
88
+ localMasterKey: localKeyBuffer.subarray(0, 16),
89
+ localMasterSalt: localKeyBuffer.subarray(16, 30),
90
+ remoteMasterKey: remoteKeyBuffer.subarray(0, 16),
91
+ remoteMasterSalt: remoteKeyBuffer.subarray(16, 30),
92
+ },
93
+ });
94
+ },
95
+ enumerable: false,
96
+ configurable: true
97
+ });
98
+ Object.defineProperty(CallSession.prototype, "callId", {
99
+ get: function () {
100
+ return this.sipMessage.headers["Call-ID"];
101
+ },
102
+ enumerable: false,
103
+ configurable: true
104
+ });
105
+ CallSession.prototype.send = function (data) {
106
+ this.socket.send(data, this.remotePort, this.remoteIP);
107
+ };
108
+ CallSession.prototype.hangup = function () {
109
+ return __awaiter(this, void 0, void 0, function () {
110
+ var requestMessage;
111
+ return __generator(this, function (_a) {
112
+ requestMessage = new index_js_1.RequestMessage("BYE sip:".concat(this.softphone.sipInfo.domain, " SIP/2.0"), {
113
+ "Call-ID": this.callId,
114
+ From: this.localPeer,
115
+ To: this.remotePeer,
116
+ Via: "SIP/2.0/TLS ".concat(this.softphone.fakeDomain, ";branch=").concat((0, utils_js_1.branch)()),
117
+ });
118
+ this.softphone.send(requestMessage);
119
+ return [2 /*return*/];
120
+ });
121
+ });
122
+ };
123
+ CallSession.prototype.sendDTMF = function (char) {
124
+ return __awaiter(this, void 0, void 0, function () {
125
+ var timestamp, sequenceNumber, rtpHeader, _i, _a, payload, rtpPacket;
126
+ return __generator(this, function (_b) {
127
+ timestamp = Math.floor(Date.now() / 1000);
128
+ sequenceNumber = timestamp % 65536;
129
+ rtpHeader = new werift_rtp_1.RtpHeader({
130
+ version: 2,
131
+ padding: false,
132
+ paddingSize: 0,
133
+ extension: false,
134
+ marker: false,
135
+ payloadOffset: 12,
136
+ payloadType: 101,
137
+ sequenceNumber: sequenceNumber,
138
+ timestamp: timestamp,
139
+ ssrc: (0, utils_js_1.randomInt)(),
140
+ csrcLength: 0,
141
+ csrc: [],
142
+ extensionProfile: 48862,
143
+ extensionLength: undefined,
144
+ extensions: [],
145
+ });
146
+ for (_i = 0, _a = dtmf_js_1.default.charToPayloads(char); _i < _a.length; _i++) {
147
+ payload = _a[_i];
148
+ rtpHeader.sequenceNumber = sequenceNumber++;
149
+ rtpPacket = new werift_rtp_1.RtpPacket(rtpHeader, payload);
150
+ this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
151
+ }
152
+ return [2 /*return*/];
153
+ });
154
+ });
155
+ };
156
+ // buffer is the content of a audio file, it is supposed to be uncompressed PCM data
157
+ // The audio should be playable by command: play -t raw -b 16 -r 16000 -e signed-integer test.wav
158
+ CallSession.prototype.streamAudio = function (input) {
159
+ var streamer = new streamer_js_1.default(this, input);
160
+ streamer.start();
161
+ return streamer;
162
+ };
163
+ // send a single rtp packet
164
+ CallSession.prototype.sendPacket = function (rtpPacket) {
165
+ if (this.disposed) {
166
+ return;
167
+ }
168
+ this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));
169
+ };
170
+ CallSession.prototype.startLocalServices = function () {
171
+ return __awaiter(this, void 0, void 0, function () {
172
+ var byeHandler;
173
+ var _this = this;
174
+ return __generator(this, function (_a) {
175
+ this.socket = node_dgram_1.default.createSocket("udp4");
176
+ this.socket.on("message", function (message) {
177
+ var rtpPacket = werift_rtp_1.RtpPacket.deSerialize(_this.srtpSession.decrypt(message));
178
+ _this.emit("rtpPacket", rtpPacket);
179
+ if (rtpPacket.header.payloadType === 101) {
180
+ _this.emit("dtmfPacket", rtpPacket);
181
+ var char = dtmf_js_1.default.payloadToChar(rtpPacket.payload);
182
+ if (char) {
183
+ _this.emit("dtmf", char);
184
+ }
185
+ }
186
+ else if (rtpPacket.header.payloadType === _this.softphone.codec.id) {
187
+ if (rtpPacket.payload.length === 4 &&
188
+ rtpPacket.payload[0] >= 0x00 &&
189
+ rtpPacket.payload[0] < 0x0c &&
190
+ rtpPacket.payload[1] === 0x8a &&
191
+ rtpPacket.payload[2] === 0x03 &&
192
+ rtpPacket.payload[3] === 0xc0) {
193
+ // special DTMF packet in audio format
194
+ // first byte 0x00 to 0x0c means DTMF 0 to 9, *, #
195
+ // we ignore it since DTMF is handled by `if (rtpPacket.header.payloadType === 101) {`
196
+ return; // ignore it
197
+ }
198
+ try {
199
+ rtpPacket.payload = _this.decoder.decode(rtpPacket.payload);
200
+ _this.emit("audioPacket", rtpPacket);
201
+ }
202
+ catch (_a) {
203
+ console.error("opus decode failed", rtpPacket);
204
+ }
205
+ }
206
+ });
207
+ // as I tested, we can use a random port here and it still works
208
+ // but it seems that in SDP we need to tell remote our local IP Address, not 127.0.0.1
209
+ this.socket.bind(); // random port
210
+ // send a message to remote server so that it knows where to reply
211
+ this.send("hello");
212
+ byeHandler = function (inboundMessage) {
213
+ if (inboundMessage.headers["Call-ID"] !== _this.callId) {
214
+ return;
215
+ }
216
+ if (inboundMessage.headers.CSeq.endsWith(" BYE")) {
217
+ _this.softphone.off("message", byeHandler);
218
+ _this.dispose();
219
+ }
220
+ };
221
+ this.softphone.on("message", byeHandler);
222
+ return [2 /*return*/];
223
+ });
224
+ });
225
+ };
226
+ CallSession.prototype.dispose = function () {
227
+ var _a, _b;
228
+ this.disposed = true;
229
+ this.emit("disposed");
230
+ this.removeAllListeners();
231
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.removeAllListeners();
232
+ (_b = this.socket) === null || _b === void 0 ? void 0 : _b.close();
233
+ };
234
+ CallSession.prototype.transfer = function (transferTo) {
235
+ var _this = this;
236
+ var requestMessage = new index_js_1.RequestMessage("REFER sip:".concat(this.softphone.sipInfo.username, "@").concat(this.softphone.sipInfo.outboundProxy, ";transport=tls SIP/2.0"), {
237
+ Via: "SIP/2.0/TLS ".concat(this.softphone.client.localAddress, ":").concat(this.softphone.client.localPort, ";rport;branch=").concat((0, utils_js_1.branch)(), ";alias"),
238
+ "Max-Forwards": 70,
239
+ From: this.localPeer,
240
+ To: this.remotePeer,
241
+ Contact: "<sip:".concat(this.softphone.sipInfo.username, "@").concat(this.softphone.client.localAddress, ":").concat(this.softphone.client.localPort, ";transport=TLS;ob>"),
242
+ "Call-ID": this.callId,
243
+ Event: "refer",
244
+ Expires: 600,
245
+ Supported: "replaces, 100rel, timer, norefersub",
246
+ Accept: "message/sipfrag;version=2.0",
247
+ "Allow-Events": "presence, message-summary, refer",
248
+ "Refer-To": "sip:".concat(transferTo, "@").concat(this.softphone.sipInfo.domain),
249
+ "Referred-By": "<sip:".concat(this.softphone.sipInfo.username, "@").concat(this.softphone.sipInfo.domain, ">"),
250
+ });
251
+ this.softphone.send(requestMessage);
252
+ // reply to those NOTIFY messages
253
+ var notifyHandler = function (inboundMessage) {
254
+ if (!inboundMessage.subject.startsWith("NOTIFY ")) {
255
+ return;
256
+ }
257
+ var responseMessage = new index_js_1.ResponseMessage(inboundMessage, 200);
258
+ _this.softphone.send(responseMessage);
259
+ if (inboundMessage.body.trim() === "SIP/2.0 200 OK") {
260
+ _this.softphone.off("message", notifyHandler);
261
+ }
262
+ };
263
+ this.softphone.on("message", notifyHandler);
264
+ };
265
+ return CallSession;
266
+ }(node_events_1.default));
267
+ exports.default = CallSession;
268
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/call-session/index.ts"],"names":[],"mappings":"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"}