@babblevoice/babble-drachtio-callmanager 2.3.28 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +2 -1
- package/lib/call.js +350 -346
- package/package.json +1 -1
- package/test/interface/call.js +1 -1
- package/test/mock/srf.js +14 -14
- package/test/unit/call.js +2 -2
package/index.js
CHANGED
|
@@ -13,7 +13,8 @@ const default_options = {
|
|
|
13
13
|
"late": false, /* Late negotiation */
|
|
14
14
|
"registrar": false, /* our registrar object or falsey */
|
|
15
15
|
"referauthrequired": true,
|
|
16
|
-
"ignoreipv6candidates": true /* ipv6 does not work in projectrtp */
|
|
16
|
+
"ignoreipv6candidates": true, /* ipv6 does not work in projectrtp */
|
|
17
|
+
"privacy": false
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
/**
|
package/lib/call.js
CHANGED
|
@@ -103,11 +103,24 @@ class SipError extends Error {
|
|
|
103
103
|
|
|
104
104
|
/* Reverse codes - include inbound error codes.
|
|
105
105
|
If not in this list we return REQUEST_TERMINATED during creation */
|
|
106
|
+
/*
|
|
106
107
|
const inboundsiperros = {
|
|
107
108
|
486: hangupcodes.USER_BUSY,
|
|
108
109
|
408: hangupcodes.REQUEST_TIMEOUT,
|
|
109
|
-
404: hangupcodes.UNALLOCATED_NUMBER
|
|
110
|
+
404: hangupcodes.UNALLOCATED_NUMBER,
|
|
111
|
+
603: hangupcodes.DECLINED
|
|
110
112
|
}
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
const inboundsiperros = {}
|
|
117
|
+
const hangupcodeskeys = Object.keys( hangupcodes )
|
|
118
|
+
for (let i = 0; i < hangupcodeskeys.length; i++) {
|
|
119
|
+
const key = hangupcodeskeys[ i ]
|
|
120
|
+
const value = hangupcodes[ key ]
|
|
121
|
+
inboundsiperros[ value.sip ] = value
|
|
122
|
+
}
|
|
123
|
+
|
|
111
124
|
|
|
112
125
|
let callmanager = {
|
|
113
126
|
"options": {}
|
|
@@ -124,6 +137,8 @@ let callmanager = {
|
|
|
124
137
|
|
|
125
138
|
class call {
|
|
126
139
|
|
|
140
|
+
#noack = false
|
|
141
|
+
|
|
127
142
|
/**
|
|
128
143
|
* Construct our call object with all defaults, including a default UUID.
|
|
129
144
|
* @constructs call
|
|
@@ -138,8 +153,6 @@ class call {
|
|
|
138
153
|
*/
|
|
139
154
|
this.type = "uac"
|
|
140
155
|
|
|
141
|
-
this.privacy = false
|
|
142
|
-
|
|
143
156
|
/**
|
|
144
157
|
@typedef { Object } callstate
|
|
145
158
|
@property { boolean } trying
|
|
@@ -255,15 +268,6 @@ class call {
|
|
|
255
268
|
*/
|
|
256
269
|
this._entity
|
|
257
270
|
|
|
258
|
-
/**
|
|
259
|
-
Override caller id or name.
|
|
260
|
-
@private
|
|
261
|
-
*/
|
|
262
|
-
this._remote = {
|
|
263
|
-
"id": undefined,
|
|
264
|
-
"name": undefined
|
|
265
|
-
}
|
|
266
|
-
|
|
267
271
|
/**
|
|
268
272
|
* @summary contains network information regarding call
|
|
269
273
|
*/
|
|
@@ -327,25 +331,12 @@ class call {
|
|
|
327
331
|
*/
|
|
328
332
|
this._em = new events.EventEmitter()
|
|
329
333
|
|
|
330
|
-
/**
|
|
331
|
-
* @typedef { Object } options
|
|
332
|
-
* @property { string } [ contact ] contact string
|
|
333
|
-
* @property { string } [ preferedcodecs ] as it says
|
|
334
|
-
* @property { boolean } [ rfc2833 ] if set to true enable 2833
|
|
335
|
-
* @property { string } [ display ] how the user should be displayed
|
|
336
|
-
* @property { Array } [ headers ]
|
|
337
|
-
* @property { string } [ contactparams]
|
|
338
|
-
* @property { number | true } [ autoanswer ] autoanswer true or delay
|
|
339
|
-
* @property { number } [ uactimeout ] timeout in mS
|
|
340
|
-
* @property { boolean } [ late ] - do we use late negotiation
|
|
341
|
-
* @property { boolean } [ noAck ] do not use - converts our options into Drachtio options
|
|
342
|
-
* @property { string } [ localSdp ] do not use - what we pass into drachtio
|
|
343
|
-
*/
|
|
344
334
|
/**
|
|
345
335
|
* copy default
|
|
346
|
-
* @type {
|
|
336
|
+
* @type { calloptions }
|
|
347
337
|
*/
|
|
348
338
|
this.options = { ...callmanager.options }
|
|
339
|
+
this.options.headers = {}
|
|
349
340
|
|
|
350
341
|
/**
|
|
351
342
|
* @private
|
|
@@ -391,7 +382,7 @@ class call {
|
|
|
391
382
|
const entitycalls = await callstore.getbyentity( this._entity.uri )
|
|
392
383
|
let entitycallcount = 0
|
|
393
384
|
if( false !== entitycalls ) entitycallcount = entitycalls.size
|
|
394
|
-
|
|
385
|
+
|
|
395
386
|
return {
|
|
396
387
|
"username": this._entity.username,
|
|
397
388
|
"realm": this._entity.realm,
|
|
@@ -412,7 +403,7 @@ class call {
|
|
|
412
403
|
if( !e.uri && !( e.username && e.realm ) ) return
|
|
413
404
|
this._entity = e
|
|
414
405
|
|
|
415
|
-
this._entity.display = ""
|
|
406
|
+
if( !this._entity.display ) this._entity.display = ""
|
|
416
407
|
|
|
417
408
|
if( this._entity.uri ) {
|
|
418
409
|
if( !this._entity.username ) {
|
|
@@ -436,69 +427,6 @@ class call {
|
|
|
436
427
|
@property { string } type - "callerid" | "calledid"
|
|
437
428
|
*/
|
|
438
429
|
|
|
439
|
-
/**
|
|
440
|
-
* Sets caller id
|
|
441
|
-
* @param { string } callerid
|
|
442
|
-
*/
|
|
443
|
-
set callerid( callerid ) {
|
|
444
|
-
this._remote.id = callerid
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Sets caller id name
|
|
449
|
-
* @param { string } calleridname
|
|
450
|
-
*/
|
|
451
|
-
set calleridname( calleridname ) {
|
|
452
|
-
this._remote.name = calleridname
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
get callerid() {
|
|
456
|
-
return this._remote.id
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
get calleridname() {
|
|
460
|
-
return this._remote.name
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
*
|
|
465
|
-
* @returns { object }
|
|
466
|
-
*/
|
|
467
|
-
#getremoteuac() {
|
|
468
|
-
/* "Display Name" <sip:0123456789@bling.babblevoice.com>;party=calling;screen=yes;privacy=off */
|
|
469
|
-
if( this._entity ) {
|
|
470
|
-
return {
|
|
471
|
-
"name": this._entity.display,
|
|
472
|
-
"uri": this._entity.uri,
|
|
473
|
-
"user": this._entity.username,
|
|
474
|
-
"host": this._entity.realm,
|
|
475
|
-
"privacy": this.privacy,
|
|
476
|
-
"type": "calledid"
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
if( this.options && this.options.contact ) {
|
|
481
|
-
const parseduri = parseuri( this.options.contact )
|
|
482
|
-
return {
|
|
483
|
-
"name": "",
|
|
484
|
-
"uri": this.options.contact,
|
|
485
|
-
"user": parseduri.user,
|
|
486
|
-
"host": parseduri.host,
|
|
487
|
-
"privacy": this.privacy,
|
|
488
|
-
"type": "calledid"
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/* we shouldn't get here */
|
|
493
|
-
return {
|
|
494
|
-
"name": "",
|
|
495
|
-
"uri": "",
|
|
496
|
-
"user": "0000000000",
|
|
497
|
-
"host": "localhost.localdomain",
|
|
498
|
-
"privacy": this.privacy,
|
|
499
|
-
"type": "calledid"
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
430
|
|
|
503
431
|
/**
|
|
504
432
|
*
|
|
@@ -531,47 +459,171 @@ class call {
|
|
|
531
459
|
}
|
|
532
460
|
|
|
533
461
|
/**
|
|
462
|
+
* Remember: this is from the perspective of us - not the phone.
|
|
463
|
+
* The phone perspective is the opposite
|
|
464
|
+
* Inbound
|
|
465
|
+
* A call is received - i.e. we receive a SIP invite
|
|
534
466
|
*
|
|
535
|
-
*
|
|
467
|
+
* Outbound
|
|
468
|
+
* We make an outbound call. i.e. we send an INVITE
|
|
469
|
+
*
|
|
470
|
+
* Exceptions
|
|
471
|
+
* clicktocall - we send an INVITE but that is an inbound call
|
|
472
|
+
* so the invite is i nthe opposie direction.
|
|
473
|
+
* @returns { "inbound" | "outbound" }
|
|
536
474
|
*/
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
475
|
+
get direction() {
|
|
476
|
+
if( this.options.clicktocall ) return "inbound"
|
|
477
|
+
return "uas"==this.type?"inbound":"outbound"
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Returns the called object. i.e.
|
|
482
|
+
* If we are inbound then this is the destination
|
|
483
|
+
* If we are outbound then this is the entity we are calling
|
|
484
|
+
* @returns { remoteid }
|
|
485
|
+
*/
|
|
486
|
+
get calledid() {
|
|
487
|
+
|
|
488
|
+
const startingpoint = {
|
|
489
|
+
"name": "",
|
|
490
|
+
"uri": "",
|
|
491
|
+
"user": "0000000000",
|
|
492
|
+
"host": "localhost.localdomain",
|
|
493
|
+
"privacy": true === this.options.privacy,
|
|
494
|
+
"type": "calledid"
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if( "outbound" === this.direction ) {
|
|
498
|
+
if( this.parent ) {
|
|
499
|
+
const dest = this.parent.destination
|
|
500
|
+
startingpoint.user = dest.user
|
|
501
|
+
startingpoint.host = dest.host
|
|
502
|
+
} else {
|
|
503
|
+
const dest = parseuri( this.options.contact )
|
|
504
|
+
startingpoint.user = dest.user
|
|
505
|
+
startingpoint.host = dest.host
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
} else { /* inbound */
|
|
509
|
+
if( this.parent ) {
|
|
510
|
+
const dest = this.parent.destination
|
|
511
|
+
startingpoint.user = dest.user
|
|
512
|
+
startingpoint.host = dest.host
|
|
513
|
+
} else {
|
|
514
|
+
const dest = this.destination
|
|
515
|
+
startingpoint.user = dest.user
|
|
516
|
+
startingpoint.host = dest.host
|
|
549
517
|
}
|
|
550
|
-
} else {
|
|
551
|
-
parsed = this.#getremotefromheaders()
|
|
552
518
|
}
|
|
553
519
|
|
|
554
|
-
|
|
520
|
+
startingpoint.privacy = this.options.privacy
|
|
555
521
|
|
|
556
|
-
|
|
557
|
-
"
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
"type": "callerid"
|
|
522
|
+
if( this.options.calledid ) {
|
|
523
|
+
if( "number" in this.options.calledid ) {
|
|
524
|
+
startingpoint.user = this.options.calledid.number
|
|
525
|
+
startingpoint.uri = this.options.calledid.number + "@" + startingpoint.host
|
|
526
|
+
}
|
|
527
|
+
if( "name" in this.options.calledid ) startingpoint.name = this.options.calledid.name
|
|
563
528
|
}
|
|
529
|
+
|
|
530
|
+
return startingpoint
|
|
564
531
|
}
|
|
565
532
|
|
|
566
533
|
/**
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
get
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
534
|
+
* @returns { remoteid }
|
|
535
|
+
*/
|
|
536
|
+
// eslint-disable-next-line complexity
|
|
537
|
+
get callerid() {
|
|
538
|
+
|
|
539
|
+
let startingpoint = {
|
|
540
|
+
"name": "",
|
|
541
|
+
"uri": "",
|
|
542
|
+
"user": "0000000000",
|
|
543
|
+
"host": "localhost.localdomain",
|
|
544
|
+
"privacy": true === this.options.privacy,
|
|
545
|
+
"type": "callerid"
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if( "outbound" === this.direction ) {
|
|
549
|
+
if( this.parent ) {
|
|
550
|
+
startingpoint = this.parent.callerid
|
|
551
|
+
} else {
|
|
552
|
+
const parseduri = parseuri( this.options.contact )
|
|
553
|
+
if( parseduri.user ) {
|
|
554
|
+
startingpoint.uri = this.options.contact
|
|
555
|
+
startingpoint.user = parseduri.user
|
|
556
|
+
startingpoint.host = parseduri.host
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} else { /* inbound */
|
|
560
|
+
if( this._entity ) {
|
|
561
|
+
startingpoint.name = this._entity.display
|
|
562
|
+
startingpoint.uri = this._entity.uri
|
|
563
|
+
startingpoint.user = this._entity.username
|
|
564
|
+
startingpoint.host = this._entity.realm
|
|
565
|
+
} else {
|
|
566
|
+
let parsed = this.#getremotefromheaders()
|
|
567
|
+
parsed = this.#fixparseduriobj( parsed )
|
|
568
|
+
|
|
569
|
+
startingpoint.uri = parsed.uri
|
|
570
|
+
startingpoint.user = parsed.user
|
|
571
|
+
startingpoint.host = parsed.host
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if( this.options.callerid ) {
|
|
576
|
+
if( "number" in this.options.callerid ) startingpoint.user = this.options.callerid.number
|
|
577
|
+
if( "name" in this.options.callerid ) startingpoint.name = this.options.callerid.name
|
|
578
|
+
if( "host" in this.options.callerid ) startingpoint.host = this.options.callerid.host
|
|
574
579
|
}
|
|
580
|
+
|
|
581
|
+
return startingpoint
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* @param { string } c
|
|
586
|
+
*/
|
|
587
|
+
set callerid( c ) {
|
|
588
|
+
if( !this.options.callerid ) this.options.callerid = {}
|
|
589
|
+
if( !this.options.callerid.number ) this.options.callerid.number = ""
|
|
590
|
+
|
|
591
|
+
this.options.callerid.number = c
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* @param { string } c
|
|
596
|
+
*/
|
|
597
|
+
set calleridname( c ) {
|
|
598
|
+
|
|
599
|
+
if( !this.options.callerid ) this.options.callerid = {}
|
|
600
|
+
if( !this.options.callerid.name ) this.options.callerid.name = ""
|
|
601
|
+
|
|
602
|
+
this.options.callerid.name = c
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* @param { string } c
|
|
607
|
+
*/
|
|
608
|
+
set calledid( c ) {
|
|
609
|
+
|
|
610
|
+
if( !this.options.calledid ) this.options.calledid = {}
|
|
611
|
+
if( !this.options.calledid.number ) this.options.calledid.number = ""
|
|
612
|
+
if( !this.options.calledid.name ) this.options.calledid.name = ""
|
|
613
|
+
|
|
614
|
+
this.options.calledid.number = c
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* @param { string } c
|
|
619
|
+
*/
|
|
620
|
+
set calledidname( c ) {
|
|
621
|
+
|
|
622
|
+
if( !this.options.calledid ) this.options.calledid = {}
|
|
623
|
+
if( !this.options.calledid.number ) this.options.calledid.number = ""
|
|
624
|
+
if( !this.options.calledid.name ) this.options.calledid.name = ""
|
|
625
|
+
|
|
626
|
+
this.options.calledid.name = c
|
|
575
627
|
}
|
|
576
628
|
|
|
577
629
|
/**
|
|
@@ -845,6 +897,12 @@ class call {
|
|
|
845
897
|
@type {call}
|
|
846
898
|
*/
|
|
847
899
|
|
|
900
|
+
/**
|
|
901
|
+
Emitted when a call is answered
|
|
902
|
+
@event call.updated
|
|
903
|
+
@type {call}
|
|
904
|
+
*/
|
|
905
|
+
|
|
848
906
|
/**
|
|
849
907
|
Emitted when a call is mixed with another call (not after unhold as this has it's own event)
|
|
850
908
|
@event call.mix
|
|
@@ -941,7 +999,7 @@ class call {
|
|
|
941
999
|
this.children.add( other )
|
|
942
1000
|
|
|
943
1001
|
/* maintain privacy */
|
|
944
|
-
other.privacy = this.privacy
|
|
1002
|
+
other.options.privacy = this.options.privacy
|
|
945
1003
|
|
|
946
1004
|
if( mix ) {
|
|
947
1005
|
this.channels.audio.mix( other.channels.audio )
|
|
@@ -1656,7 +1714,7 @@ class call {
|
|
|
1656
1714
|
* @returns { Promise } resolves on timeout or when unmix happens
|
|
1657
1715
|
* @private
|
|
1658
1716
|
*/
|
|
1659
|
-
_hold( direction = "
|
|
1717
|
+
_hold( direction = "recvonly" ) {
|
|
1660
1718
|
|
|
1661
1719
|
if( this.state.held ) return
|
|
1662
1720
|
this.state.held = true
|
|
@@ -2356,13 +2414,16 @@ class call {
|
|
|
2356
2414
|
/* Call outstanding resolves for promises - this will trigger out hangup promise also */
|
|
2357
2415
|
resolves.forEach( r => r( this ) )
|
|
2358
2416
|
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2417
|
+
callstore.delete( this ).then( () => {
|
|
2418
|
+
this._em.emit( "call.destroyed", this )
|
|
2419
|
+
callmanager.options.em.emit( "call.destroyed", this )
|
|
2420
|
+
|
|
2421
|
+
this._em.emit( "call.reporting", this )
|
|
2422
|
+
callmanager.options.em.emit( "call.reporting", this )
|
|
2364
2423
|
|
|
2365
|
-
|
|
2424
|
+
this.removealllisteners()
|
|
2425
|
+
return 0
|
|
2426
|
+
} ).catch( () => {} )
|
|
2366
2427
|
}
|
|
2367
2428
|
|
|
2368
2429
|
/**
|
|
@@ -2392,8 +2453,6 @@ class call {
|
|
|
2392
2453
|
await Promise.all( hangups )
|
|
2393
2454
|
}
|
|
2394
2455
|
|
|
2395
|
-
await callstore.delete( this )
|
|
2396
|
-
|
|
2397
2456
|
this._sethangupcause( src, reason )
|
|
2398
2457
|
|
|
2399
2458
|
/* flag destroyed so when we receive our close event we know what to do */
|
|
@@ -2422,9 +2481,6 @@ class call {
|
|
|
2422
2481
|
return
|
|
2423
2482
|
}
|
|
2424
2483
|
this._state._hangup = true
|
|
2425
|
-
|
|
2426
|
-
await callstore.delete( this )
|
|
2427
|
-
|
|
2428
2484
|
this._sethangupcause( "us", reason )
|
|
2429
2485
|
|
|
2430
2486
|
if( this.state.established ) {
|
|
@@ -2468,10 +2524,15 @@ class call {
|
|
|
2468
2524
|
/**
|
|
2469
2525
|
* Send an UPDATE. Use to updated called id, caller id, sdp etc. Send in dialog - TODO look how to send
|
|
2470
2526
|
* early as this is recomended in the RFC.
|
|
2471
|
-
* @param { object } options
|
|
2472
|
-
* @param { entity } options.remote
|
|
2473
2527
|
*/
|
|
2474
|
-
async update(
|
|
2528
|
+
async update() {
|
|
2529
|
+
|
|
2530
|
+
/* if we are asked to update it suggests we have received new information and overrides should go */
|
|
2531
|
+
delete this.options.callerid
|
|
2532
|
+
delete this.options.calledid
|
|
2533
|
+
|
|
2534
|
+
this._em.emit( "call.updated", this )
|
|
2535
|
+
callmanager.options.em.emit( "call.updated", this )
|
|
2475
2536
|
|
|
2476
2537
|
if( !this._dialog ) {
|
|
2477
2538
|
console.trace( "Early update not currently supported" )
|
|
@@ -2488,77 +2549,23 @@ class call {
|
|
|
2488
2549
|
requestoptions.body = this.sdp.local.toString()
|
|
2489
2550
|
}
|
|
2490
2551
|
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
let name = ""
|
|
2494
|
-
let user = "0000000000"
|
|
2495
|
-
let realm = "localhost.localdomain"
|
|
2496
|
-
|
|
2497
|
-
if( options && options.remote ) {
|
|
2498
|
-
name = options.remote.display.replace( /[^\w\-\s']+/g, "" ) /* only allow alpa num whitespace and ' */
|
|
2499
|
-
realm = options.remote.realm
|
|
2500
|
-
user = options.remote.username
|
|
2501
|
-
} else {
|
|
2502
|
-
const other = this.other
|
|
2503
|
-
if( other ) {
|
|
2504
|
-
const remote = other.remote
|
|
2505
|
-
name = remote.name.replace( /[^\w\-\s']+/g, "" ) /* only allow alpa num whitespace and ' */
|
|
2506
|
-
realm = remote.host
|
|
2507
|
-
user = remote.user
|
|
2508
|
-
}
|
|
2509
|
-
}
|
|
2552
|
+
this.#configcalleridfornewuac()
|
|
2510
2553
|
|
|
2511
|
-
|
|
2512
|
-
const remoteid = `"${name}" <sip:${user}@${realm}>`
|
|
2513
|
-
requestoptions.headers[ "P-Asserted-Identity" ] = remoteid
|
|
2514
|
-
requestoptions.headers[ "FROM" ] = remoteid
|
|
2554
|
+
this._dialog.request( { ...this.options, ...requestoptions } )
|
|
2515
2555
|
|
|
2516
|
-
this._dialog.request( requestoptions )
|
|
2517
2556
|
return true
|
|
2518
2557
|
}
|
|
2519
2558
|
|
|
2520
|
-
/**
|
|
2521
|
-
@callback earlycallback
|
|
2522
|
-
@param { call } call - our call object which is early
|
|
2523
|
-
*/
|
|
2524
2559
|
|
|
2525
|
-
/**
|
|
2526
|
-
@callback confirmcallback
|
|
2527
|
-
@async
|
|
2528
|
-
@param { call } call - our call object which is early
|
|
2529
|
-
*/
|
|
2530
|
-
|
|
2531
|
-
/**
|
|
2532
|
-
@callback failcallback
|
|
2533
|
-
@param { call } call - our call object which is early
|
|
2534
|
-
*/
|
|
2535
2560
|
|
|
2536
2561
|
/**
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
@param { string } [ options.auth.username ] - If SIP auth required username
|
|
2545
|
-
@param { string } [ options.auth.password ] - If SIP auth required password
|
|
2546
|
-
@param { object } [ options.headers ] - Object containing extra sip headers required.
|
|
2547
|
-
@param { object } [ options.uactimeout ] - override the deault timeout
|
|
2548
|
-
@param { boolean } [ options.late ] - late negotiation
|
|
2549
|
-
@param { entity } [ options.entity ] - used to store this call against and look up a contact string if not supplied.
|
|
2550
|
-
@param { object } [ options.entity ]
|
|
2551
|
-
@param { string } [ options.entity.username ]
|
|
2552
|
-
@param { string } [ options.entity.realm ]
|
|
2553
|
-
@param { string } [ options.entity.uri ]
|
|
2554
|
-
@param { number } [ options.entity.max ] - if included no more than this number of calls for this entity (only if we look user up)
|
|
2555
|
-
@param { object } [ options.parent ] - the call we wish to become parent
|
|
2556
|
-
@param { object } [ callbacks ]
|
|
2557
|
-
@param { earlycallback } [ callbacks.early ] - callback to provide a call object with early call (pre dialog)
|
|
2558
|
-
@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
|
|
2559
|
-
@param { failcallback } [ callbacks.fail ] - Called when child is terminated
|
|
2560
|
-
@return { Promise< call | false > } - returns a promise which resolves to a new call object if a dialog has been confirmed. If none are confirmed ten return false. Each attempt is fed into callbacks.early.
|
|
2561
|
-
*/
|
|
2562
|
+
* @summary Creates a new SIP dialog. Returns a promise which resolves
|
|
2563
|
+
* when the dialog is either answered (or cancelled for some reason).
|
|
2564
|
+
* The promise resolves to a new call is one is generated, or undefined if not.
|
|
2565
|
+
* @param { calloptions } [ options ] - Options object. See default_options in index.js for more details.
|
|
2566
|
+
* @param { newuaccallbacks } [ callbacks ]
|
|
2567
|
+
* @return { Promise< call | false > } - returns a promise which resolves to a new call object if a dialog has been confirmed. If none are confirmed ten return false. Each attempt is fed into callbacks.early.
|
|
2568
|
+
*/
|
|
2562
2569
|
async newuac( options, callbacks = {} ) {
|
|
2563
2570
|
|
|
2564
2571
|
/* If max-forwards is not specified then we decrement the parent and pass on */
|
|
@@ -2658,7 +2665,7 @@ class call {
|
|
|
2658
2665
|
if( callbacks.confirm ) callbacks.confirm( c )
|
|
2659
2666
|
}
|
|
2660
2667
|
}
|
|
2661
|
-
|
|
2668
|
+
|
|
2662
2669
|
for( const contact of contactinfo.contacts ) {
|
|
2663
2670
|
if( undefined === contact ) continue
|
|
2664
2671
|
const newoptions = { ...options }
|
|
@@ -2728,7 +2735,7 @@ class call {
|
|
|
2728
2735
|
*/
|
|
2729
2736
|
async #openchannelsfornewuac( channeldef = undefined ) {
|
|
2730
2737
|
if( this.options.late ) {
|
|
2731
|
-
this
|
|
2738
|
+
this.#noack = true /* this is a MUST for late negotiation */
|
|
2732
2739
|
} else {
|
|
2733
2740
|
|
|
2734
2741
|
await this.#openrelatedchannel( channeldef )
|
|
@@ -2749,9 +2756,6 @@ class call {
|
|
|
2749
2756
|
.addicecandidates( this.channels.audio.local.address, this.channels.audio.local.port, this.channels.audio.local.icepwd )
|
|
2750
2757
|
.rtcpmux()
|
|
2751
2758
|
}
|
|
2752
|
-
|
|
2753
|
-
/* Create our SDP */
|
|
2754
|
-
this.options.localSdp = this.sdp.local.toString()
|
|
2755
2759
|
}
|
|
2756
2760
|
}
|
|
2757
2761
|
|
|
@@ -2781,13 +2785,17 @@ class call {
|
|
|
2781
2785
|
|
|
2782
2786
|
this.sip.tags.remote = this._dialog.sip.remoteTag
|
|
2783
2787
|
|
|
2784
|
-
if( true === this
|
|
2788
|
+
if( true === this.#noack ) {
|
|
2785
2789
|
await this._onlatebridge()
|
|
2786
2790
|
} else {
|
|
2787
2791
|
await this._onearlybridge()
|
|
2788
2792
|
}
|
|
2789
2793
|
|
|
2790
2794
|
if( callbacks.confirm ) await callbacks.confirm( this )
|
|
2795
|
+
|
|
2796
|
+
this._em.emit( "call.answered", this )
|
|
2797
|
+
callmanager.options.em.emit( "call.answered", this )
|
|
2798
|
+
|
|
2791
2799
|
return this
|
|
2792
2800
|
}
|
|
2793
2801
|
|
|
@@ -2810,55 +2818,26 @@ class call {
|
|
|
2810
2818
|
}
|
|
2811
2819
|
|
|
2812
2820
|
/**
|
|
2813
|
-
*
|
|
2814
|
-
* @param { object } options
|
|
2821
|
+
* @returns { object }
|
|
2815
2822
|
*/
|
|
2816
|
-
|
|
2817
|
-
#configcalleridfornewuac( options ) {
|
|
2818
|
-
let name = ""
|
|
2819
|
-
let user = "0000000000"
|
|
2820
|
-
let realm = "localhost.localdomain"
|
|
2821
|
-
|
|
2822
|
-
if( options.parent ) {
|
|
2823
|
-
const remote = options.parent.remote
|
|
2824
|
-
if( remote ) {
|
|
2825
|
-
name = remote.name.replace( /[^\w\-\s']+/g, "" ) /* only allow alpa num whitespace and ' */
|
|
2826
|
-
realm = remote.host
|
|
2827
|
-
user = remote.user
|
|
2828
|
-
}
|
|
2829
|
-
|
|
2830
|
-
if( this.parent.callerid ) {
|
|
2831
|
-
if ( this.parent.callerid.number ) user = this.parent.callerid.number
|
|
2832
|
-
}
|
|
2823
|
+
#configcalleridfornewuac() {
|
|
2833
2824
|
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
}
|
|
2837
|
-
} else if( this._entity ) {
|
|
2838
|
-
if( this._entity.username ) user = this._entity.username
|
|
2839
|
-
if( this._entity.realm ) realm = this._entity.realm
|
|
2840
|
-
if( this._entity.display ) name = this._entity.display
|
|
2841
|
-
}
|
|
2825
|
+
const callerid = this.callerid
|
|
2826
|
+
const calleridstr = `"${callerid.name}" <sip:${callerid.user}@${callerid.host}>`
|
|
2842
2827
|
|
|
2843
|
-
|
|
2844
|
-
if( options.
|
|
2845
|
-
|
|
2846
|
-
user = options.callerid.number
|
|
2847
|
-
this.callerid = user
|
|
2848
|
-
}
|
|
2849
|
-
|
|
2850
|
-
if( options.callerid.name ) {
|
|
2851
|
-
name = options.callerid.name
|
|
2852
|
-
this.calleridname = name
|
|
2853
|
-
}
|
|
2828
|
+
let privacy = ""
|
|
2829
|
+
if( true === this.options.privacy ) {
|
|
2830
|
+
privacy = ";privacy=full"
|
|
2854
2831
|
}
|
|
2855
2832
|
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2833
|
+
/*
|
|
2834
|
+
RFC 3325 - should we also consider the P-Preferred-Identity header?
|
|
2835
|
+
P-Asserted-Identity?
|
|
2836
|
+
*/
|
|
2837
|
+
this.options.headers[ "Remote-Party-ID" ] = calleridstr + ";party=calling;screen=yes" + privacy
|
|
2838
|
+
this.options.headers[ "From" ] = calleridstr
|
|
2860
2839
|
|
|
2861
|
-
return { user, realm }
|
|
2840
|
+
return { user: callerid.user, realm: callerid.host }
|
|
2862
2841
|
}
|
|
2863
2842
|
|
|
2864
2843
|
/**
|
|
@@ -2869,6 +2848,8 @@ class call {
|
|
|
2869
2848
|
|
|
2870
2849
|
const parts = parseuri( contactstr )
|
|
2871
2850
|
|
|
2851
|
+
if( this.options.clicktocall ) this.options.autoanswer = true
|
|
2852
|
+
|
|
2872
2853
|
if( !this.options.contactparams ) this.options.contactparams = ""
|
|
2873
2854
|
if( true === this.options.autoanswer ) {
|
|
2874
2855
|
this.options.headers[ "Call-Info" ] = `<sip:${parts.host}>;answer-after=0`
|
|
@@ -2919,38 +2900,70 @@ class call {
|
|
|
2919
2900
|
}
|
|
2920
2901
|
|
|
2921
2902
|
/**
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2903
|
+
* @typedef { object } calloptions
|
|
2904
|
+
* @property { call } [ parent ] - the parent call object
|
|
2905
|
+
* @property { boolean } [ orphan ] - orphan this call once made
|
|
2906
|
+
* @property { string } [ contact ] - The contact string
|
|
2907
|
+
* @property { string } [ preferedcodecs ] as it says
|
|
2908
|
+
* @property { boolean } [ rfc2833 ] if set to true enable 2833
|
|
2909
|
+
* @property { string } [ contactparams ] - additional params to add to the contact string in the invite
|
|
2910
|
+
* @property { object } [ auth ]
|
|
2911
|
+
* @property { string } [ auth.username ] - If SIP auth required username
|
|
2912
|
+
* @property { string } [ auth.password ] - If SIP auth required password
|
|
2913
|
+
* @property { object } [ headers ] - Object containing extra sip headers required.
|
|
2914
|
+
* @property { object } [ uactimeout ] - override the deault timeout
|
|
2915
|
+
* @property { true | number } [ autoanswer ] - if true add call-info to auto answer, if number delay to add
|
|
2916
|
+
* @property { boolean } [ clicktocall ] - if set to true, will set autoanswer to true and swap the source and desination on caller ID
|
|
2917
|
+
* @property { boolean } [ late ] - late negotiation
|
|
2918
|
+
* @property { boolean } [ privacy ] - sets the privacy
|
|
2919
|
+
* @property { entity } [ entity ] - used to store this call against and look up a contact string if not supplied.
|
|
2920
|
+
* @property { object } [ entity ]
|
|
2921
|
+
* @property { string } [ entity.username ]
|
|
2922
|
+
* @property { string } [ entity.realm ]
|
|
2923
|
+
* @property { string } [ entity.uri ]
|
|
2924
|
+
* @property { number } [ entity.max ] - if included no more than this number of calls for this entity (only if we look user up)
|
|
2925
|
+
* @property { number } [ entity.first ] - if multiple contacts for this entity use the first only
|
|
2926
|
+
* @property { object } [ callerid ]
|
|
2927
|
+
* @property { string } [ callerid.number ]
|
|
2928
|
+
* @property { string } [ callerid.name ]
|
|
2929
|
+
* @property { string } [ callerid.host ]
|
|
2930
|
+
* @property { object } [ calledid ]
|
|
2931
|
+
* @property { string } [ calledid.number ]
|
|
2932
|
+
* @property { string } [ calledid.name ]
|
|
2933
|
+
* @property { call } [ bond ] - other channel to bond to for pottential channel pairing
|
|
2934
|
+
*/
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* @callback earlycallback
|
|
2938
|
+
* @param { call } call - our call object which is early
|
|
2953
2939
|
*/
|
|
2940
|
+
|
|
2941
|
+
/**
|
|
2942
|
+
* @callback confirmcallback
|
|
2943
|
+
* @async
|
|
2944
|
+
* @param { call } call - our call object which is early
|
|
2945
|
+
*/
|
|
2946
|
+
|
|
2947
|
+
/**
|
|
2948
|
+
* @callback failcallback
|
|
2949
|
+
* @param { call } call - our call object which is early
|
|
2950
|
+
*/
|
|
2951
|
+
|
|
2952
|
+
/**
|
|
2953
|
+
* @typedef { object } newuaccallbacks
|
|
2954
|
+
* @property { earlycallback } [ early ] - callback to provide a call object with early call (pre dialog)
|
|
2955
|
+
* @property { confirmcallback } [ 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
|
|
2956
|
+
* @property { failcallback } [ fail ] - Called when child is terminated
|
|
2957
|
+
*/
|
|
2958
|
+
|
|
2959
|
+
/**
|
|
2960
|
+
* @summary Creates a new SIP dialog(s). Returns a promise which resolves
|
|
2961
|
+
* when the dialog is either answered (or cancelled for some reason).
|
|
2962
|
+
* The promise resolves to a new call is one is generated, or undefined if not.
|
|
2963
|
+
* @param { calloptions } [ options ] - Options object. See default_options in index.js for more details.
|
|
2964
|
+
* @param { newuaccallbacks } [ callbacks ]
|
|
2965
|
+
* @return { Promise< call | false > } - returns a promise which resolves to a new call object if a dialog has been confirmed. If none are confirmed then return false. Each attempt is fed into callbacks.early.
|
|
2966
|
+
*/
|
|
2954
2967
|
static async newuac( options, callbacks = {} ) {
|
|
2955
2968
|
|
|
2956
2969
|
if( !options.contact && !options.entity ) return false
|
|
@@ -2969,31 +2982,19 @@ class call {
|
|
|
2969
2982
|
|
|
2970
2983
|
newcall.bond( options.bond )
|
|
2971
2984
|
|
|
2972
|
-
newcall.options = {
|
|
2973
|
-
headers: { ...options.headers }
|
|
2974
|
-
}
|
|
2975
|
-
|
|
2976
2985
|
if( options.entity ) {
|
|
2977
2986
|
newcall.entity = options.entity
|
|
2978
2987
|
callstore.set( newcall )
|
|
2979
2988
|
}
|
|
2980
2989
|
|
|
2981
|
-
if( options.privacy ) this.privacy = true
|
|
2982
|
-
|
|
2983
|
-
newcall.#configcalleridfornewuac( options )
|
|
2984
|
-
|
|
2985
|
-
// Polycom
|
|
2986
|
-
// Alert-Info: <https://www.babblevoice.com/polycom/LoudRing.wav>
|
|
2987
|
-
// Vtech
|
|
2988
|
-
// Alert-Info: <http://www.babblevoice.com>;info=ringer2
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
2990
|
// spread is not recursive
|
|
2991
|
+
newcall.options = { ...newcall.options, ...options }
|
|
2992
2992
|
const tmpheaders = { ...callmanager.options.headers, ...newcall.options.headers, ...options.headers }
|
|
2993
|
-
newcall.options = { ...callmanager.options, ...newcall.options, ...options }
|
|
2994
2993
|
newcall.options.headers = tmpheaders
|
|
2994
|
+
|
|
2995
|
+
newcall.#configcalleridfornewuac()
|
|
2995
2996
|
newcall.import()
|
|
2996
|
-
|
|
2997
|
+
|
|
2997
2998
|
newcall.#configautoanswerfornewuac( options.contact )
|
|
2998
2999
|
|
|
2999
3000
|
newcall.options.headers[ "Allow-Events" ] = "talk, hold, presence, as-feature-event, dialog, call-info, sla, include-session-description, message-summary, refer"
|
|
@@ -3005,56 +3006,59 @@ class call {
|
|
|
3005
3006
|
|
|
3006
3007
|
let newdialog
|
|
3007
3008
|
try {
|
|
3008
|
-
newdialog = await callmanager.options.srf.createUAC(
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3009
|
+
newdialog = await callmanager.options.srf.createUAC(
|
|
3010
|
+
options.contact + newcall.options.contactparams,
|
|
3011
|
+
{ ...newcall.options, ...{ localSdp: newcall.sdp.local?newcall.sdp.local.toString():"" } }, {
|
|
3012
|
+
|
|
3013
|
+
cbRequest: ( err, req ) => {
|
|
3014
|
+
|
|
3015
|
+
if( !req ) {
|
|
3016
|
+
newcall.state.destroyed = true
|
|
3017
|
+
newcall.hangup( hangupcodes.SERVER_ERROR )
|
|
3018
|
+
console.trace( "No req object??", err )
|
|
3019
|
+
return
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
/* set new uac timeout */
|
|
3023
|
+
newcall.uactimeout = newcall.options.uactimeout
|
|
3024
|
+
|
|
3025
|
+
/* extend our parent ring timeout if necasary */
|
|
3026
|
+
if( options.parent ) {
|
|
3027
|
+
options.parent.uactimeout = Math.max( callmanager.options.uactimeout, newcall.options.uactimeout )
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
newcall._req = req
|
|
3031
|
+
newcall.state.trying = true
|
|
3032
|
+
|
|
3033
|
+
newcall.sip = {
|
|
3034
|
+
"callid": req.getParsedHeader( "call-id" ),
|
|
3035
|
+
"tags": {
|
|
3036
|
+
"local": req.getParsedHeader( "from" ).params.tag,
|
|
3037
|
+
"remote": ""
|
|
3038
|
+
},
|
|
3039
|
+
"contact": [ { "uri": options.contact } ]
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
callstore.set( newcall )
|
|
3043
|
+
if( callbacks && callbacks.early ) callbacks.early( newcall )
|
|
3044
|
+
callmanager.options.em.emit( "call.new", newcall )
|
|
3045
|
+
},
|
|
3046
|
+
cbProvisional: async ( res ) => {
|
|
3047
|
+
newcall._res = res
|
|
3048
|
+
|
|
3049
|
+
newcall.parseallow( res )
|
|
3050
|
+
|
|
3051
|
+
if( 180 === res.status ) {
|
|
3052
|
+
newcall._onring()
|
|
3053
|
+
} else if( 183 === res.status ) {
|
|
3054
|
+
await newcall._onearly()
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
if( newcall.canceled ) {
|
|
3058
|
+
newcall.hangup()
|
|
3059
|
+
}
|
|
3024
3060
|
}
|
|
3025
|
-
|
|
3026
|
-
newcall._req = req
|
|
3027
|
-
newcall.state.trying = true
|
|
3028
|
-
|
|
3029
|
-
newcall.sip = {
|
|
3030
|
-
"callid": req.getParsedHeader( "call-id" ),
|
|
3031
|
-
"tags": {
|
|
3032
|
-
"local": req.getParsedHeader( "from" ).params.tag,
|
|
3033
|
-
"remote": ""
|
|
3034
|
-
},
|
|
3035
|
-
"contact": [ { "uri": options.contact } ]
|
|
3036
|
-
}
|
|
3037
|
-
|
|
3038
|
-
callstore.set( newcall )
|
|
3039
|
-
if( callbacks && callbacks.early ) callbacks.early( newcall )
|
|
3040
|
-
callmanager.options.em.emit( "call.new", newcall )
|
|
3041
|
-
},
|
|
3042
|
-
cbProvisional: async ( res ) => {
|
|
3043
|
-
newcall._res = res
|
|
3044
|
-
|
|
3045
|
-
newcall.parseallow( res )
|
|
3046
|
-
|
|
3047
|
-
if( 180 === res.status ) {
|
|
3048
|
-
newcall._onring()
|
|
3049
|
-
} else if( 183 === res.status ) {
|
|
3050
|
-
await newcall._onearly()
|
|
3051
|
-
}
|
|
3052
|
-
|
|
3053
|
-
if( newcall.canceled ) {
|
|
3054
|
-
newcall.hangup()
|
|
3055
|
-
}
|
|
3056
|
-
}
|
|
3057
|
-
} )
|
|
3061
|
+
} )
|
|
3058
3062
|
} catch ( err ) {
|
|
3059
3063
|
newcall.#onnewuaccatch( err )
|
|
3060
3064
|
}
|
package/package.json
CHANGED
package/test/interface/call.js
CHANGED
|
@@ -786,7 +786,7 @@ describe( "call object", function() {
|
|
|
786
786
|
await call.newuac( options, { "early": ( c ) => c.hangup() } )
|
|
787
787
|
|
|
788
788
|
expect( createuacoptions.headers[ "Remote-Party-ID" ] ).to.equal( "\"\" <sip:0000000000@localhost.localdomain>" )
|
|
789
|
-
expect( createuacoptions.
|
|
789
|
+
expect( createuacoptions.late ).to.be.true
|
|
790
790
|
} )
|
|
791
791
|
|
|
792
792
|
it( "uas.newuac - early callback is called", async function() {
|
package/test/mock/srf.js
CHANGED
|
@@ -7,7 +7,7 @@ const events = require( "events" )
|
|
|
7
7
|
const call = require( "../../lib/call.js" )
|
|
8
8
|
const callmanager = require( "../../index.js" )
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const possiblesdp = [
|
|
11
11
|
`v=0
|
|
12
12
|
o=Z 1610744131900 1 IN IP4 127.0.0.1
|
|
13
13
|
s=Z
|
|
@@ -23,7 +23,7 @@ a=fmtp:101 0-16
|
|
|
23
23
|
a=rtpmap:18 G729/8000
|
|
24
24
|
a=fmtp:18 annexb=no
|
|
25
25
|
a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n"),
|
|
26
|
-
`v=0
|
|
26
|
+
`v=0
|
|
27
27
|
o=- 1608235282228 0 IN IP4 127.0.0.1
|
|
28
28
|
s=
|
|
29
29
|
c=IN IP4 192.168.0.141
|
|
@@ -32,7 +32,7 @@ m=audio 20000 RTP/AVP 8 101
|
|
|
32
32
|
a=rtpmap:101 telephone-event/8000
|
|
33
33
|
a=fmtp:101 0-16
|
|
34
34
|
a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n"),
|
|
35
|
-
`v=0
|
|
35
|
+
`v=0
|
|
36
36
|
o=- 1608235282228 0 IN IP4 127.0.0.1
|
|
37
37
|
s=
|
|
38
38
|
c=IN IP4 192.168.0.141
|
|
@@ -41,7 +41,7 @@ m=audio 20000 RTP/AVP 0 101
|
|
|
41
41
|
a=rtpmap:101 telephone-event/8000
|
|
42
42
|
a=fmtp:101 0-16
|
|
43
43
|
a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n"),
|
|
44
|
-
`v=0
|
|
44
|
+
`v=0
|
|
45
45
|
o=- 1608235282228 0 IN IP4 127.0.0.1
|
|
46
46
|
s=
|
|
47
47
|
c=IN IP4 192.168.0.141
|
|
@@ -52,7 +52,7 @@ a=rtpmap:101 telephone-event/8000
|
|
|
52
52
|
a=fmtp:101 0-16
|
|
53
53
|
a=fmtp:97 mode=20
|
|
54
54
|
a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n"),
|
|
55
|
-
`v=0
|
|
55
|
+
`v=0
|
|
56
56
|
o=Z 1610744131900 1 IN IP4 127.0.0.1
|
|
57
57
|
s=Z
|
|
58
58
|
c=IN IP4 192.168.0.200
|
|
@@ -67,7 +67,7 @@ a=fmtp:101 0-16
|
|
|
67
67
|
a=rtpmap:18 G729/8000
|
|
68
68
|
a=fmtp:18 annexb=no
|
|
69
69
|
a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n"),
|
|
70
|
-
`v=0
|
|
70
|
+
`v=0
|
|
71
71
|
o=Z 1610744131900 1 IN IP4 127.0.0.1
|
|
72
72
|
s=Z
|
|
73
73
|
c=IN IP4 192.168.0.200
|
|
@@ -86,7 +86,7 @@ a=fmtp:97 mode=20
|
|
|
86
86
|
a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n")
|
|
87
87
|
]
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
const possiblesavpsdp = [
|
|
90
90
|
`v=0
|
|
91
91
|
o=- 6278233949897424941 2 IN IP4 127.0.0.1
|
|
92
92
|
s=-
|
|
@@ -130,7 +130,7 @@ a=rtpmap:113 telephone-event/16000
|
|
|
130
130
|
a=rtpmap:126 telephone-event/8000
|
|
131
131
|
a=ssrc:3789235955 cname:k129XMgcWznC/heR
|
|
132
132
|
a=ssrc:3789235955 msid:Aq3uReW2RJFKkrlg942QblHcszboGZx9dhvK eaa81692-2187-4303-8e59-ed1bcb9591ee`.replace(/(\r\n|\n|\r)/gm, "\r\n"),
|
|
133
|
-
`v=0
|
|
133
|
+
`v=0
|
|
134
134
|
o=- 6278233949897424941 2 IN IP4 127.0.0.1
|
|
135
135
|
s=-
|
|
136
136
|
t=0 0
|
|
@@ -218,8 +218,8 @@ class req {
|
|
|
218
218
|
|
|
219
219
|
/* copied object structure from srf */
|
|
220
220
|
this.setparsedheader( "from", {
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
"uri": "sip:1000@dummy.com;transport=UDP",
|
|
222
|
+
"params": {
|
|
223
223
|
"tag": crypto.randomBytes( 5 ).toString( "hex" )
|
|
224
224
|
}
|
|
225
225
|
} )
|
|
@@ -306,7 +306,7 @@ class dialog {
|
|
|
306
306
|
|
|
307
307
|
let fromtag = ""
|
|
308
308
|
if( req ) {
|
|
309
|
-
|
|
309
|
+
const from = req.getParsedHeader( "from" )
|
|
310
310
|
fromtag = from.params.tag
|
|
311
311
|
}
|
|
312
312
|
|
|
@@ -392,7 +392,7 @@ class srf {
|
|
|
392
392
|
|
|
393
393
|
async createUAC( contact, options, callbacks ) {
|
|
394
394
|
this._createuaccount++
|
|
395
|
-
|
|
395
|
+
const _req = new req()
|
|
396
396
|
|
|
397
397
|
/* create a default */
|
|
398
398
|
callbacks.cbRequest( {}, _req )
|
|
@@ -401,7 +401,7 @@ class srf {
|
|
|
401
401
|
return this.callbacks.createuac( contact, options, callbacks )
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
-
if( this.newuactimeout
|
|
404
|
+
if( 0 < this.newuactimeout ) {
|
|
405
405
|
await new Promise( ( resolve ) => { setTimeout( () => resolve(), this.newuactimeout ) } )
|
|
406
406
|
}
|
|
407
407
|
|
|
@@ -432,7 +432,7 @@ class srfscenario {
|
|
|
432
432
|
"call": false
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
|
|
435
|
+
const defaultoptions = {
|
|
436
436
|
"method": "invite",
|
|
437
437
|
"uacsdp": possiblesdp[ 0 ],
|
|
438
438
|
"uassdp": possiblesdp[ 1 ]
|
package/test/unit/call.js
CHANGED
|
@@ -22,8 +22,8 @@ describe( "call.js", function() {
|
|
|
22
22
|
|
|
23
23
|
// TODO we set the remote id using "setremoteid", but getter returns it as "user"
|
|
24
24
|
// the names mismatch and can be confusing, we might consider some polishing here?
|
|
25
|
-
expect(call.
|
|
26
|
-
expect(call.
|
|
25
|
+
expect(call.callerid.name).equals("foo")
|
|
26
|
+
expect(call.callerid.user).equals("123456789")
|
|
27
27
|
expect( newcallcalled ).to.be.true
|
|
28
28
|
|
|
29
29
|
await call.hangup()
|