@babblevoice/babble-drachtio-callmanager 2.3.8 → 2.3.9
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 +234 -199
- 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,38 @@ 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
|
|
189
207
|
|
|
190
208
|
/**
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
209
|
+
* @typedef {Object} epochs
|
|
210
|
+
* @property {number} startat UNIX timestamp of when the call was started (created)
|
|
211
|
+
* @property {number} answerat UNIX timestamp of when the call was answered
|
|
212
|
+
* @property {number} endat UNIX timestamp of when the call ended
|
|
213
|
+
*/
|
|
196
214
|
|
|
197
215
|
/** @member {epochs} */
|
|
198
216
|
this.epochs = {
|
|
@@ -203,13 +221,15 @@ class call {
|
|
|
203
221
|
}
|
|
204
222
|
|
|
205
223
|
/**
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
224
|
+
* @typedef { object } sipdialog
|
|
225
|
+
* @property { string } callid
|
|
226
|
+
* @property { object } tags
|
|
227
|
+
* @property { string } tags.local
|
|
228
|
+
* @property { string } tags.remote
|
|
229
|
+
*/
|
|
230
|
+
/** @member { sipdialog } */
|
|
212
231
|
this.sip = {
|
|
232
|
+
"callid": undefined,
|
|
213
233
|
"tags": {
|
|
214
234
|
"remote": "",
|
|
215
235
|
"local": ""
|
|
@@ -217,32 +237,23 @@ class call {
|
|
|
217
237
|
}
|
|
218
238
|
|
|
219
239
|
/**
|
|
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
|
|
240
|
+
* For inbound calls - this is discovered by authentication. For outbound
|
|
241
|
+
* this is requested by the caller - i.e. the destination is the registered user.
|
|
242
|
+
* @type { entity }
|
|
243
|
+
* Protected for this module.
|
|
231
244
|
*/
|
|
232
245
|
this._entity
|
|
233
246
|
|
|
234
247
|
/**
|
|
235
248
|
Override caller id or name.
|
|
236
|
-
@member { _remote }
|
|
237
249
|
@private
|
|
238
250
|
*/
|
|
239
251
|
this._remote = {
|
|
240
|
-
"id":
|
|
241
|
-
"name":
|
|
252
|
+
"id": undefined,
|
|
253
|
+
"name": undefined
|
|
242
254
|
}
|
|
243
255
|
|
|
244
256
|
/**
|
|
245
|
-
* @member { object }
|
|
246
257
|
* @summary contains network information regarding call
|
|
247
258
|
*/
|
|
248
259
|
this.network = {
|
|
@@ -254,8 +265,7 @@ class call {
|
|
|
254
265
|
}
|
|
255
266
|
|
|
256
267
|
/**
|
|
257
|
-
@
|
|
258
|
-
@summary user definable object that allows other modules to store data in this call.
|
|
268
|
+
* @summary user definable object that allows other modules to store data in this call.
|
|
259
269
|
*/
|
|
260
270
|
this.vars = {}
|
|
261
271
|
|
|
@@ -266,24 +276,23 @@ class call {
|
|
|
266
276
|
this._receivedtelevents = ""
|
|
267
277
|
|
|
268
278
|
/**
|
|
269
|
-
@
|
|
270
|
-
@private
|
|
279
|
+
* @private
|
|
271
280
|
*/
|
|
272
281
|
this._promises = {
|
|
273
282
|
"resolve": {
|
|
274
|
-
"auth":
|
|
275
|
-
"hangup":
|
|
276
|
-
"events":
|
|
277
|
-
"channelevent":
|
|
283
|
+
"auth": undefined,
|
|
284
|
+
"hangup": undefined,
|
|
285
|
+
"events": undefined,
|
|
286
|
+
"channelevent": undefined
|
|
278
287
|
},
|
|
279
288
|
"reject": {
|
|
280
|
-
"auth":
|
|
281
|
-
"channelevent":
|
|
289
|
+
"auth": undefined,
|
|
290
|
+
"channelevent": undefined
|
|
282
291
|
},
|
|
283
292
|
"promise": {
|
|
284
|
-
"hangup":
|
|
285
|
-
"events":
|
|
286
|
-
"channelevent":
|
|
293
|
+
"hangup": undefined,
|
|
294
|
+
"events": undefined,
|
|
295
|
+
"channelevent": undefined
|
|
287
296
|
}
|
|
288
297
|
}
|
|
289
298
|
|
|
@@ -292,52 +301,61 @@ class call {
|
|
|
292
301
|
} )
|
|
293
302
|
|
|
294
303
|
/**
|
|
295
|
-
@
|
|
296
|
-
@private
|
|
304
|
+
* @private
|
|
297
305
|
*/
|
|
298
306
|
this._timers = {
|
|
299
|
-
"auth":
|
|
300
|
-
"newuac":
|
|
301
|
-
"events":
|
|
302
|
-
"seinterval":
|
|
303
|
-
"anyevent":
|
|
307
|
+
"auth": undefined,
|
|
308
|
+
"newuac": undefined,
|
|
309
|
+
"events": undefined,
|
|
310
|
+
"seinterval": undefined,
|
|
311
|
+
"anyevent": undefined
|
|
304
312
|
}
|
|
305
313
|
|
|
306
314
|
/**
|
|
307
|
-
@
|
|
308
|
-
@private
|
|
315
|
+
* @private
|
|
309
316
|
*/
|
|
310
317
|
this._em = new events.EventEmitter()
|
|
311
318
|
|
|
312
|
-
|
|
319
|
+
/**
|
|
320
|
+
* @typedef { Object } options
|
|
321
|
+
* @property { string } [ contact ] contact string
|
|
322
|
+
* @property { string } [ preferedcodecs ] as it says
|
|
323
|
+
* @property { boolean } [ rfc2833 ] if set to true enable 2833
|
|
324
|
+
* @property { string } [ display ] how the user should be displayed
|
|
325
|
+
* @property { Array } [ headers ]
|
|
326
|
+
* @property { number } [ uactimeout ] timeout in mS
|
|
327
|
+
* @property { boolean } [ late ] - do we use late negotiation
|
|
328
|
+
* @property { boolean } [ noAck ] do not use - converts our options into Drachtio options
|
|
329
|
+
* @property { string } [ localSdp ] do not use - what we pass into drachtio
|
|
330
|
+
*/
|
|
331
|
+
/**
|
|
332
|
+
* copy default
|
|
333
|
+
* @type { options }
|
|
334
|
+
*/
|
|
313
335
|
this.options = { ...callmanager.options }
|
|
314
336
|
|
|
315
337
|
/**
|
|
316
|
-
@
|
|
317
|
-
@private
|
|
338
|
+
* @private
|
|
318
339
|
*/
|
|
319
340
|
this._auth = sipauth.create( callmanager.options.proxy )
|
|
320
341
|
|
|
321
342
|
this.referauthrequired = callmanager.options.referauthrequired
|
|
322
343
|
|
|
323
344
|
/**
|
|
324
|
-
Enable access for other modules.
|
|
345
|
+
* Enable access for other modules.
|
|
325
346
|
*/
|
|
326
347
|
this.hangupcodes = hangupcodes
|
|
327
|
-
}
|
|
328
348
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
@property { number } ccc - Current Call Count
|
|
336
|
-
*/
|
|
349
|
+
/**
|
|
350
|
+
* If the call is referred somewhere, this is the url we use
|
|
351
|
+
* @type { string }
|
|
352
|
+
*/
|
|
353
|
+
this.referingtouri
|
|
354
|
+
}
|
|
337
355
|
|
|
338
356
|
/**
|
|
339
|
-
Returns the entity if known (i.e. outbound or inbound authed).
|
|
340
|
-
@returns { Promise< entity > }
|
|
357
|
+
* Returns the entity if known (i.e. outbound or inbound authed).
|
|
358
|
+
* @returns { Promise< entity > }
|
|
341
359
|
*/
|
|
342
360
|
get entity() {
|
|
343
361
|
|
|
@@ -381,7 +399,6 @@ class call {
|
|
|
381
399
|
if( !e.uri && !( e.username && e.realm ) ) return
|
|
382
400
|
this._entity = e
|
|
383
401
|
|
|
384
|
-
this._entity.name = ""
|
|
385
402
|
this._entity.display = ""
|
|
386
403
|
|
|
387
404
|
if( this._entity.uri ) {
|
|
@@ -408,7 +425,7 @@ class call {
|
|
|
408
425
|
|
|
409
426
|
/**
|
|
410
427
|
* Sets caller id
|
|
411
|
-
* @param {
|
|
428
|
+
* @param { string } callerid
|
|
412
429
|
*/
|
|
413
430
|
set callerid( callerid ) {
|
|
414
431
|
this._remote.id = callerid
|
|
@@ -416,7 +433,7 @@ class call {
|
|
|
416
433
|
|
|
417
434
|
/**
|
|
418
435
|
* Sets caller id name
|
|
419
|
-
* @param {
|
|
436
|
+
* @param { string } calleridname
|
|
420
437
|
*/
|
|
421
438
|
set calleridname( calleridname ) {
|
|
422
439
|
this._remote.name = calleridname
|
|
@@ -578,7 +595,7 @@ class call {
|
|
|
578
595
|
|
|
579
596
|
/**
|
|
580
597
|
hasmedia
|
|
581
|
-
@return {
|
|
598
|
+
@return { boolean } - true if the call has media (i.e. is established on not held).
|
|
582
599
|
*/
|
|
583
600
|
get hasmedia() {
|
|
584
601
|
if( this.state.held ) return false
|
|
@@ -597,7 +614,7 @@ class call {
|
|
|
597
614
|
|
|
598
615
|
/**
|
|
599
616
|
trying
|
|
600
|
-
@return {
|
|
617
|
+
@return { boolean } - true if the call has been trying.
|
|
601
618
|
*/
|
|
602
619
|
get trying() {
|
|
603
620
|
return this.state.trying
|
|
@@ -605,7 +622,7 @@ class call {
|
|
|
605
622
|
|
|
606
623
|
/**
|
|
607
624
|
ringing
|
|
608
|
-
@return {
|
|
625
|
+
@return { boolean } - true if the call has been ringing.
|
|
609
626
|
*/
|
|
610
627
|
get ringing() {
|
|
611
628
|
return this.state.ringing
|
|
@@ -620,7 +637,7 @@ class call {
|
|
|
620
637
|
|
|
621
638
|
/**
|
|
622
639
|
established - if the call isn't already established then set the answerat time.
|
|
623
|
-
@param {
|
|
640
|
+
@param { boolean } s - true if the call has been established.
|
|
624
641
|
*/
|
|
625
642
|
set established( s ) {
|
|
626
643
|
if( this.state.established != s ) {
|
|
@@ -631,7 +648,7 @@ class call {
|
|
|
631
648
|
|
|
632
649
|
/**
|
|
633
650
|
established
|
|
634
|
-
@return {
|
|
651
|
+
@return { boolean } - true if the call has been established.
|
|
635
652
|
*/
|
|
636
653
|
get established() {
|
|
637
654
|
return this.state.established
|
|
@@ -639,7 +656,7 @@ class call {
|
|
|
639
656
|
|
|
640
657
|
/**
|
|
641
658
|
@summary canceled - if the call isn't already canceled then set the endat time.
|
|
642
|
-
@type {boolean}
|
|
659
|
+
@type { boolean }
|
|
643
660
|
*/
|
|
644
661
|
set canceled( s ) {
|
|
645
662
|
if( this.state.canceled != s ) {
|
|
@@ -658,7 +675,7 @@ class call {
|
|
|
658
675
|
|
|
659
676
|
/**
|
|
660
677
|
destroyed - if the call isn't already desroyed then set the endat time.
|
|
661
|
-
@param {
|
|
678
|
+
@param { boolean } s - true if the call has been destroyed.
|
|
662
679
|
*/
|
|
663
680
|
set destroyed( s ) {
|
|
664
681
|
if( this.state.destroyed != s ) {
|
|
@@ -669,7 +686,7 @@ class call {
|
|
|
669
686
|
|
|
670
687
|
/**
|
|
671
688
|
destroyed
|
|
672
|
-
@return {
|
|
689
|
+
@return { boolean } - true if teh call has been destroyed.
|
|
673
690
|
*/
|
|
674
691
|
get destroyed() {
|
|
675
692
|
return true == this.state.destroyed
|
|
@@ -681,7 +698,7 @@ class call {
|
|
|
681
698
|
|
|
682
699
|
/**
|
|
683
700
|
@summary the current state of the call as a string: trying|proceeding|early|confirmed|terminated
|
|
684
|
-
@return {string}
|
|
701
|
+
@return { string }
|
|
685
702
|
*/
|
|
686
703
|
get statestr() {
|
|
687
704
|
if( this.state.established ) {
|
|
@@ -705,54 +722,50 @@ class call {
|
|
|
705
722
|
|
|
706
723
|
/**
|
|
707
724
|
duration
|
|
708
|
-
@return {number} - the number of seconds between now (or endat if ended) and the time the call was started.
|
|
725
|
+
@return { number } - the number of seconds between now (or endat if ended) and the time the call was started.
|
|
709
726
|
*/
|
|
710
727
|
get duration() {
|
|
711
|
-
if( 0 !== this.epochs.endat ) return
|
|
712
|
-
return
|
|
728
|
+
if( 0 !== this.epochs.endat ) return this.epochs.endat - this.epochs.startat
|
|
729
|
+
return Math.floor( +new Date() / 1000 ) - this.epochs.startat
|
|
713
730
|
}
|
|
714
731
|
|
|
715
732
|
/**
|
|
716
733
|
Get the estrablished time.
|
|
717
|
-
@return {number} - the number of seconds between now (or endat if ended) and the time the call was answered.
|
|
734
|
+
@return { number } - the number of seconds between now (or endat if ended) and the time the call was answered.
|
|
718
735
|
*/
|
|
719
736
|
get billingduration() {
|
|
720
737
|
if( 0 === this.epochs.answerat ) return 0
|
|
721
|
-
if( 0 !== this.epochs.endat ) return
|
|
722
|
-
return
|
|
738
|
+
if( 0 !== this.epochs.endat ) return this.epochs.endat - this.epochs.answerat
|
|
739
|
+
return Math.floor( +new Date() / 1000 ) - this.epochs.answerat
|
|
723
740
|
}
|
|
724
741
|
|
|
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
742
|
|
|
731
743
|
/**
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
744
|
+
* Callback for events we pass back to inerested parties.
|
|
745
|
+
* Registers an event callback for this specific call. An event sink registered
|
|
746
|
+
* on this member will receive events only for this call. We emit on call specific
|
|
747
|
+
* emitter and a global emitter.
|
|
748
|
+
* @param { string } ev - The contact string for registered or other sip contact
|
|
749
|
+
* @param { (...args: any[] ) => void } cb
|
|
750
|
+
*/
|
|
738
751
|
on( ev, cb ) {
|
|
739
752
|
this._em.on( ev, cb )
|
|
740
753
|
}
|
|
741
754
|
|
|
742
755
|
/**
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
756
|
+
* See event emitter once
|
|
757
|
+
* @param { string } ev - The contact string for registered or other sip contact
|
|
758
|
+
* @param { (...args: any[] ) => void } cb
|
|
759
|
+
*/
|
|
747
760
|
once( ev, cb ) {
|
|
748
761
|
this._em.once( ev, cb )
|
|
749
762
|
}
|
|
750
763
|
|
|
751
764
|
/**
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
765
|
+
* See event emitter off
|
|
766
|
+
* @param { string } ev - The contact string for registered or other sip contact
|
|
767
|
+
* @param { (...args: any[] ) => void } cb
|
|
768
|
+
*/
|
|
756
769
|
off( ev, cb ) {
|
|
757
770
|
if( !cb ) {
|
|
758
771
|
this._em.removeAllListeners( ev )
|
|
@@ -763,9 +776,9 @@ class call {
|
|
|
763
776
|
}
|
|
764
777
|
|
|
765
778
|
/**
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
779
|
+
* See event emitter removeAllListeners
|
|
780
|
+
* @param { string } [ ev ] - The contact string for registered or other sip contact
|
|
781
|
+
*/
|
|
769
782
|
removealllisteners( ev ) {
|
|
770
783
|
if( !ev ) {
|
|
771
784
|
const evnames = this._em.eventNames()
|
|
@@ -896,7 +909,7 @@ class call {
|
|
|
896
909
|
child.parent = false
|
|
897
910
|
}
|
|
898
911
|
|
|
899
|
-
this.parent =
|
|
912
|
+
this.parent = undefined
|
|
900
913
|
this.children.clear()
|
|
901
914
|
}
|
|
902
915
|
|
|
@@ -931,7 +944,7 @@ class call {
|
|
|
931
944
|
_onring() {
|
|
932
945
|
if( this.state.ringing ) return
|
|
933
946
|
this.state.ringing = true
|
|
934
|
-
if(
|
|
947
|
+
if( undefined !== this.parent ) {
|
|
935
948
|
this.parent.ring()
|
|
936
949
|
}
|
|
937
950
|
|
|
@@ -1134,18 +1147,20 @@ class call {
|
|
|
1134
1147
|
|
|
1135
1148
|
/**
|
|
1136
1149
|
Sometimes we don't care who if we are the parent or child - we just want the other party
|
|
1137
|
-
@return { object|
|
|
1150
|
+
@return { object | boolean } returns call object or if none false
|
|
1138
1151
|
*/
|
|
1139
1152
|
get other() {
|
|
1140
1153
|
if( this.parent ) return this.parent
|
|
1141
1154
|
|
|
1155
|
+
/* first established */
|
|
1142
1156
|
for( const child of this.children ) {
|
|
1143
1157
|
if( child.established ) {
|
|
1144
1158
|
return child
|
|
1145
1159
|
}
|
|
1146
1160
|
}
|
|
1147
1161
|
|
|
1148
|
-
|
|
1162
|
+
/* or the first */
|
|
1163
|
+
if( 0 < this.children.size ) return this.children.values().next().value
|
|
1149
1164
|
|
|
1150
1165
|
return false
|
|
1151
1166
|
}
|
|
@@ -1172,10 +1187,10 @@ class call {
|
|
|
1172
1187
|
}
|
|
1173
1188
|
|
|
1174
1189
|
this._timers.auth = setTimeout( () => {
|
|
1175
|
-
this._promises.reject.auth()
|
|
1176
|
-
this._promises.resolve.auth =
|
|
1177
|
-
this._promises.reject.auth =
|
|
1178
|
-
this._timers.auth =
|
|
1190
|
+
this._promises.reject.auth( new SipError( hangupcodes.REQUEST_TIMEOUT, "Auth timed out" ) )
|
|
1191
|
+
this._promises.resolve.auth = undefined
|
|
1192
|
+
this._promises.reject.auth = undefined
|
|
1193
|
+
this._timers.auth = undefined
|
|
1179
1194
|
|
|
1180
1195
|
this.hangup( hangupcodes.REQUEST_TIMEOUT )
|
|
1181
1196
|
|
|
@@ -1206,7 +1221,7 @@ class call {
|
|
|
1206
1221
|
this._req = req
|
|
1207
1222
|
this._res = res
|
|
1208
1223
|
|
|
1209
|
-
req.on( "cancel", ( req ) => this._oncanceled( req ) )
|
|
1224
|
+
req.on( "cancel", ( /*req*/ ) => this._oncanceled( /*req*/ ) )
|
|
1210
1225
|
|
|
1211
1226
|
if( !this._auth.has( this._req ) ) return false
|
|
1212
1227
|
|
|
@@ -1230,14 +1245,14 @@ class call {
|
|
|
1230
1245
|
|
|
1231
1246
|
await this.hangup( hangupcodes.FORBIDDEN )
|
|
1232
1247
|
|
|
1233
|
-
const
|
|
1234
|
-
this._promises.resolve.auth =
|
|
1235
|
-
this._promises.reject.auth =
|
|
1248
|
+
const reject = this._promises.reject.auth
|
|
1249
|
+
this._promises.resolve.auth = undefined
|
|
1250
|
+
this._promises.reject.auth = undefined
|
|
1236
1251
|
|
|
1237
1252
|
clearTimeout( this._timers.auth )
|
|
1238
|
-
this._timers.auth =
|
|
1253
|
+
this._timers.auth = undefined
|
|
1239
1254
|
|
|
1240
|
-
if(
|
|
1255
|
+
if( reject ) reject( new SipError( hangupcodes.FORBIDDEN, "Bad Auth" ))
|
|
1241
1256
|
|
|
1242
1257
|
return false
|
|
1243
1258
|
}
|
|
@@ -1255,11 +1270,11 @@ class call {
|
|
|
1255
1270
|
this.state.authed = true
|
|
1256
1271
|
await callstore.set( this )
|
|
1257
1272
|
|
|
1258
|
-
const
|
|
1259
|
-
this._promises.resolve.auth =
|
|
1260
|
-
this._promises.reject.auth =
|
|
1261
|
-
this._timers.auth =
|
|
1262
|
-
if(
|
|
1273
|
+
const resolve = this._promises.resolve.auth
|
|
1274
|
+
this._promises.resolve.auth = undefined
|
|
1275
|
+
this._promises.reject.auth = undefined
|
|
1276
|
+
this._timers.auth = undefined
|
|
1277
|
+
if( resolve ) resolve()
|
|
1263
1278
|
|
|
1264
1279
|
this._em.emit( "call.authed", this )
|
|
1265
1280
|
callmanager.options.em.emit( "call.authed", this )
|
|
@@ -1298,14 +1313,14 @@ class call {
|
|
|
1298
1313
|
if( this._promises.resolve.events ) {
|
|
1299
1314
|
const r = this._promises.resolve.events
|
|
1300
1315
|
|
|
1301
|
-
this._promises.resolve.events =
|
|
1302
|
-
this._promises.promise.events =
|
|
1316
|
+
this._promises.resolve.events = undefined
|
|
1317
|
+
this._promises.promise.events = undefined
|
|
1303
1318
|
r( ourmatch[ 0 ] )
|
|
1304
1319
|
}
|
|
1305
1320
|
|
|
1306
1321
|
if( this._timers.events ) {
|
|
1307
1322
|
clearTimeout( this._timers.events )
|
|
1308
|
-
this._timers.events =
|
|
1323
|
+
this._timers.events = undefined
|
|
1309
1324
|
}
|
|
1310
1325
|
}
|
|
1311
1326
|
}
|
|
@@ -1313,9 +1328,9 @@ class call {
|
|
|
1313
1328
|
|
|
1314
1329
|
/**
|
|
1315
1330
|
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..
|
|
1331
|
+
@param { string | RegExp } [match] - reg exp matching what is required from the user.
|
|
1332
|
+
@param { number } [timeout] - time to wait before giving up.
|
|
1333
|
+
@return { Promise } - the promise either resolves to a string if it matches or undefined if it times out..
|
|
1319
1334
|
*/
|
|
1320
1335
|
waitfortelevents( match = /[0-9A-D*#]/, timeout = 30000 ) {
|
|
1321
1336
|
|
|
@@ -1330,9 +1345,9 @@ class call {
|
|
|
1330
1345
|
this._promises.resolve.events()
|
|
1331
1346
|
}
|
|
1332
1347
|
|
|
1333
|
-
this._promises.resolve.events =
|
|
1334
|
-
this._promises.promise.events =
|
|
1335
|
-
this._timers.events =
|
|
1348
|
+
this._promises.resolve.events = undefined
|
|
1349
|
+
this._promises.promise.events = undefined
|
|
1350
|
+
this._timers.events = undefined
|
|
1336
1351
|
delete this.eventmatch
|
|
1337
1352
|
|
|
1338
1353
|
}, timeout )
|
|
@@ -1417,7 +1432,7 @@ class call {
|
|
|
1417
1432
|
/* we have already opened a channel (probably early now answering) */
|
|
1418
1433
|
this.channels.audio.remote( channeldef.remote )
|
|
1419
1434
|
} else {
|
|
1420
|
-
|
|
1435
|
+
|
|
1421
1436
|
await this.#openrelatedchannel( channeldef )
|
|
1422
1437
|
|
|
1423
1438
|
this.sdp.local = sdpgen.create()
|
|
@@ -1437,10 +1452,12 @@ class call {
|
|
|
1437
1452
|
}
|
|
1438
1453
|
|
|
1439
1454
|
/**
|
|
1440
|
-
*
|
|
1455
|
+
* @param { object } preferredcall - allow to specify a, not necessarily related call,
|
|
1456
|
+
* that can be used to open the new channel's node.
|
|
1457
|
+
*
|
|
1441
1458
|
* @returns { Promise }
|
|
1442
1459
|
*/
|
|
1443
|
-
async #choosecodecforanswer() {
|
|
1460
|
+
async #choosecodecforanswer( preferredcall = undefined ) {
|
|
1444
1461
|
if( this._req.msg && this._req.msg.body ) {
|
|
1445
1462
|
this.selectedcodec = this.sdp.remote.intersection( this.options.preferedcodecs, true )
|
|
1446
1463
|
if( !this.selectedcodec ) {
|
|
@@ -1467,6 +1484,8 @@ class call {
|
|
|
1467
1484
|
channeldef.remote.icepwd = this.sdp.remote.sdp.media[ 0 ].icePwd
|
|
1468
1485
|
}
|
|
1469
1486
|
|
|
1487
|
+
channeldef.preferredcall = preferredcall
|
|
1488
|
+
|
|
1470
1489
|
/* We might have already opened our audio when we received 183 (early). */
|
|
1471
1490
|
await this.#openchannelsforanswer( channeldef )
|
|
1472
1491
|
}
|
|
@@ -1474,16 +1493,18 @@ class call {
|
|
|
1474
1493
|
|
|
1475
1494
|
/**
|
|
1476
1495
|
* 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).
|
|
1496
|
+
* @param { object } [ options ]
|
|
1497
|
+
* @param { boolean } [ options.early ] - don't answer the channel (establish) but establish early media (respond to 183).
|
|
1498
|
+
* @param { object } [ options.preferredcall ]
|
|
1479
1499
|
*
|
|
1480
1500
|
* @return {Promise} Returns a promise which resolves if the call is answered, otherwise rejects the promise.
|
|
1481
1501
|
*/
|
|
1482
|
-
async answer( options = {} ) {
|
|
1502
|
+
async answer( options = { early: false, preferredcall: undefined } ) {
|
|
1483
1503
|
|
|
1484
1504
|
if( this.canceled || this.established ) return
|
|
1485
1505
|
|
|
1486
|
-
await this.#choosecodecforanswer()
|
|
1506
|
+
await this.#choosecodecforanswer( options.preferredcall )
|
|
1507
|
+
|
|
1487
1508
|
if( this.canceled ) return
|
|
1488
1509
|
|
|
1489
1510
|
if( options.early ) {
|
|
@@ -1555,12 +1576,12 @@ class call {
|
|
|
1555
1576
|
*/
|
|
1556
1577
|
|
|
1557
1578
|
if( this._timers.anyevent ) clearTimeout( this._timers.anyevent )
|
|
1558
|
-
this._timers.anyevent =
|
|
1579
|
+
this._timers.anyevent = undefined
|
|
1559
1580
|
|
|
1560
1581
|
const r = this._promises.resolve.channelevent
|
|
1561
|
-
this._promises.resolve.channelevent =
|
|
1562
|
-
this._promises.reject.channelevent =
|
|
1563
|
-
this._promises.promise.channelevent =
|
|
1582
|
+
this._promises.resolve.channelevent = undefined
|
|
1583
|
+
this._promises.reject.channelevent = undefined
|
|
1584
|
+
this._promises.promise.channelevent = undefined
|
|
1564
1585
|
if( r ) r( e )
|
|
1565
1586
|
}
|
|
1566
1587
|
|
|
@@ -1597,7 +1618,7 @@ class call {
|
|
|
1597
1618
|
|
|
1598
1619
|
A telephone event will resolve this promise as we typically need speech to be interupted
|
|
1599
1620
|
by the user. Note, peeking a telephone-event (i.e. DTMF) will not clear it like waitfortelevents will.
|
|
1600
|
-
@param {
|
|
1621
|
+
@param { object } constraints - event to filter for from our RTP server - excluding DTMF events - these will always return
|
|
1601
1622
|
*/
|
|
1602
1623
|
waitforanyevent( constraints, timeout = 500 ) {
|
|
1603
1624
|
|
|
@@ -1613,9 +1634,9 @@ class call {
|
|
|
1613
1634
|
|
|
1614
1635
|
this._timers.anyevent = setTimeout( () => {
|
|
1615
1636
|
const r = this._promises.resolve.channelevent
|
|
1616
|
-
this._promises.promise.channelevent =
|
|
1617
|
-
this._promises.resolve.channelevent =
|
|
1618
|
-
this._promises.reject.channelevent =
|
|
1637
|
+
this._promises.promise.channelevent = undefined
|
|
1638
|
+
this._promises.resolve.channelevent = undefined
|
|
1639
|
+
this._promises.reject.channelevent = undefined
|
|
1619
1640
|
if( r ) r( "timeout" )
|
|
1620
1641
|
}, timeout * 1000 )
|
|
1621
1642
|
|
|
@@ -2195,8 +2216,8 @@ class call {
|
|
|
2195
2216
|
@param { string } address - remote address (ip)
|
|
2196
2217
|
@param { number } port - remote port
|
|
2197
2218
|
@param { number } codec
|
|
2198
|
-
@param { string } fingerprint - remote sha 256 fingerprint
|
|
2199
|
-
@param { string } mode - "active"|"passive"
|
|
2219
|
+
@param { string } [ fingerprint ] - remote sha 256 fingerprint
|
|
2220
|
+
@param { string } [ mode ] - "active"|"passive"
|
|
2200
2221
|
*/
|
|
2201
2222
|
static _createchannelremotedef( address, port, codec, fingerprint, mode /* active|passive */ ) {
|
|
2202
2223
|
const chandef = {
|
|
@@ -2220,6 +2241,8 @@ class call {
|
|
|
2220
2241
|
|
|
2221
2242
|
/**
|
|
2222
2243
|
Sets our hangup cause correctly - if not already set.
|
|
2244
|
+
@param { string } src
|
|
2245
|
+
@param { object } [ reason ]
|
|
2223
2246
|
@private
|
|
2224
2247
|
*/
|
|
2225
2248
|
_sethangupcause( src, reason ) {
|
|
@@ -2250,24 +2273,24 @@ class call {
|
|
|
2250
2273
|
/* Clean up promises (ensure they are resolved) and clear any timers */
|
|
2251
2274
|
for ( const [ key, value ] of Object.entries( this._timers ) ) {
|
|
2252
2275
|
if( value ) clearTimeout( value )
|
|
2253
|
-
this._timers[ key ] =
|
|
2276
|
+
this._timers[ key ] = undefined
|
|
2254
2277
|
}
|
|
2255
2278
|
|
|
2256
2279
|
const authreject = this._promises.reject.auth
|
|
2257
|
-
this._promises.reject.auth =
|
|
2258
|
-
this._promises.resolve.auth =
|
|
2259
|
-
if( authreject ) authreject(
|
|
2280
|
+
this._promises.reject.auth = undefined
|
|
2281
|
+
this._promises.resolve.auth = undefined
|
|
2282
|
+
if( authreject ) authreject( new SipError( hangupcodes.REQUEST_TIMEOUT, "Auth timed out (cleanup)" ) )
|
|
2260
2283
|
|
|
2261
2284
|
const chanev = this._promises.reject.channelevent
|
|
2262
|
-
this._promises.resolve.channelevent =
|
|
2263
|
-
this._promises.reject.channelevent =
|
|
2264
|
-
this._promises.promise.channelevent =
|
|
2285
|
+
this._promises.resolve.channelevent = undefined
|
|
2286
|
+
this._promises.reject.channelevent = undefined
|
|
2287
|
+
this._promises.promise.channelevent = undefined
|
|
2265
2288
|
if( chanev ) chanev( Error( "Call hungup" ) )
|
|
2266
2289
|
|
|
2267
2290
|
const resolves = []
|
|
2268
2291
|
for ( const [ key, value ] of Object.entries( this._promises.resolve ) ) {
|
|
2269
2292
|
if( value ) resolves.push( value )
|
|
2270
|
-
this._promises.resolve[ key ] =
|
|
2293
|
+
this._promises.resolve[ key ] = undefined
|
|
2271
2294
|
}
|
|
2272
2295
|
|
|
2273
2296
|
/* Call outstanding resolves for promises - this will trigger out hangup promise also */
|
|
@@ -2286,8 +2309,8 @@ class call {
|
|
|
2286
2309
|
* Used by our frame to a) continue a hangup which has been initiated by either us or the network.
|
|
2287
2310
|
* Complete the hangup, including hanging up all children and waiting for them to complete their
|
|
2288
2311
|
* 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
|
|
2312
|
+
* @param { string } [ src ] - "us"|"wire"
|
|
2313
|
+
* @param { object } [ reason ] - one of the reasons from the hangupcodes enum - only used if we havn't alread set our reason
|
|
2291
2314
|
* @private
|
|
2292
2315
|
*/
|
|
2293
2316
|
async _onhangup( src = "us", reason ) {
|
|
@@ -2377,16 +2400,16 @@ class call {
|
|
|
2377
2400
|
}
|
|
2378
2401
|
|
|
2379
2402
|
await this._promises.promise.hangup
|
|
2380
|
-
this._promises.promise.hangup =
|
|
2381
|
-
this._promises.resolve.hangup =
|
|
2403
|
+
this._promises.promise.hangup = undefined
|
|
2404
|
+
this._promises.resolve.hangup = undefined
|
|
2382
2405
|
|
|
2383
2406
|
}
|
|
2384
2407
|
|
|
2385
2408
|
/**
|
|
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 {
|
|
2409
|
+
* Send an UPDATE. Use to updated called id, caller id, sdp etc. Send in dialog - TODO look how to send
|
|
2410
|
+
* early as this is recomended in the RFC.
|
|
2411
|
+
* @param { object } options
|
|
2412
|
+
* @param { entity } options.remote
|
|
2390
2413
|
*/
|
|
2391
2414
|
async update( options ) {
|
|
2392
2415
|
|
|
@@ -2454,19 +2477,23 @@ class call {
|
|
|
2454
2477
|
@summary Creates a new SIP dialog. Returns a promise which resolves
|
|
2455
2478
|
when the dialog is either answered (or cancelled for some reason).
|
|
2456
2479
|
The promise resolves to a new call is one is generated, or undefined if not.
|
|
2457
|
-
@param {
|
|
2480
|
+
@param { object } [ options ] - Options object. See default_options in index.js for more details.
|
|
2458
2481
|
@param { string } [ options.contact ] - The contact string
|
|
2459
2482
|
@param { boolean } [ options.orphan ] - If present and true then orphan the new call
|
|
2483
|
+
@param { object } [ options.auth ]
|
|
2460
2484
|
@param { string } [ options.auth.username ] - If SIP auth required username
|
|
2461
2485
|
@param { string } [ options.auth.password ] - If SIP auth required password
|
|
2462
2486
|
@param { object } [ options.headers ] - Object containing extra sip headers required.
|
|
2463
2487
|
@param { object } [ options.uactimeout ] - override the deault timeout
|
|
2464
2488
|
@param { boolean } [ options.late ] - late negotiation
|
|
2465
2489
|
@param { entity } [ options.entity ] - used to store this call against and look up a contact string if not supplied.
|
|
2490
|
+
@param { object } [ options.entity ]
|
|
2466
2491
|
@param { string } [ options.entity.username ]
|
|
2467
2492
|
@param { string } [ options.entity.realm ]
|
|
2468
2493
|
@param { string } [ options.entity.uri ]
|
|
2469
2494
|
@param { number } [ options.entity.max ] - if included no more than this number of calls for this entity (only if we look user up)
|
|
2495
|
+
@param { object } [ options.parent ] - the call we wish to become parent
|
|
2496
|
+
@param { object } [ options.preferredcall ] another related call which we may want to use the rtp host on
|
|
2470
2497
|
@param { object } [ callbacks ]
|
|
2471
2498
|
@param { earlycallback } [ callbacks.early ] - callback to provide a call object with early call (pre dialog)
|
|
2472
2499
|
@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 +2515,13 @@ class call {
|
|
|
2488
2515
|
|
|
2489
2516
|
options.headers[ "Max-Forwards" ] = maxforwards
|
|
2490
2517
|
|
|
2491
|
-
if( !options.orphan ) {
|
|
2518
|
+
if( !options.orphan && !options.parent ) {
|
|
2492
2519
|
options.parent = this
|
|
2520
|
+
|
|
2521
|
+
if ( !options.preferredcall )
|
|
2522
|
+
options.preferredcall = options.parent.channels.audio
|
|
2493
2523
|
}
|
|
2494
|
-
|
|
2524
|
+
|
|
2495
2525
|
return await call.newuac( options, callbacks )
|
|
2496
2526
|
}
|
|
2497
2527
|
|
|
@@ -2600,13 +2630,17 @@ class call {
|
|
|
2600
2630
|
* @param { object } [ channeldef ]
|
|
2601
2631
|
*/
|
|
2602
2632
|
async #openrelatedchannel( channeldef ) {
|
|
2603
|
-
|
|
2604
2633
|
const relatedcall = this.other
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2634
|
+
/* TODO: this is a hack. projectrtp has become too complicated with both a listen and connect
|
|
2635
|
+
mechanism. This is causing problems in code like this. There is no interface to
|
|
2636
|
+
detect which mode the channel is in - but the channels property will exist on a connect
|
|
2637
|
+
style channel. projectrtp will get a rewrite to support only one. */
|
|
2638
|
+
if( relatedcall && relatedcall.channels.audio && relatedcall.channels.audio.channels )
|
|
2639
|
+
this.channels.audio = await this.other.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2640
|
+
else if ( channeldef && channeldef.preferredcall && channeldef.preferredcall.channels && channeldef.preferredcall.channels.audio )
|
|
2641
|
+
this.channels.audio = await channeldef.preferredcall.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2642
|
+
else
|
|
2608
2643
|
this.channels.audio = await projectrtp.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2609
|
-
|
|
2610
2644
|
}
|
|
2611
2645
|
|
|
2612
2646
|
/**
|
|
@@ -2626,12 +2660,12 @@ class call {
|
|
|
2626
2660
|
/**
|
|
2627
2661
|
*
|
|
2628
2662
|
*/
|
|
2629
|
-
async #openchannelsfornewuac() {
|
|
2663
|
+
async #openchannelsfornewuac( channeldef = undefined ) {
|
|
2630
2664
|
if( this.options.late ) {
|
|
2631
2665
|
this.options.noAck = true /* this is a MUST for late negotiation */
|
|
2632
2666
|
} else {
|
|
2633
2667
|
|
|
2634
|
-
await this.#openrelatedchannel()
|
|
2668
|
+
await this.#openrelatedchannel( channeldef )
|
|
2635
2669
|
|
|
2636
2670
|
this.sdp.local = sdpgen.create().addcodecs( this.options.preferedcodecs )
|
|
2637
2671
|
this.sdp.local.setaudioport( this.channels.audio.local.port )
|
|
@@ -2785,6 +2819,7 @@ class call {
|
|
|
2785
2819
|
@param { object } [ options ] - Options object. See default_options in index.js for more details.
|
|
2786
2820
|
@param { call } [ options.parent ] - the parent call object
|
|
2787
2821
|
@param { string } [ options.contact ] - The contact string
|
|
2822
|
+
@param { object } [ options.auth ]
|
|
2788
2823
|
@param { string } [ options.auth.username ] - If SIP auth required username
|
|
2789
2824
|
@param { string } [ options.auth.password ] - If SIP auth required password
|
|
2790
2825
|
@param { object } [ options.headers ] - Object containing extra sip headers required.
|
|
@@ -2793,6 +2828,7 @@ class call {
|
|
|
2793
2828
|
@param { boolean } [ options.late ] - late negotiation
|
|
2794
2829
|
@param { boolean } [ options.privacy ] - sets the privacy
|
|
2795
2830
|
@param { entity } [ options.entity ] - used to store this call against and look up a contact string if not supplied.
|
|
2831
|
+
@param { object } [ options.entity ]}
|
|
2796
2832
|
@param { string } [ options.entity.username ]
|
|
2797
2833
|
@param { string } [ options.entity.realm ]
|
|
2798
2834
|
@param { string } [ options.entity.uri ]
|
|
@@ -2801,6 +2837,7 @@ class call {
|
|
|
2801
2837
|
@param { object } [ options.callerid ]
|
|
2802
2838
|
@param { string } [ options.callerid.number ]
|
|
2803
2839
|
@param { string } [ options.callerid.name ]
|
|
2840
|
+
@param { object } [ options.preferredcall ] another related call which we may want to use the rtp host on
|
|
2804
2841
|
@param { object } [ callbacks ]
|
|
2805
2842
|
@param { earlycallback } [ callbacks.early ] - callback to provide a call object with early call (pre dialog)
|
|
2806
2843
|
@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
|
|
@@ -2849,7 +2886,7 @@ class call {
|
|
|
2849
2886
|
newcall.options.headers = tmpheaders
|
|
2850
2887
|
|
|
2851
2888
|
newcall.#confignetwork( options )
|
|
2852
|
-
await newcall.#openchannelsfornewuac()
|
|
2889
|
+
await newcall.#openchannelsfornewuac( { "preferredcall" : options.preferredcall } )
|
|
2853
2890
|
|
|
2854
2891
|
let newdialog
|
|
2855
2892
|
try {
|
|
@@ -2926,7 +2963,7 @@ class call {
|
|
|
2926
2963
|
*/
|
|
2927
2964
|
#setdialog( d ) {
|
|
2928
2965
|
clearTimeout( this._timers.newuac )
|
|
2929
|
-
this._timers.newuac =
|
|
2966
|
+
this._timers.newuac = undefined
|
|
2930
2967
|
|
|
2931
2968
|
if( this.destroyedcancelledorhungup ) return
|
|
2932
2969
|
|
|
@@ -2962,7 +2999,7 @@ class call {
|
|
|
2962
2999
|
Create a new object when we receive an INVITE request.
|
|
2963
3000
|
|
|
2964
3001
|
@param { object } req - req object from drachtio
|
|
2965
|
-
@param {
|
|
3002
|
+
@param { object } res - res object from drachtio
|
|
2966
3003
|
@returns { Promise< call > }
|
|
2967
3004
|
*/
|
|
2968
3005
|
static async frominvite( req, res ) {
|
|
@@ -2990,7 +3027,7 @@ class call {
|
|
|
2990
3027
|
@private
|
|
2991
3028
|
*/
|
|
2992
3029
|
c._req = req
|
|
2993
|
-
c._req.on( "cancel", ( req ) => c._oncanceled( req ) )
|
|
3030
|
+
c._req.on( "cancel", ( /*req*/ ) => c._oncanceled( /*req*/ ) )
|
|
2994
3031
|
|
|
2995
3032
|
/**
|
|
2996
3033
|
@member
|
|
@@ -3024,13 +3061,11 @@ class call {
|
|
|
3024
3061
|
*/
|
|
3025
3062
|
set uactimeout( ms ) {
|
|
3026
3063
|
if( this.established ) return
|
|
3027
|
-
const msi = parseInt( ms )
|
|
3028
|
-
if( isNaN( msi ) ) return
|
|
3029
3064
|
|
|
3030
3065
|
clearTimeout( this._timers.newuac )
|
|
3031
3066
|
this._timers.newuac = setTimeout( () => {
|
|
3032
3067
|
this.hangup( hangupcodes.REQUEST_TIMEOUT )
|
|
3033
|
-
},
|
|
3068
|
+
}, ms )
|
|
3034
3069
|
}
|
|
3035
3070
|
}
|
|
3036
3071
|
|
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.9",
|
|
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
|
|