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.
- package/README.md +107 -34
- package/dist/{src → cjs}/call-session/inbound.d.ts +3 -3
- package/dist/cjs/call-session/inbound.js +96 -0
- package/dist/cjs/call-session/inbound.js.map +1 -0
- package/dist/{src → cjs}/call-session/index.d.ts +13 -8
- package/dist/cjs/call-session/index.js +268 -0
- package/dist/cjs/call-session/index.js.map +1 -0
- package/dist/{src → cjs}/call-session/outbound.d.ts +3 -3
- package/dist/cjs/call-session/outbound.js +125 -0
- package/dist/cjs/call-session/outbound.js.map +1 -0
- package/dist/{src → cjs}/call-session/streamer.d.ts +2 -2
- package/dist/cjs/call-session/streamer.js +151 -0
- package/dist/cjs/call-session/streamer.js.map +1 -0
- package/dist/cjs/codec.d.ts +14 -0
- package/dist/cjs/codec.js +60 -0
- package/dist/cjs/codec.js.map +1 -0
- package/dist/cjs/dtmf.js +48 -0
- package/dist/cjs/dtmf.js.map +1 -0
- package/dist/cjs/index.d.ts +28 -0
- package/dist/cjs/index.js +299 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/{src → cjs}/sip-message/inbound/index.d.ts +1 -1
- package/dist/cjs/sip-message/inbound/index.js +43 -0
- package/dist/cjs/sip-message/inbound/index.js.map +1 -0
- package/dist/cjs/sip-message/index.d.ts +5 -0
- package/dist/{src → cjs}/sip-message/index.js +10 -10
- package/dist/cjs/sip-message/index.js.map +1 -0
- package/dist/{src → cjs}/sip-message/outbound/index.d.ts +1 -1
- package/dist/cjs/sip-message/outbound/index.js +36 -0
- package/dist/cjs/sip-message/outbound/index.js.map +1 -0
- package/dist/{src → cjs}/sip-message/outbound/request.d.ts +1 -1
- package/dist/cjs/sip-message/outbound/request.js +61 -0
- package/dist/cjs/sip-message/outbound/request.js.map +1 -0
- package/dist/{src → cjs}/sip-message/outbound/response.d.ts +2 -2
- package/dist/cjs/sip-message/outbound/response.js +53 -0
- package/dist/cjs/sip-message/outbound/response.js.map +1 -0
- package/dist/cjs/sip-message/response-codes.js +84 -0
- package/dist/{src → cjs}/sip-message/response-codes.js.map +1 -1
- package/dist/cjs/sip-message/sip-message.js +40 -0
- package/dist/cjs/sip-message/sip-message.js.map +1 -0
- package/dist/cjs/types.d.ts +8 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/{src → cjs}/utils.d.ts +2 -2
- package/dist/cjs/utils.js +43 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/call-session/inbound.d.ts +8 -0
- package/dist/esm/call-session/inbound.js +91 -0
- package/dist/esm/call-session/inbound.js.map +1 -0
- package/dist/esm/call-session/index.d.ts +38 -0
- package/dist/esm/call-session/index.js +263 -0
- package/dist/esm/call-session/index.js.map +1 -0
- package/dist/esm/call-session/outbound.d.ts +9 -0
- package/dist/esm/call-session/outbound.js +120 -0
- package/dist/esm/call-session/outbound.js.map +1 -0
- package/dist/esm/call-session/streamer.d.ts +16 -0
- package/dist/esm/call-session/streamer.js +146 -0
- package/dist/esm/call-session/streamer.js.map +1 -0
- package/dist/esm/codec.d.ts +14 -0
- package/dist/esm/codec.js +58 -0
- package/dist/esm/codec.js.map +1 -0
- package/dist/esm/dtmf.d.ts +7 -0
- package/dist/esm/dtmf.js +46 -0
- package/dist/esm/dtmf.js.map +1 -0
- package/dist/esm/index.d.ts +28 -0
- package/dist/esm/index.js +294 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/sip-message/inbound/index.d.ts +5 -0
- package/dist/esm/sip-message/inbound/index.js +38 -0
- package/dist/esm/sip-message/inbound/index.js.map +1 -0
- package/dist/esm/sip-message/index.d.ts +5 -0
- package/dist/esm/sip-message/index.js +6 -0
- package/dist/esm/sip-message/index.js.map +1 -0
- package/dist/esm/sip-message/outbound/index.d.ts +5 -0
- package/dist/esm/sip-message/outbound/index.js +31 -0
- package/dist/esm/sip-message/outbound/index.js.map +1 -0
- package/dist/esm/sip-message/outbound/request.d.ts +7 -0
- package/dist/esm/sip-message/outbound/request.js +56 -0
- package/dist/esm/sip-message/outbound/request.js.map +1 -0
- package/dist/esm/sip-message/outbound/response.d.ts +6 -0
- package/dist/esm/sip-message/outbound/response.js +48 -0
- package/dist/esm/sip-message/outbound/response.js.map +1 -0
- package/dist/esm/sip-message/response-codes.d.ts +4 -0
- package/dist/esm/sip-message/response-codes.js +82 -0
- package/dist/esm/sip-message/response-codes.js.map +1 -0
- package/dist/esm/sip-message/sip-message.d.ts +10 -0
- package/dist/esm/sip-message/sip-message.js +38 -0
- package/dist/esm/sip-message/sip-message.js.map +1 -0
- package/dist/esm/types.d.ts +8 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils.d.ts +8 -0
- package/dist/esm/utils.js +31 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +26 -13
- package/.ackrc +0 -3
- package/.prettierignore +0 -1
- package/.vscode/settings.json +0 -32
- package/demos/inbound-call.ts +0 -77
- package/demos/outbound-call.ts +0 -79
- package/dist/demos/inbound-call.d.ts +0 -1
- package/dist/demos/inbound-call.js +0 -78
- package/dist/demos/inbound-call.js.map +0 -1
- package/dist/demos/outbound-call.d.ts +0 -1
- package/dist/demos/outbound-call.js +0 -81
- package/dist/demos/outbound-call.js.map +0 -1
- package/dist/src/call-session/inbound.js +0 -60
- package/dist/src/call-session/inbound.js.map +0 -1
- package/dist/src/call-session/index.js +0 -200
- package/dist/src/call-session/index.js.map +0 -1
- package/dist/src/call-session/outbound.js +0 -70
- package/dist/src/call-session/outbound.js.map +0 -1
- package/dist/src/call-session/streamer.js +0 -88
- package/dist/src/call-session/streamer.js.map +0 -1
- package/dist/src/codec.d.ts +0 -5
- package/dist/src/codec.js +0 -14
- package/dist/src/codec.js.map +0 -1
- package/dist/src/dtmf.js +0 -40
- package/dist/src/dtmf.js.map +0 -1
- package/dist/src/sip-message/inbound/index.js +0 -23
- package/dist/src/sip-message/inbound/index.js.map +0 -1
- package/dist/src/sip-message/index.d.ts +0 -5
- package/dist/src/sip-message/index.js.map +0 -1
- package/dist/src/sip-message/outbound/index.js +0 -15
- package/dist/src/sip-message/outbound/index.js.map +0 -1
- package/dist/src/sip-message/outbound/request.js +0 -29
- package/dist/src/sip-message/outbound/request.js.map +0 -1
- package/dist/src/sip-message/outbound/response.js +0 -21
- package/dist/src/sip-message/outbound/response.js.map +0 -1
- package/dist/src/sip-message/response-codes.js +0 -84
- package/dist/src/sip-message/sip-message.js +0 -26
- package/dist/src/sip-message/sip-message.js.map +0 -1
- package/dist/src/softphone.d.ts +0 -25
- package/dist/src/softphone.js +0 -208
- package/dist/src/softphone.js.map +0 -1
- package/dist/src/utils.js +0 -41
- package/dist/src/utils.js.map +0 -1
- package/eslint.config.mjs +0 -5
- package/prettier.config.mjs +0 -3
- package/src/call-session/inbound.ts +0 -55
- package/src/call-session/index.ts +0 -222
- package/src/call-session/outbound.ts +0 -65
- package/src/call-session/streamer.ts +0 -87
- package/src/codec.ts +0 -18
- package/src/dtmf.ts +0 -40
- package/src/sip-message/inbound/index.ts +0 -21
- package/src/sip-message/index.ts +0 -5
- package/src/sip-message/outbound/index.ts +0 -11
- package/src/sip-message/outbound/request.ts +0 -35
- package/src/sip-message/outbound/response.ts +0 -23
- package/src/sip-message/response-codes.ts +0 -84
- package/src/sip-message/sip-message.ts +0 -31
- package/src/softphone.ts +0 -237
- package/src/utils.ts +0 -52
- package/tsconfig.json +0 -10
- /package/dist/{src → cjs}/dtmf.d.ts +0 -0
- /package/dist/{src → cjs}/sip-message/response-codes.d.ts +0 -0
- /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
|
|
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
|
|
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
|
|
27
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
|
|
97
|
-
|
|
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
|
|
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
|
-
|
|
135
|
+
### Audio codec
|
|
129
136
|
|
|
130
|
-
###
|
|
137
|
+
### By default it is `OPUS/16000`
|
|
131
138
|
|
|
132
|
-
|
|
133
|
-
This SDK will auto decode/encode the codec to/from "uncompressed PCM".
|
|
139
|
+
### Other codecs
|
|
134
140
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
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
|
|
189
|
+
For Linux and Windows, please do some investigation yourself. Audio file
|
|
190
|
+
generation is out of scope of this SDK.
|
|
164
191
|
|
|
165
|
-
###
|
|
192
|
+
### PCMU/8000
|
|
166
193
|
|
|
167
|
-
|
|
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
|
-
|
|
201
|
+
Please note that, if I name the file as *.wav, `play` will complain:
|
|
170
202
|
|
|
171
|
-
|
|
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
|
-
|
|
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(
|
|
181
|
-
console.log(
|
|
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
|
|
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(
|
|
191
|
-
if
|
|
192
|
-
|
|
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
|
|
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
|
|
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
|
|
3
|
-
import type Softphone from
|
|
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
|
|
2
|
-
import EventEmitter from
|
|
3
|
-
import { RtpPacket, SrtpSession } from
|
|
4
|
-
import { type InboundMessage } from
|
|
5
|
-
import type Softphone from
|
|
6
|
-
import Streamer from
|
|
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
|
-
|
|
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:
|
|
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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"}
|