@babblevoice/babble-drachtio-callmanager 2.3.8 → 2.3.10
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/jsconfig.json +10 -0
- package/lib/call.js +266 -198
- package/lib/callmanager.js +9 -5
- package/lib/sdp.js +2 -2
- package/lib/store.js +22 -22
- package/package.json +9 -4
- package/test/interface/call.js +8 -8
package/jsconfig.json
ADDED
package/lib/call.js
CHANGED
|
@@ -87,6 +87,20 @@ const hangupcodes = {
|
|
|
87
87
|
REJECTED: { "reason": "REJECTED", "sip": 608 }
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Ecapsulate a SIP exception
|
|
92
|
+
* @param { object } hangupcode
|
|
93
|
+
* @param { string } message
|
|
94
|
+
*/
|
|
95
|
+
class SipError extends Error {
|
|
96
|
+
constructor( hangupcode, message ) {
|
|
97
|
+
super( message )
|
|
98
|
+
this.code = hangupcode.sip
|
|
99
|
+
this.hangupcode = hangupcode
|
|
100
|
+
this.name = "SipError"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
90
104
|
/* Reverse codes - include inbound error codes.
|
|
91
105
|
If not in this list we return REQUEST_TERMINATED during creation */
|
|
92
106
|
const inboundsiperros = {
|
|
@@ -99,19 +113,27 @@ let callmanager = {
|
|
|
99
113
|
"options": {}
|
|
100
114
|
}
|
|
101
115
|
|
|
102
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* @typedef { object } entity
|
|
118
|
+
* @property { string } uri full uri
|
|
119
|
+
* @property { string } [ username ] username part
|
|
120
|
+
* @property { string } [ realm ] realm (domain) part
|
|
121
|
+
* @property { string } [ display ] how the user should be displayed
|
|
122
|
+
* @property { number } [ ccc ] - Current Call Count
|
|
123
|
+
*/
|
|
124
|
+
|
|
103
125
|
class call {
|
|
104
126
|
|
|
105
127
|
/**
|
|
106
|
-
Construct our call object with all defaults, including a default UUID.
|
|
107
|
-
@constructs call
|
|
108
|
-
@hideconstructor
|
|
128
|
+
* Construct our call object with all defaults, including a default UUID.
|
|
129
|
+
* @constructs call
|
|
130
|
+
* @hideconstructor
|
|
109
131
|
*/
|
|
110
132
|
constructor() {
|
|
111
133
|
this.uuid = uuidv4()
|
|
112
134
|
|
|
113
135
|
/**
|
|
114
|
-
@enum {string} type "uas" | "uac"
|
|
136
|
+
@enum { string } type "uas" | "uac"
|
|
115
137
|
@summary The type (uac or uas) from our perspective.
|
|
116
138
|
*/
|
|
117
139
|
this.type = "uac"
|
|
@@ -149,7 +171,7 @@ class call {
|
|
|
149
171
|
}
|
|
150
172
|
|
|
151
173
|
/**
|
|
152
|
-
*
|
|
174
|
+
* Protected for this module
|
|
153
175
|
*/
|
|
154
176
|
this._state = {
|
|
155
177
|
"_onhangup": false,
|
|
@@ -157,42 +179,41 @@ class call {
|
|
|
157
179
|
}
|
|
158
180
|
|
|
159
181
|
/**
|
|
160
|
-
@
|
|
161
|
-
@summary Channels which have been created
|
|
182
|
+
* @summary Channels which have been created
|
|
162
183
|
*/
|
|
163
184
|
this.channels = {
|
|
164
|
-
"audio":
|
|
185
|
+
"audio": undefined,
|
|
165
186
|
"closed": {
|
|
166
187
|
"audio": []
|
|
167
188
|
}
|
|
168
189
|
}
|
|
169
190
|
|
|
170
191
|
/**
|
|
171
|
-
@
|
|
172
|
-
@summary Store our local and remote sdp objects
|
|
192
|
+
* @summary Store our local and remote sdp objects
|
|
173
193
|
*/
|
|
174
194
|
this.sdp = {
|
|
175
|
-
"local":
|
|
176
|
-
"remote":
|
|
195
|
+
"local": undefined,
|
|
196
|
+
"remote": undefined
|
|
177
197
|
}
|
|
178
198
|
|
|
179
199
|
/**
|
|
180
|
-
@
|
|
181
|
-
@summary UACs we create
|
|
200
|
+
* @summary UACs we create
|
|
182
201
|
*/
|
|
183
202
|
this.children = new Set()
|
|
184
203
|
/**
|
|
185
|
-
@
|
|
186
|
-
@summary Who created us
|
|
204
|
+
* @summary Who created us
|
|
187
205
|
*/
|
|
188
|
-
this.parent =
|
|
206
|
+
this.parent = undefined
|
|
207
|
+
|
|
208
|
+
/** @summary Other channels which we might need - for things like opening a channel on the same node. */
|
|
209
|
+
this.relatives = new Set()
|
|
189
210
|
|
|
190
211
|
/**
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
212
|
+
* @typedef {Object} epochs
|
|
213
|
+
* @property {number} startat UNIX timestamp of when the call was started (created)
|
|
214
|
+
* @property {number} answerat UNIX timestamp of when the call was answered
|
|
215
|
+
* @property {number} endat UNIX timestamp of when the call ended
|
|
216
|
+
*/
|
|
196
217
|
|
|
197
218
|
/** @member {epochs} */
|
|
198
219
|
this.epochs = {
|
|
@@ -203,13 +224,15 @@ class call {
|
|
|
203
224
|
}
|
|
204
225
|
|
|
205
226
|
/**
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
227
|
+
* @typedef { object } sipdialog
|
|
228
|
+
* @property { string } callid
|
|
229
|
+
* @property { object } tags
|
|
230
|
+
* @property { string } tags.local
|
|
231
|
+
* @property { string } tags.remote
|
|
232
|
+
*/
|
|
233
|
+
/** @member { sipdialog } */
|
|
212
234
|
this.sip = {
|
|
235
|
+
"callid": undefined,
|
|
213
236
|
"tags": {
|
|
214
237
|
"remote": "",
|
|
215
238
|
"local": ""
|
|
@@ -217,32 +240,23 @@ class call {
|
|
|
217
240
|
}
|
|
218
241
|
|
|
219
242
|
/**
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
@
|
|
223
|
-
|
|
224
|
-
@property { string } [ display ] how the user should be displayed
|
|
225
|
-
*/
|
|
226
|
-
/**
|
|
227
|
-
For inbound calls - this is discovered by authentication. For outbound
|
|
228
|
-
this is requested by the caller - i.e. the destination is the registered user.
|
|
229
|
-
@member { _entity }
|
|
230
|
-
@private
|
|
243
|
+
* For inbound calls - this is discovered by authentication. For outbound
|
|
244
|
+
* this is requested by the caller - i.e. the destination is the registered user.
|
|
245
|
+
* @type { entity }
|
|
246
|
+
* Protected for this module.
|
|
231
247
|
*/
|
|
232
248
|
this._entity
|
|
233
249
|
|
|
234
250
|
/**
|
|
235
251
|
Override caller id or name.
|
|
236
|
-
@member { _remote }
|
|
237
252
|
@private
|
|
238
253
|
*/
|
|
239
254
|
this._remote = {
|
|
240
|
-
"id":
|
|
241
|
-
"name":
|
|
255
|
+
"id": undefined,
|
|
256
|
+
"name": undefined
|
|
242
257
|
}
|
|
243
258
|
|
|
244
259
|
/**
|
|
245
|
-
* @member { object }
|
|
246
260
|
* @summary contains network information regarding call
|
|
247
261
|
*/
|
|
248
262
|
this.network = {
|
|
@@ -254,8 +268,7 @@ class call {
|
|
|
254
268
|
}
|
|
255
269
|
|
|
256
270
|
/**
|
|
257
|
-
@
|
|
258
|
-
@summary user definable object that allows other modules to store data in this call.
|
|
271
|
+
* @summary user definable object that allows other modules to store data in this call.
|
|
259
272
|
*/
|
|
260
273
|
this.vars = {}
|
|
261
274
|
|
|
@@ -266,24 +279,23 @@ class call {
|
|
|
266
279
|
this._receivedtelevents = ""
|
|
267
280
|
|
|
268
281
|
/**
|
|
269
|
-
@
|
|
270
|
-
@private
|
|
282
|
+
* @private
|
|
271
283
|
*/
|
|
272
284
|
this._promises = {
|
|
273
285
|
"resolve": {
|
|
274
|
-
"auth":
|
|
275
|
-
"hangup":
|
|
276
|
-
"events":
|
|
277
|
-
"channelevent":
|
|
286
|
+
"auth": undefined,
|
|
287
|
+
"hangup": undefined,
|
|
288
|
+
"events": undefined,
|
|
289
|
+
"channelevent": undefined
|
|
278
290
|
},
|
|
279
291
|
"reject": {
|
|
280
|
-
"auth":
|
|
281
|
-
"channelevent":
|
|
292
|
+
"auth": undefined,
|
|
293
|
+
"channelevent": undefined
|
|
282
294
|
},
|
|
283
295
|
"promise": {
|
|
284
|
-
"hangup":
|
|
285
|
-
"events":
|
|
286
|
-
"channelevent":
|
|
296
|
+
"hangup": undefined,
|
|
297
|
+
"events": undefined,
|
|
298
|
+
"channelevent": undefined
|
|
287
299
|
}
|
|
288
300
|
}
|
|
289
301
|
|
|
@@ -292,52 +304,61 @@ class call {
|
|
|
292
304
|
} )
|
|
293
305
|
|
|
294
306
|
/**
|
|
295
|
-
@
|
|
296
|
-
@private
|
|
307
|
+
* @private
|
|
297
308
|
*/
|
|
298
309
|
this._timers = {
|
|
299
|
-
"auth":
|
|
300
|
-
"newuac":
|
|
301
|
-
"events":
|
|
302
|
-
"seinterval":
|
|
303
|
-
"anyevent":
|
|
310
|
+
"auth": undefined,
|
|
311
|
+
"newuac": undefined,
|
|
312
|
+
"events": undefined,
|
|
313
|
+
"seinterval": undefined,
|
|
314
|
+
"anyevent": undefined
|
|
304
315
|
}
|
|
305
316
|
|
|
306
317
|
/**
|
|
307
|
-
@
|
|
308
|
-
@private
|
|
318
|
+
* @private
|
|
309
319
|
*/
|
|
310
320
|
this._em = new events.EventEmitter()
|
|
311
321
|
|
|
312
|
-
|
|
322
|
+
/**
|
|
323
|
+
* @typedef { Object } options
|
|
324
|
+
* @property { string } [ contact ] contact string
|
|
325
|
+
* @property { string } [ preferedcodecs ] as it says
|
|
326
|
+
* @property { boolean } [ rfc2833 ] if set to true enable 2833
|
|
327
|
+
* @property { string } [ display ] how the user should be displayed
|
|
328
|
+
* @property { Array } [ headers ]
|
|
329
|
+
* @property { number } [ uactimeout ] timeout in mS
|
|
330
|
+
* @property { boolean } [ late ] - do we use late negotiation
|
|
331
|
+
* @property { boolean } [ noAck ] do not use - converts our options into Drachtio options
|
|
332
|
+
* @property { string } [ localSdp ] do not use - what we pass into drachtio
|
|
333
|
+
*/
|
|
334
|
+
/**
|
|
335
|
+
* copy default
|
|
336
|
+
* @type { options }
|
|
337
|
+
*/
|
|
313
338
|
this.options = { ...callmanager.options }
|
|
314
339
|
|
|
315
340
|
/**
|
|
316
|
-
@
|
|
317
|
-
@private
|
|
341
|
+
* @private
|
|
318
342
|
*/
|
|
319
343
|
this._auth = sipauth.create( callmanager.options.proxy )
|
|
320
344
|
|
|
321
345
|
this.referauthrequired = callmanager.options.referauthrequired
|
|
322
346
|
|
|
323
347
|
/**
|
|
324
|
-
Enable access for other modules.
|
|
348
|
+
* Enable access for other modules.
|
|
325
349
|
*/
|
|
326
350
|
this.hangupcodes = hangupcodes
|
|
327
|
-
}
|
|
328
351
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
@property { number } ccc - Current Call Count
|
|
336
|
-
*/
|
|
352
|
+
/**
|
|
353
|
+
* If the call is referred somewhere, this is the url we use
|
|
354
|
+
* @type { string }
|
|
355
|
+
*/
|
|
356
|
+
this.referingtouri
|
|
357
|
+
}
|
|
337
358
|
|
|
338
359
|
/**
|
|
339
|
-
Returns the entity if known (i.e. outbound or inbound authed).
|
|
340
|
-
@returns { Promise< entity > }
|
|
360
|
+
* Returns the entity if known (i.e. outbound or inbound authed).
|
|
361
|
+
* @returns { Promise< entity > }
|
|
341
362
|
*/
|
|
342
363
|
get entity() {
|
|
343
364
|
|
|
@@ -381,7 +402,6 @@ class call {
|
|
|
381
402
|
if( !e.uri && !( e.username && e.realm ) ) return
|
|
382
403
|
this._entity = e
|
|
383
404
|
|
|
384
|
-
this._entity.name = ""
|
|
385
405
|
this._entity.display = ""
|
|
386
406
|
|
|
387
407
|
if( this._entity.uri ) {
|
|
@@ -408,7 +428,7 @@ class call {
|
|
|
408
428
|
|
|
409
429
|
/**
|
|
410
430
|
* Sets caller id
|
|
411
|
-
* @param {
|
|
431
|
+
* @param { string } callerid
|
|
412
432
|
*/
|
|
413
433
|
set callerid( callerid ) {
|
|
414
434
|
this._remote.id = callerid
|
|
@@ -416,7 +436,7 @@ class call {
|
|
|
416
436
|
|
|
417
437
|
/**
|
|
418
438
|
* Sets caller id name
|
|
419
|
-
* @param {
|
|
439
|
+
* @param { string } calleridname
|
|
420
440
|
*/
|
|
421
441
|
set calleridname( calleridname ) {
|
|
422
442
|
this._remote.name = calleridname
|
|
@@ -578,7 +598,7 @@ class call {
|
|
|
578
598
|
|
|
579
599
|
/**
|
|
580
600
|
hasmedia
|
|
581
|
-
@return {
|
|
601
|
+
@return { boolean } - true if the call has media (i.e. is established on not held).
|
|
582
602
|
*/
|
|
583
603
|
get hasmedia() {
|
|
584
604
|
if( this.state.held ) return false
|
|
@@ -597,7 +617,7 @@ class call {
|
|
|
597
617
|
|
|
598
618
|
/**
|
|
599
619
|
trying
|
|
600
|
-
@return {
|
|
620
|
+
@return { boolean } - true if the call has been trying.
|
|
601
621
|
*/
|
|
602
622
|
get trying() {
|
|
603
623
|
return this.state.trying
|
|
@@ -605,7 +625,7 @@ class call {
|
|
|
605
625
|
|
|
606
626
|
/**
|
|
607
627
|
ringing
|
|
608
|
-
@return {
|
|
628
|
+
@return { boolean } - true if the call has been ringing.
|
|
609
629
|
*/
|
|
610
630
|
get ringing() {
|
|
611
631
|
return this.state.ringing
|
|
@@ -620,7 +640,7 @@ class call {
|
|
|
620
640
|
|
|
621
641
|
/**
|
|
622
642
|
established - if the call isn't already established then set the answerat time.
|
|
623
|
-
@param {
|
|
643
|
+
@param { boolean } s - true if the call has been established.
|
|
624
644
|
*/
|
|
625
645
|
set established( s ) {
|
|
626
646
|
if( this.state.established != s ) {
|
|
@@ -631,7 +651,7 @@ class call {
|
|
|
631
651
|
|
|
632
652
|
/**
|
|
633
653
|
established
|
|
634
|
-
@return {
|
|
654
|
+
@return { boolean } - true if the call has been established.
|
|
635
655
|
*/
|
|
636
656
|
get established() {
|
|
637
657
|
return this.state.established
|
|
@@ -639,7 +659,7 @@ class call {
|
|
|
639
659
|
|
|
640
660
|
/**
|
|
641
661
|
@summary canceled - if the call isn't already canceled then set the endat time.
|
|
642
|
-
@type {boolean}
|
|
662
|
+
@type { boolean }
|
|
643
663
|
*/
|
|
644
664
|
set canceled( s ) {
|
|
645
665
|
if( this.state.canceled != s ) {
|
|
@@ -658,7 +678,7 @@ class call {
|
|
|
658
678
|
|
|
659
679
|
/**
|
|
660
680
|
destroyed - if the call isn't already desroyed then set the endat time.
|
|
661
|
-
@param {
|
|
681
|
+
@param { boolean } s - true if the call has been destroyed.
|
|
662
682
|
*/
|
|
663
683
|
set destroyed( s ) {
|
|
664
684
|
if( this.state.destroyed != s ) {
|
|
@@ -669,7 +689,7 @@ class call {
|
|
|
669
689
|
|
|
670
690
|
/**
|
|
671
691
|
destroyed
|
|
672
|
-
@return {
|
|
692
|
+
@return { boolean } - true if teh call has been destroyed.
|
|
673
693
|
*/
|
|
674
694
|
get destroyed() {
|
|
675
695
|
return true == this.state.destroyed
|
|
@@ -681,7 +701,7 @@ class call {
|
|
|
681
701
|
|
|
682
702
|
/**
|
|
683
703
|
@summary the current state of the call as a string: trying|proceeding|early|confirmed|terminated
|
|
684
|
-
@return {string}
|
|
704
|
+
@return { string }
|
|
685
705
|
*/
|
|
686
706
|
get statestr() {
|
|
687
707
|
if( this.state.established ) {
|
|
@@ -705,54 +725,50 @@ class call {
|
|
|
705
725
|
|
|
706
726
|
/**
|
|
707
727
|
duration
|
|
708
|
-
@return {number} - the number of seconds between now (or endat if ended) and the time the call was started.
|
|
728
|
+
@return { number } - the number of seconds between now (or endat if ended) and the time the call was started.
|
|
709
729
|
*/
|
|
710
730
|
get duration() {
|
|
711
|
-
if( 0 !== this.epochs.endat ) return
|
|
712
|
-
return
|
|
731
|
+
if( 0 !== this.epochs.endat ) return this.epochs.endat - this.epochs.startat
|
|
732
|
+
return Math.floor( +new Date() / 1000 ) - this.epochs.startat
|
|
713
733
|
}
|
|
714
734
|
|
|
715
735
|
/**
|
|
716
736
|
Get the estrablished time.
|
|
717
|
-
@return {number} - the number of seconds between now (or endat if ended) and the time the call was answered.
|
|
737
|
+
@return { number } - the number of seconds between now (or endat if ended) and the time the call was answered.
|
|
718
738
|
*/
|
|
719
739
|
get billingduration() {
|
|
720
740
|
if( 0 === this.epochs.answerat ) return 0
|
|
721
|
-
if( 0 !== this.epochs.endat ) return
|
|
722
|
-
return
|
|
741
|
+
if( 0 !== this.epochs.endat ) return this.epochs.endat - this.epochs.answerat
|
|
742
|
+
return Math.floor( +new Date() / 1000 ) - this.epochs.answerat
|
|
723
743
|
}
|
|
724
744
|
|
|
725
|
-
/**
|
|
726
|
-
Callback for events we pass back to inerested parties.
|
|
727
|
-
@callback call.event
|
|
728
|
-
@param {object} call - we pass *this back into the requester
|
|
729
|
-
*/
|
|
730
745
|
|
|
731
746
|
/**
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
747
|
+
* Callback for events we pass back to inerested parties.
|
|
748
|
+
* Registers an event callback for this specific call. An event sink registered
|
|
749
|
+
* on this member will receive events only for this call. We emit on call specific
|
|
750
|
+
* emitter and a global emitter.
|
|
751
|
+
* @param { string } ev - The contact string for registered or other sip contact
|
|
752
|
+
* @param { (...args: any[] ) => void } cb
|
|
753
|
+
*/
|
|
738
754
|
on( ev, cb ) {
|
|
739
755
|
this._em.on( ev, cb )
|
|
740
756
|
}
|
|
741
757
|
|
|
742
758
|
/**
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
759
|
+
* See event emitter once
|
|
760
|
+
* @param { string } ev - The contact string for registered or other sip contact
|
|
761
|
+
* @param { (...args: any[] ) => void } cb
|
|
762
|
+
*/
|
|
747
763
|
once( ev, cb ) {
|
|
748
764
|
this._em.once( ev, cb )
|
|
749
765
|
}
|
|
750
766
|
|
|
751
767
|
/**
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
768
|
+
* See event emitter off
|
|
769
|
+
* @param { string } ev - The contact string for registered or other sip contact
|
|
770
|
+
* @param { (...args: any[] ) => void } cb
|
|
771
|
+
*/
|
|
756
772
|
off( ev, cb ) {
|
|
757
773
|
if( !cb ) {
|
|
758
774
|
this._em.removeAllListeners( ev )
|
|
@@ -763,9 +779,9 @@ class call {
|
|
|
763
779
|
}
|
|
764
780
|
|
|
765
781
|
/**
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
782
|
+
* See event emitter removeAllListeners
|
|
783
|
+
* @param { string } [ ev ] - The contact string for registered or other sip contact
|
|
784
|
+
*/
|
|
769
785
|
removealllisteners( ev ) {
|
|
770
786
|
if( !ev ) {
|
|
771
787
|
const evnames = this._em.eventNames()
|
|
@@ -876,16 +892,19 @@ class call {
|
|
|
876
892
|
/**
|
|
877
893
|
Emits the event call.pick to allow other parts of dial plan to give up on further processing.
|
|
878
894
|
It wuld be normal to bridge this call to another after this call has been made.
|
|
895
|
+
@return { call }
|
|
879
896
|
*/
|
|
880
897
|
pick() {
|
|
881
898
|
this.state.picked = true
|
|
882
899
|
this._em.emit( "call.pick", this )
|
|
900
|
+
return this
|
|
883
901
|
}
|
|
884
902
|
|
|
885
903
|
/**
|
|
886
904
|
Delink calls logically - any calls which have parent or children they are all removed.
|
|
887
905
|
when the dialog is either answered (or doesn't answer for some reason).
|
|
888
906
|
The promise resolves to a new call is one is generated, or undefined if not.
|
|
907
|
+
@return { call }
|
|
889
908
|
*/
|
|
890
909
|
detach() {
|
|
891
910
|
if( this.parent ) {
|
|
@@ -896,13 +915,16 @@ class call {
|
|
|
896
915
|
child.parent = false
|
|
897
916
|
}
|
|
898
917
|
|
|
899
|
-
this.parent =
|
|
918
|
+
this.parent = undefined
|
|
900
919
|
this.children.clear()
|
|
920
|
+
return this
|
|
901
921
|
}
|
|
902
922
|
|
|
903
923
|
/**
|
|
904
|
-
Logically adopt a child call
|
|
905
|
-
@param {
|
|
924
|
+
* Logically adopt a child call
|
|
925
|
+
* @param { object } other
|
|
926
|
+
* @param { boolean } [ mix ]
|
|
927
|
+
* @return { call }
|
|
906
928
|
*/
|
|
907
929
|
adopt( other, mix ) {
|
|
908
930
|
other.parent = this
|
|
@@ -922,6 +944,29 @@ class call {
|
|
|
922
944
|
this.epochs.mix = Math.floor( +new Date() / 1000 )
|
|
923
945
|
other.epochs.mix = Math.floor( +new Date() / 1000 )
|
|
924
946
|
}
|
|
947
|
+
return this
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* Create a bond between us and another call. This is currently only used
|
|
952
|
+
* to provide other channels we know we might need to open a channel on
|
|
953
|
+
* the same node as. (replaces preferredcall)
|
|
954
|
+
* @param { object } relative
|
|
955
|
+
* @return { call }
|
|
956
|
+
*/
|
|
957
|
+
bond( relative ) {
|
|
958
|
+
if( !relative ) return
|
|
959
|
+
this.relatives.add( relative )
|
|
960
|
+
return this
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Disown distant relatives.
|
|
965
|
+
* @return { call }
|
|
966
|
+
*/
|
|
967
|
+
disown() {
|
|
968
|
+
this.relatives.clear()
|
|
969
|
+
return this
|
|
925
970
|
}
|
|
926
971
|
|
|
927
972
|
/**
|
|
@@ -931,7 +976,7 @@ class call {
|
|
|
931
976
|
_onring() {
|
|
932
977
|
if( this.state.ringing ) return
|
|
933
978
|
this.state.ringing = true
|
|
934
|
-
if(
|
|
979
|
+
if( undefined !== this.parent ) {
|
|
935
980
|
this.parent.ring()
|
|
936
981
|
}
|
|
937
982
|
|
|
@@ -1134,18 +1179,20 @@ class call {
|
|
|
1134
1179
|
|
|
1135
1180
|
/**
|
|
1136
1181
|
Sometimes we don't care who if we are the parent or child - we just want the other party
|
|
1137
|
-
@return { object|
|
|
1182
|
+
@return { object | boolean } returns call object or if none false
|
|
1138
1183
|
*/
|
|
1139
1184
|
get other() {
|
|
1140
1185
|
if( this.parent ) return this.parent
|
|
1141
1186
|
|
|
1187
|
+
/* first established */
|
|
1142
1188
|
for( const child of this.children ) {
|
|
1143
1189
|
if( child.established ) {
|
|
1144
1190
|
return child
|
|
1145
1191
|
}
|
|
1146
1192
|
}
|
|
1147
1193
|
|
|
1148
|
-
|
|
1194
|
+
/* or the first */
|
|
1195
|
+
if( 0 < this.children.size ) return this.children.values().next().value
|
|
1149
1196
|
|
|
1150
1197
|
return false
|
|
1151
1198
|
}
|
|
@@ -1172,10 +1219,10 @@ class call {
|
|
|
1172
1219
|
}
|
|
1173
1220
|
|
|
1174
1221
|
this._timers.auth = setTimeout( () => {
|
|
1175
|
-
this._promises.reject.auth()
|
|
1176
|
-
this._promises.resolve.auth =
|
|
1177
|
-
this._promises.reject.auth =
|
|
1178
|
-
this._timers.auth =
|
|
1222
|
+
this._promises.reject.auth( new SipError( hangupcodes.REQUEST_TIMEOUT, "Auth timed out" ) )
|
|
1223
|
+
this._promises.resolve.auth = undefined
|
|
1224
|
+
this._promises.reject.auth = undefined
|
|
1225
|
+
this._timers.auth = undefined
|
|
1179
1226
|
|
|
1180
1227
|
this.hangup( hangupcodes.REQUEST_TIMEOUT )
|
|
1181
1228
|
|
|
@@ -1206,7 +1253,7 @@ class call {
|
|
|
1206
1253
|
this._req = req
|
|
1207
1254
|
this._res = res
|
|
1208
1255
|
|
|
1209
|
-
req.on( "cancel", ( req ) => this._oncanceled( req ) )
|
|
1256
|
+
req.on( "cancel", ( /*req*/ ) => this._oncanceled( /*req*/ ) )
|
|
1210
1257
|
|
|
1211
1258
|
if( !this._auth.has( this._req ) ) return false
|
|
1212
1259
|
|
|
@@ -1230,14 +1277,14 @@ class call {
|
|
|
1230
1277
|
|
|
1231
1278
|
await this.hangup( hangupcodes.FORBIDDEN )
|
|
1232
1279
|
|
|
1233
|
-
const
|
|
1234
|
-
this._promises.resolve.auth =
|
|
1235
|
-
this._promises.reject.auth =
|
|
1280
|
+
const reject = this._promises.reject.auth
|
|
1281
|
+
this._promises.resolve.auth = undefined
|
|
1282
|
+
this._promises.reject.auth = undefined
|
|
1236
1283
|
|
|
1237
1284
|
clearTimeout( this._timers.auth )
|
|
1238
|
-
this._timers.auth =
|
|
1285
|
+
this._timers.auth = undefined
|
|
1239
1286
|
|
|
1240
|
-
if(
|
|
1287
|
+
if( reject ) reject( new SipError( hangupcodes.FORBIDDEN, "Bad Auth" ))
|
|
1241
1288
|
|
|
1242
1289
|
return false
|
|
1243
1290
|
}
|
|
@@ -1255,11 +1302,11 @@ class call {
|
|
|
1255
1302
|
this.state.authed = true
|
|
1256
1303
|
await callstore.set( this )
|
|
1257
1304
|
|
|
1258
|
-
const
|
|
1259
|
-
this._promises.resolve.auth =
|
|
1260
|
-
this._promises.reject.auth =
|
|
1261
|
-
this._timers.auth =
|
|
1262
|
-
if(
|
|
1305
|
+
const resolve = this._promises.resolve.auth
|
|
1306
|
+
this._promises.resolve.auth = undefined
|
|
1307
|
+
this._promises.reject.auth = undefined
|
|
1308
|
+
this._timers.auth = undefined
|
|
1309
|
+
if( resolve ) resolve()
|
|
1263
1310
|
|
|
1264
1311
|
this._em.emit( "call.authed", this )
|
|
1265
1312
|
callmanager.options.em.emit( "call.authed", this )
|
|
@@ -1298,14 +1345,14 @@ class call {
|
|
|
1298
1345
|
if( this._promises.resolve.events ) {
|
|
1299
1346
|
const r = this._promises.resolve.events
|
|
1300
1347
|
|
|
1301
|
-
this._promises.resolve.events =
|
|
1302
|
-
this._promises.promise.events =
|
|
1348
|
+
this._promises.resolve.events = undefined
|
|
1349
|
+
this._promises.promise.events = undefined
|
|
1303
1350
|
r( ourmatch[ 0 ] )
|
|
1304
1351
|
}
|
|
1305
1352
|
|
|
1306
1353
|
if( this._timers.events ) {
|
|
1307
1354
|
clearTimeout( this._timers.events )
|
|
1308
|
-
this._timers.events =
|
|
1355
|
+
this._timers.events = undefined
|
|
1309
1356
|
}
|
|
1310
1357
|
}
|
|
1311
1358
|
}
|
|
@@ -1313,9 +1360,9 @@ class call {
|
|
|
1313
1360
|
|
|
1314
1361
|
/**
|
|
1315
1362
|
Called by our call plan to wait for events for auto attendant/IVR.
|
|
1316
|
-
@param {string} [match] - reg exp matching what is required from the user.
|
|
1317
|
-
@param {
|
|
1318
|
-
@return {Promise} - the promise either resolves to a string if it matches or undefined if it times out..
|
|
1363
|
+
@param { string | RegExp } [match] - reg exp matching what is required from the user.
|
|
1364
|
+
@param { number } [timeout] - time to wait before giving up.
|
|
1365
|
+
@return { Promise } - the promise either resolves to a string if it matches or undefined if it times out..
|
|
1319
1366
|
*/
|
|
1320
1367
|
waitfortelevents( match = /[0-9A-D*#]/, timeout = 30000 ) {
|
|
1321
1368
|
|
|
@@ -1330,9 +1377,9 @@ class call {
|
|
|
1330
1377
|
this._promises.resolve.events()
|
|
1331
1378
|
}
|
|
1332
1379
|
|
|
1333
|
-
this._promises.resolve.events =
|
|
1334
|
-
this._promises.promise.events =
|
|
1335
|
-
this._timers.events =
|
|
1380
|
+
this._promises.resolve.events = undefined
|
|
1381
|
+
this._promises.promise.events = undefined
|
|
1382
|
+
this._timers.events = undefined
|
|
1336
1383
|
delete this.eventmatch
|
|
1337
1384
|
|
|
1338
1385
|
}, timeout )
|
|
@@ -1417,7 +1464,7 @@ class call {
|
|
|
1417
1464
|
/* we have already opened a channel (probably early now answering) */
|
|
1418
1465
|
this.channels.audio.remote( channeldef.remote )
|
|
1419
1466
|
} else {
|
|
1420
|
-
|
|
1467
|
+
|
|
1421
1468
|
await this.#openrelatedchannel( channeldef )
|
|
1422
1469
|
|
|
1423
1470
|
this.sdp.local = sdpgen.create()
|
|
@@ -1437,7 +1484,8 @@ class call {
|
|
|
1437
1484
|
}
|
|
1438
1485
|
|
|
1439
1486
|
/**
|
|
1440
|
-
*
|
|
1487
|
+
* that can be used to open the new channel's node.
|
|
1488
|
+
*
|
|
1441
1489
|
* @returns { Promise }
|
|
1442
1490
|
*/
|
|
1443
1491
|
async #choosecodecforanswer() {
|
|
@@ -1474,16 +1522,17 @@ class call {
|
|
|
1474
1522
|
|
|
1475
1523
|
/**
|
|
1476
1524
|
* Answer this (inbound) call and store a channel which can be used. This framework will catch and cleanup this call if this is rejected.
|
|
1477
|
-
* @param { object } options
|
|
1478
|
-
* @param { boolean } options.early - don't answer the channel (establish) but establish early media (respond to 183).
|
|
1525
|
+
* @param { object } [ options ]
|
|
1526
|
+
* @param { boolean } [ options.early ] - don't answer the channel (establish) but establish early media (respond to 183).
|
|
1479
1527
|
*
|
|
1480
1528
|
* @return {Promise} Returns a promise which resolves if the call is answered, otherwise rejects the promise.
|
|
1481
1529
|
*/
|
|
1482
|
-
async answer( options = {} ) {
|
|
1530
|
+
async answer( options = { early: false } ) {
|
|
1483
1531
|
|
|
1484
1532
|
if( this.canceled || this.established ) return
|
|
1485
1533
|
|
|
1486
1534
|
await this.#choosecodecforanswer()
|
|
1535
|
+
|
|
1487
1536
|
if( this.canceled ) return
|
|
1488
1537
|
|
|
1489
1538
|
if( options.early ) {
|
|
@@ -1555,12 +1604,12 @@ class call {
|
|
|
1555
1604
|
*/
|
|
1556
1605
|
|
|
1557
1606
|
if( this._timers.anyevent ) clearTimeout( this._timers.anyevent )
|
|
1558
|
-
this._timers.anyevent =
|
|
1607
|
+
this._timers.anyevent = undefined
|
|
1559
1608
|
|
|
1560
1609
|
const r = this._promises.resolve.channelevent
|
|
1561
|
-
this._promises.resolve.channelevent =
|
|
1562
|
-
this._promises.reject.channelevent =
|
|
1563
|
-
this._promises.promise.channelevent =
|
|
1610
|
+
this._promises.resolve.channelevent = undefined
|
|
1611
|
+
this._promises.reject.channelevent = undefined
|
|
1612
|
+
this._promises.promise.channelevent = undefined
|
|
1564
1613
|
if( r ) r( e )
|
|
1565
1614
|
}
|
|
1566
1615
|
|
|
@@ -1597,7 +1646,7 @@ class call {
|
|
|
1597
1646
|
|
|
1598
1647
|
A telephone event will resolve this promise as we typically need speech to be interupted
|
|
1599
1648
|
by the user. Note, peeking a telephone-event (i.e. DTMF) will not clear it like waitfortelevents will.
|
|
1600
|
-
@param {
|
|
1649
|
+
@param { object } constraints - event to filter for from our RTP server - excluding DTMF events - these will always return
|
|
1601
1650
|
*/
|
|
1602
1651
|
waitforanyevent( constraints, timeout = 500 ) {
|
|
1603
1652
|
|
|
@@ -1613,9 +1662,9 @@ class call {
|
|
|
1613
1662
|
|
|
1614
1663
|
this._timers.anyevent = setTimeout( () => {
|
|
1615
1664
|
const r = this._promises.resolve.channelevent
|
|
1616
|
-
this._promises.promise.channelevent =
|
|
1617
|
-
this._promises.resolve.channelevent =
|
|
1618
|
-
this._promises.reject.channelevent =
|
|
1665
|
+
this._promises.promise.channelevent = undefined
|
|
1666
|
+
this._promises.resolve.channelevent = undefined
|
|
1667
|
+
this._promises.reject.channelevent = undefined
|
|
1619
1668
|
if( r ) r( "timeout" )
|
|
1620
1669
|
}, timeout * 1000 )
|
|
1621
1670
|
|
|
@@ -2195,8 +2244,8 @@ class call {
|
|
|
2195
2244
|
@param { string } address - remote address (ip)
|
|
2196
2245
|
@param { number } port - remote port
|
|
2197
2246
|
@param { number } codec
|
|
2198
|
-
@param { string } fingerprint - remote sha 256 fingerprint
|
|
2199
|
-
@param { string } mode - "active"|"passive"
|
|
2247
|
+
@param { string } [ fingerprint ] - remote sha 256 fingerprint
|
|
2248
|
+
@param { string } [ mode ] - "active"|"passive"
|
|
2200
2249
|
*/
|
|
2201
2250
|
static _createchannelremotedef( address, port, codec, fingerprint, mode /* active|passive */ ) {
|
|
2202
2251
|
const chandef = {
|
|
@@ -2220,6 +2269,8 @@ class call {
|
|
|
2220
2269
|
|
|
2221
2270
|
/**
|
|
2222
2271
|
Sets our hangup cause correctly - if not already set.
|
|
2272
|
+
@param { string } src
|
|
2273
|
+
@param { object } [ reason ]
|
|
2223
2274
|
@private
|
|
2224
2275
|
*/
|
|
2225
2276
|
_sethangupcause( src, reason ) {
|
|
@@ -2250,24 +2301,24 @@ class call {
|
|
|
2250
2301
|
/* Clean up promises (ensure they are resolved) and clear any timers */
|
|
2251
2302
|
for ( const [ key, value ] of Object.entries( this._timers ) ) {
|
|
2252
2303
|
if( value ) clearTimeout( value )
|
|
2253
|
-
this._timers[ key ] =
|
|
2304
|
+
this._timers[ key ] = undefined
|
|
2254
2305
|
}
|
|
2255
2306
|
|
|
2256
2307
|
const authreject = this._promises.reject.auth
|
|
2257
|
-
this._promises.reject.auth =
|
|
2258
|
-
this._promises.resolve.auth =
|
|
2259
|
-
if( authreject ) authreject(
|
|
2308
|
+
this._promises.reject.auth = undefined
|
|
2309
|
+
this._promises.resolve.auth = undefined
|
|
2310
|
+
if( authreject ) authreject( new SipError( hangupcodes.REQUEST_TIMEOUT, "Auth timed out (cleanup)" ) )
|
|
2260
2311
|
|
|
2261
2312
|
const chanev = this._promises.reject.channelevent
|
|
2262
|
-
this._promises.resolve.channelevent =
|
|
2263
|
-
this._promises.reject.channelevent =
|
|
2264
|
-
this._promises.promise.channelevent =
|
|
2313
|
+
this._promises.resolve.channelevent = undefined
|
|
2314
|
+
this._promises.reject.channelevent = undefined
|
|
2315
|
+
this._promises.promise.channelevent = undefined
|
|
2265
2316
|
if( chanev ) chanev( Error( "Call hungup" ) )
|
|
2266
2317
|
|
|
2267
2318
|
const resolves = []
|
|
2268
2319
|
for ( const [ key, value ] of Object.entries( this._promises.resolve ) ) {
|
|
2269
2320
|
if( value ) resolves.push( value )
|
|
2270
|
-
this._promises.resolve[ key ] =
|
|
2321
|
+
this._promises.resolve[ key ] = undefined
|
|
2271
2322
|
}
|
|
2272
2323
|
|
|
2273
2324
|
/* Call outstanding resolves for promises - this will trigger out hangup promise also */
|
|
@@ -2286,8 +2337,8 @@ class call {
|
|
|
2286
2337
|
* Used by our frame to a) continue a hangup which has been initiated by either us or the network.
|
|
2287
2338
|
* Complete the hangup, including hanging up all children and waiting for them to complete their
|
|
2288
2339
|
* hangup.
|
|
2289
|
-
* @param {string} [
|
|
2290
|
-
* @param {object} reason - one of the reasons from the hangupcodes enum - only used if we havn't alread set our reason
|
|
2340
|
+
* @param { string } [ src ] - "us"|"wire"
|
|
2341
|
+
* @param { object } [ reason ] - one of the reasons from the hangupcodes enum - only used if we havn't alread set our reason
|
|
2291
2342
|
* @private
|
|
2292
2343
|
*/
|
|
2293
2344
|
async _onhangup( src = "us", reason ) {
|
|
@@ -2377,16 +2428,16 @@ class call {
|
|
|
2377
2428
|
}
|
|
2378
2429
|
|
|
2379
2430
|
await this._promises.promise.hangup
|
|
2380
|
-
this._promises.promise.hangup =
|
|
2381
|
-
this._promises.resolve.hangup =
|
|
2431
|
+
this._promises.promise.hangup = undefined
|
|
2432
|
+
this._promises.resolve.hangup = undefined
|
|
2382
2433
|
|
|
2383
2434
|
}
|
|
2384
2435
|
|
|
2385
2436
|
/**
|
|
2386
|
-
Send an UPDATE. Use to updated called id, caller id, sdp etc. Send in dialog - TODO look how to send
|
|
2387
|
-
early as this is recomended in the RFC.
|
|
2388
|
-
@param {
|
|
2389
|
-
@param {
|
|
2437
|
+
* Send an UPDATE. Use to updated called id, caller id, sdp etc. Send in dialog - TODO look how to send
|
|
2438
|
+
* early as this is recomended in the RFC.
|
|
2439
|
+
* @param { object } options
|
|
2440
|
+
* @param { entity } options.remote
|
|
2390
2441
|
*/
|
|
2391
2442
|
async update( options ) {
|
|
2392
2443
|
|
|
@@ -2454,19 +2505,22 @@ class call {
|
|
|
2454
2505
|
@summary Creates a new SIP dialog. Returns a promise which resolves
|
|
2455
2506
|
when the dialog is either answered (or cancelled for some reason).
|
|
2456
2507
|
The promise resolves to a new call is one is generated, or undefined if not.
|
|
2457
|
-
@param {
|
|
2508
|
+
@param { object } [ options ] - Options object. See default_options in index.js for more details.
|
|
2458
2509
|
@param { string } [ options.contact ] - The contact string
|
|
2459
2510
|
@param { boolean } [ options.orphan ] - If present and true then orphan the new call
|
|
2511
|
+
@param { object } [ options.auth ]
|
|
2460
2512
|
@param { string } [ options.auth.username ] - If SIP auth required username
|
|
2461
2513
|
@param { string } [ options.auth.password ] - If SIP auth required password
|
|
2462
2514
|
@param { object } [ options.headers ] - Object containing extra sip headers required.
|
|
2463
2515
|
@param { object } [ options.uactimeout ] - override the deault timeout
|
|
2464
2516
|
@param { boolean } [ options.late ] - late negotiation
|
|
2465
2517
|
@param { entity } [ options.entity ] - used to store this call against and look up a contact string if not supplied.
|
|
2518
|
+
@param { object } [ options.entity ]
|
|
2466
2519
|
@param { string } [ options.entity.username ]
|
|
2467
2520
|
@param { string } [ options.entity.realm ]
|
|
2468
2521
|
@param { string } [ options.entity.uri ]
|
|
2469
2522
|
@param { number } [ options.entity.max ] - if included no more than this number of calls for this entity (only if we look user up)
|
|
2523
|
+
@param { object } [ options.parent ] - the call we wish to become parent
|
|
2470
2524
|
@param { object } [ callbacks ]
|
|
2471
2525
|
@param { earlycallback } [ callbacks.early ] - callback to provide a call object with early call (pre dialog)
|
|
2472
2526
|
@param { confirmcallback } [ callbacks.confirm ] - called when a dialog is confirmed but before it is bridged with a parent - this provides an opportunity for another call to adopt this call
|
|
@@ -2488,10 +2542,10 @@ class call {
|
|
|
2488
2542
|
|
|
2489
2543
|
options.headers[ "Max-Forwards" ] = maxforwards
|
|
2490
2544
|
|
|
2491
|
-
if( !options.orphan ) {
|
|
2545
|
+
if( !options.orphan && !options.parent ) {
|
|
2492
2546
|
options.parent = this
|
|
2493
2547
|
}
|
|
2494
|
-
|
|
2548
|
+
|
|
2495
2549
|
return await call.newuac( options, callbacks )
|
|
2496
2550
|
}
|
|
2497
2551
|
|
|
@@ -2600,13 +2654,24 @@ class call {
|
|
|
2600
2654
|
* @param { object } [ channeldef ]
|
|
2601
2655
|
*/
|
|
2602
2656
|
async #openrelatedchannel( channeldef ) {
|
|
2603
|
-
|
|
2604
2657
|
const relatedcall = this.other
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2658
|
+
/* TODO: this is a hack. projectrtp has become too complicated with both a listen and connect
|
|
2659
|
+
mechanism. This is causing problems in code like this. There is no interface to
|
|
2660
|
+
detect which mode the channel is in - but the channels property will exist on a connect
|
|
2661
|
+
style channel. projectrtp will get a rewrite to support only one. */
|
|
2662
|
+
if( relatedcall && relatedcall.channels.audio && relatedcall.channels.audio.channels ) {
|
|
2663
|
+
this.channels.audio = await this.other.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2664
|
+
return
|
|
2665
|
+
}
|
|
2609
2666
|
|
|
2667
|
+
for( const other of this.relatives ) {
|
|
2668
|
+
if( other.channels && other.channels.audio ) {
|
|
2669
|
+
this.channels.audio = await other.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2670
|
+
return
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
this.channels.audio = await projectrtp.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2610
2675
|
}
|
|
2611
2676
|
|
|
2612
2677
|
/**
|
|
@@ -2626,12 +2691,12 @@ class call {
|
|
|
2626
2691
|
/**
|
|
2627
2692
|
*
|
|
2628
2693
|
*/
|
|
2629
|
-
async #openchannelsfornewuac() {
|
|
2694
|
+
async #openchannelsfornewuac( channeldef = undefined ) {
|
|
2630
2695
|
if( this.options.late ) {
|
|
2631
2696
|
this.options.noAck = true /* this is a MUST for late negotiation */
|
|
2632
2697
|
} else {
|
|
2633
2698
|
|
|
2634
|
-
await this.#openrelatedchannel()
|
|
2699
|
+
await this.#openrelatedchannel( channeldef )
|
|
2635
2700
|
|
|
2636
2701
|
this.sdp.local = sdpgen.create().addcodecs( this.options.preferedcodecs )
|
|
2637
2702
|
this.sdp.local.setaudioport( this.channels.audio.local.port )
|
|
@@ -2785,6 +2850,7 @@ class call {
|
|
|
2785
2850
|
@param { object } [ options ] - Options object. See default_options in index.js for more details.
|
|
2786
2851
|
@param { call } [ options.parent ] - the parent call object
|
|
2787
2852
|
@param { string } [ options.contact ] - The contact string
|
|
2853
|
+
@param { object } [ options.auth ]
|
|
2788
2854
|
@param { string } [ options.auth.username ] - If SIP auth required username
|
|
2789
2855
|
@param { string } [ options.auth.password ] - If SIP auth required password
|
|
2790
2856
|
@param { object } [ options.headers ] - Object containing extra sip headers required.
|
|
@@ -2793,6 +2859,7 @@ class call {
|
|
|
2793
2859
|
@param { boolean } [ options.late ] - late negotiation
|
|
2794
2860
|
@param { boolean } [ options.privacy ] - sets the privacy
|
|
2795
2861
|
@param { entity } [ options.entity ] - used to store this call against and look up a contact string if not supplied.
|
|
2862
|
+
@param { object } [ options.entity ]}
|
|
2796
2863
|
@param { string } [ options.entity.username ]
|
|
2797
2864
|
@param { string } [ options.entity.realm ]
|
|
2798
2865
|
@param { string } [ options.entity.uri ]
|
|
@@ -2801,6 +2868,7 @@ class call {
|
|
|
2801
2868
|
@param { object } [ options.callerid ]
|
|
2802
2869
|
@param { string } [ options.callerid.number ]
|
|
2803
2870
|
@param { string } [ options.callerid.name ]
|
|
2871
|
+
@param { call } [ options.bond ] - other channel to bond to for pottential channel pairing
|
|
2804
2872
|
@param { object } [ callbacks ]
|
|
2805
2873
|
@param { earlycallback } [ callbacks.early ] - callback to provide a call object with early call (pre dialog)
|
|
2806
2874
|
@param { confirmcallback } [ callbacks.confirm ] - called when a dialog is confirmed but before it is bridged with a parent - this provides an opportunity for another call to adopt this call
|
|
@@ -2823,6 +2891,8 @@ class call {
|
|
|
2823
2891
|
options.parent.adopt( newcall )
|
|
2824
2892
|
}
|
|
2825
2893
|
|
|
2894
|
+
newcall.bond( options.bond )
|
|
2895
|
+
|
|
2826
2896
|
newcall.options = {
|
|
2827
2897
|
headers: { ...options.headers }
|
|
2828
2898
|
}
|
|
@@ -2926,7 +2996,7 @@ class call {
|
|
|
2926
2996
|
*/
|
|
2927
2997
|
#setdialog( d ) {
|
|
2928
2998
|
clearTimeout( this._timers.newuac )
|
|
2929
|
-
this._timers.newuac =
|
|
2999
|
+
this._timers.newuac = undefined
|
|
2930
3000
|
|
|
2931
3001
|
if( this.destroyedcancelledorhungup ) return
|
|
2932
3002
|
|
|
@@ -2962,7 +3032,7 @@ class call {
|
|
|
2962
3032
|
Create a new object when we receive an INVITE request.
|
|
2963
3033
|
|
|
2964
3034
|
@param { object } req - req object from drachtio
|
|
2965
|
-
@param {
|
|
3035
|
+
@param { object } res - res object from drachtio
|
|
2966
3036
|
@returns { Promise< call > }
|
|
2967
3037
|
*/
|
|
2968
3038
|
static async frominvite( req, res ) {
|
|
@@ -2990,7 +3060,7 @@ class call {
|
|
|
2990
3060
|
@private
|
|
2991
3061
|
*/
|
|
2992
3062
|
c._req = req
|
|
2993
|
-
c._req.on( "cancel", ( req ) => c._oncanceled( req ) )
|
|
3063
|
+
c._req.on( "cancel", ( /*req*/ ) => c._oncanceled( /*req*/ ) )
|
|
2994
3064
|
|
|
2995
3065
|
/**
|
|
2996
3066
|
@member
|
|
@@ -3024,13 +3094,11 @@ class call {
|
|
|
3024
3094
|
*/
|
|
3025
3095
|
set uactimeout( ms ) {
|
|
3026
3096
|
if( this.established ) return
|
|
3027
|
-
const msi = parseInt( ms )
|
|
3028
|
-
if( isNaN( msi ) ) return
|
|
3029
3097
|
|
|
3030
3098
|
clearTimeout( this._timers.newuac )
|
|
3031
3099
|
this._timers.newuac = setTimeout( () => {
|
|
3032
3100
|
this.hangup( hangupcodes.REQUEST_TIMEOUT )
|
|
3033
|
-
},
|
|
3101
|
+
}, ms )
|
|
3034
3102
|
}
|
|
3035
3103
|
}
|
|
3036
3104
|
|
package/lib/callmanager.js
CHANGED
|
@@ -15,7 +15,6 @@ class callmanager {
|
|
|
15
15
|
@param {object} options
|
|
16
16
|
*/
|
|
17
17
|
constructor( options ) {
|
|
18
|
-
this.onnewcall = false
|
|
19
18
|
this.options = options
|
|
20
19
|
|
|
21
20
|
if( undefined === this.options.em ) {
|
|
@@ -55,12 +54,16 @@ class callmanager {
|
|
|
55
54
|
} catch( e ) {
|
|
56
55
|
console.error( e )
|
|
57
56
|
}
|
|
58
|
-
|
|
59
57
|
|
|
60
|
-
if(
|
|
58
|
+
if( this.onnewcall ) {
|
|
61
59
|
try {
|
|
62
60
|
await this.onnewcall( c )
|
|
63
61
|
} catch( e ) {
|
|
62
|
+
/* auth failed or timed out excluded as this is noral(ish) */
|
|
63
|
+
if( 403 === e.code ) return
|
|
64
|
+
if( 408 === e.code ) return
|
|
65
|
+
|
|
66
|
+
console.trace( e )
|
|
64
67
|
c.hangup( this.hangupcodes.SERVER_ERROR )
|
|
65
68
|
}
|
|
66
69
|
}
|
|
@@ -108,13 +111,14 @@ class callmanager {
|
|
|
108
111
|
Is configured to use drachtio and registers emitter for presence.
|
|
109
112
|
@return {callmanager}
|
|
110
113
|
*/
|
|
111
|
-
let cm
|
|
114
|
+
let cm
|
|
112
115
|
module.exports.callmanager = ( options ) => {
|
|
113
|
-
if(
|
|
116
|
+
if( cm ) return cm
|
|
114
117
|
|
|
115
118
|
assert( undefined !== options.srf )
|
|
116
119
|
cm = new callmanager( options )
|
|
117
120
|
call.setcallmanager( cm )
|
|
121
|
+
// @ts-ignore
|
|
118
122
|
cm._use()
|
|
119
123
|
return cm
|
|
120
124
|
}
|
package/lib/sdp.js
CHANGED
|
@@ -82,8 +82,8 @@ const defaultaudiomedia = {
|
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
84
|
* Takes a mixed input and outputs an array in the form [ "pcmu", "pcma" ]
|
|
85
|
-
* @param { string |
|
|
86
|
-
* @return {
|
|
85
|
+
* @param { string | Array<string|number> } codecarray
|
|
86
|
+
* @return { Array< string >}
|
|
87
87
|
*/
|
|
88
88
|
function alltocodecname( codecarray ) {
|
|
89
89
|
|
package/lib/store.js
CHANGED
|
@@ -12,11 +12,6 @@ let storebyrealm = new Map()
|
|
|
12
12
|
* @param {string} c.uuid - uuid of the call
|
|
13
13
|
* @param {object} c.sip
|
|
14
14
|
* @param {string} c.sip.callid - the call id string
|
|
15
|
-
* @param {object} c.sip.tags - the local and remote tags
|
|
16
|
-
* @param {string} c.sip.tags.local - the local tag
|
|
17
|
-
* @param {string} c.sip.tags.remote - the remote tag
|
|
18
|
-
* @param {object} c.entity - entity object
|
|
19
|
-
* @param {object} c.entity.uri
|
|
20
15
|
*/
|
|
21
16
|
function iscallobjectgood( c ) {
|
|
22
17
|
if( "object" !== typeof c ) return false
|
|
@@ -67,8 +62,11 @@ function deletefromcallidset( c ) {
|
|
|
67
62
|
|
|
68
63
|
/**
|
|
69
64
|
*
|
|
70
|
-
* @param { object } c
|
|
65
|
+
* @param { object } c
|
|
71
66
|
* @param { object } c._entity
|
|
67
|
+
* @param { object } [ c._entity.uri ]
|
|
68
|
+
* @param { object } [ c._entity.username ]
|
|
69
|
+
* @param { object } [ c._entity.realm ]
|
|
72
70
|
* @return { object | boolean } returns boolean if no further processing or entity object
|
|
73
71
|
*/
|
|
74
72
|
function fixentity( c ) {
|
|
@@ -94,20 +92,21 @@ function fixentity( c ) {
|
|
|
94
92
|
/**
|
|
95
93
|
* This can be called multiple times for the same call to store or update. Stores a
|
|
96
94
|
* call object in our store.
|
|
97
|
-
* @param {object} c - our call object.
|
|
98
|
-
* @param {string} c.uuid - uuid of the call
|
|
99
|
-
* @param {object} c.sip
|
|
100
|
-
* @param {string} c.sip.callid - the call id string
|
|
101
|
-
* @param {object} c.sip.tags - the local and remote tags
|
|
102
|
-
* @param {string} c.sip.tags.local - the local tag
|
|
103
|
-
* @param {string} c.sip.tags.remote - the remote tag
|
|
104
|
-
* @param {object} c.
|
|
105
|
-
* @param {object} c.
|
|
106
|
-
* @param {object} c._entity
|
|
107
|
-
* @param {object} c.
|
|
108
|
-
* @param {object}
|
|
109
|
-
* @param {
|
|
110
|
-
* @
|
|
95
|
+
* @param { object } c - our call object.
|
|
96
|
+
* @param { string } c.uuid - uuid of the call
|
|
97
|
+
* @param { object } c.sip
|
|
98
|
+
* @param { string } c.sip.callid - the call id string
|
|
99
|
+
* @param { object } c.sip.tags - the local and remote tags
|
|
100
|
+
* @param { string } c.sip.tags.local - the local tag
|
|
101
|
+
* @param { string } c.sip.tags.remote - the remote tag
|
|
102
|
+
* @param { object } c._entity
|
|
103
|
+
* @param { object } [ c._entity.uri ]
|
|
104
|
+
* @param { object } [ c._entity.username ]
|
|
105
|
+
* @param { object } [ c._entity.realm ]
|
|
106
|
+
* @param { object } c.destination
|
|
107
|
+
* @param { object } [ c._state ]
|
|
108
|
+
* @param { boolean } [ c._state._hangup ]
|
|
109
|
+
* @return { Promise } - which resolves on completion (for future in case we support redis or similar)
|
|
111
110
|
*/
|
|
112
111
|
module.exports.set = async ( c ) => {
|
|
113
112
|
if( !iscallobjectgood( c ) ) return false
|
|
@@ -163,13 +162,14 @@ module.exports.getbyentity = async ( uri ) => {
|
|
|
163
162
|
* @param {string} realm - the entity realm
|
|
164
163
|
* @return {Promise} which resolves to either a set containing calls for this entity or undefined
|
|
165
164
|
*/
|
|
166
|
-
|
|
165
|
+
async function getbyrealm( realm ) {
|
|
167
166
|
if( !storebyrealm.has( realm ) ) return false
|
|
168
167
|
return storebyrealm.get( realm )
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
/* backwards compat - is now realm more generally */
|
|
172
|
-
module.exports.
|
|
171
|
+
module.exports.getbyrealm = getbyrealm
|
|
172
|
+
module.exports.getbyentityrealm = getbyrealm
|
|
173
173
|
|
|
174
174
|
/**
|
|
175
175
|
* Returns a unique call by call id and sip tags.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babblevoice/babble-drachtio-callmanager",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.10",
|
|
4
4
|
"description": "Call processing to create a PBX",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,10 +28,15 @@
|
|
|
28
28
|
"@babblevoice/projectrtp": "^2.3.7"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"
|
|
32
|
-
"eslint": "^8.
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
|
32
|
+
"eslint": "^8.32.0",
|
|
33
|
+
"eslint-config-standard-with-typescript": "^30.0.0",
|
|
34
|
+
"eslint-plugin-import": "^2.27.5",
|
|
35
|
+
"eslint-plugin-n": "^15.6.1",
|
|
33
36
|
"eslint-plugin-promise": "^6.1.1",
|
|
34
|
-
"mocha": "^9.2.2"
|
|
37
|
+
"mocha": "^9.2.2",
|
|
38
|
+
"chai": "^4.3.6",
|
|
39
|
+
"typescript": "^4.9.4"
|
|
35
40
|
},
|
|
36
41
|
"bugs": {
|
|
37
42
|
"url": "https://github.com/tinpotnick/babble-drachtio-callmanager/issues"
|
package/test/interface/call.js
CHANGED
|
@@ -70,7 +70,7 @@ describe( "call object", function() {
|
|
|
70
70
|
expect( call.state ).to.have.property( "destroyed" ).that.is.a( "boolean" ).to.be.true
|
|
71
71
|
|
|
72
72
|
expect( call ).to.have.property( "children" ) // Set - how do you test?
|
|
73
|
-
expect( call ).to.have.property( "parent" ).that.is.
|
|
73
|
+
expect( call ).to.have.property( "parent" ).that.is.undefined
|
|
74
74
|
|
|
75
75
|
expect( call ).to.have.property( "vars" ).that.is.a( "object" )
|
|
76
76
|
|
|
@@ -80,7 +80,7 @@ describe( "call object", function() {
|
|
|
80
80
|
expect( call.epochs ).to.have.property( "endat" ).that.is.a( "number" )
|
|
81
81
|
|
|
82
82
|
expect( call ).to.have.property( "channels" ).that.is.a( "object" )
|
|
83
|
-
expect( call.channels ).to.have.property( "audio" ).to.be.
|
|
83
|
+
expect( call.channels ).to.have.property( "audio" ).to.be.undefined
|
|
84
84
|
|
|
85
85
|
/* if uas */
|
|
86
86
|
expect( call ).to.have.property( "network" ).that.is.a( "object" )
|
|
@@ -577,7 +577,7 @@ describe( "call object", function() {
|
|
|
577
577
|
srfscenario.inbound()
|
|
578
578
|
} )
|
|
579
579
|
|
|
580
|
-
c.on( "call.destroyed", ( c ) => {
|
|
580
|
+
c.on( "call.destroyed", ( /*c*/ ) => {
|
|
581
581
|
eventhappened = true
|
|
582
582
|
} )
|
|
583
583
|
|
|
@@ -597,7 +597,7 @@ describe( "call object", function() {
|
|
|
597
597
|
eventhappened = true
|
|
598
598
|
} )
|
|
599
599
|
|
|
600
|
-
srfscenario.options.em.on( "call.destroyed", ( c ) => {
|
|
600
|
+
srfscenario.options.em.on( "call.destroyed", ( /*c*/ ) => {
|
|
601
601
|
eventhappened = false
|
|
602
602
|
} )
|
|
603
603
|
|
|
@@ -650,7 +650,7 @@ describe( "call object", function() {
|
|
|
650
650
|
c._req.msg.uri = "sip:bob@biloxi.com"
|
|
651
651
|
c._req.setparsedheader( "from", { "params": { "tag": "767sf76wew" }, "uri": "sip:bob@biloxi.com", "host": "biloxi.com" } )
|
|
652
652
|
|
|
653
|
-
c._res.onsend( ( code, msg ) => {
|
|
653
|
+
c._res.onsend( ( code, /*msg*/ ) => {
|
|
654
654
|
|
|
655
655
|
if( 407 == code ) {
|
|
656
656
|
|
|
@@ -773,7 +773,7 @@ describe( "call object", function() {
|
|
|
773
773
|
const srfscenario = new srf.srfscenario( {} )
|
|
774
774
|
|
|
775
775
|
let createuacoptions
|
|
776
|
-
srfscenario.oncreateUAC( ( contact, options, callbacks ) => {
|
|
776
|
+
srfscenario.oncreateUAC( ( contact, options, /*callbacks*/ ) => {
|
|
777
777
|
createuacoptions = options
|
|
778
778
|
|
|
779
779
|
} )
|
|
@@ -798,7 +798,7 @@ describe( "call object", function() {
|
|
|
798
798
|
}
|
|
799
799
|
|
|
800
800
|
let earlycallbackcalled = false
|
|
801
|
-
const c = await call.newuac( options, { "early": ( c ) => earlycallbackcalled = true } )
|
|
801
|
+
const c = await call.newuac( options, { "early": ( /*c*/ ) => earlycallbackcalled = true } )
|
|
802
802
|
|
|
803
803
|
c.hangup()
|
|
804
804
|
|
|
@@ -814,7 +814,7 @@ describe( "call object", function() {
|
|
|
814
814
|
}
|
|
815
815
|
|
|
816
816
|
let earlycallbackcalled = false
|
|
817
|
-
const c = await call.newuac( options, { "confirm": ( c ) => earlycallbackcalled = true } )
|
|
817
|
+
const c = await call.newuac( options, { "confirm": ( /*c*/ ) => earlycallbackcalled = true } )
|
|
818
818
|
|
|
819
819
|
c.hangup()
|
|
820
820
|
|