@babblevoice/babble-drachtio-callmanager 3.0.0 → 3.2.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/lib/call.js +313 -115
- package/package.json +1 -1
package/lib/call.js
CHANGED
|
@@ -40,6 +40,18 @@ function parseuri( s ) {
|
|
|
40
40
|
return {}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Util to convert key names to lowercase
|
|
45
|
+
* @param { object } obj
|
|
46
|
+
* @returns
|
|
47
|
+
*/
|
|
48
|
+
function keynameslower( obj ) {
|
|
49
|
+
return Object.keys( obj ).reduce( ( accumulator, currentvalue ) => {
|
|
50
|
+
accumulator[ currentvalue.toLowerCase() ] = obj[ currentvalue ]
|
|
51
|
+
return accumulator
|
|
52
|
+
}, {} )
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
/*
|
|
44
56
|
Enum for different reasons for hangup.
|
|
45
57
|
*/
|
|
@@ -357,6 +369,44 @@ class call {
|
|
|
357
369
|
this.referingtouri
|
|
358
370
|
}
|
|
359
371
|
|
|
372
|
+
/**
|
|
373
|
+
*
|
|
374
|
+
* @returns { entity }
|
|
375
|
+
*/
|
|
376
|
+
#getentityforuac() {
|
|
377
|
+
if( "uac" == this.type ) {
|
|
378
|
+
return this.options.entity
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
*
|
|
384
|
+
* @returns { entity }
|
|
385
|
+
*/
|
|
386
|
+
#getentityforuas() {
|
|
387
|
+
if( !this._entity ) return
|
|
388
|
+
|
|
389
|
+
if( this._entity.uri ) {
|
|
390
|
+
if( !this._entity.username ) {
|
|
391
|
+
const uriparts = this._entity.uri.split( "@" )
|
|
392
|
+
this._entity.username = uriparts[ 0 ]
|
|
393
|
+
if( 1 < uriparts.length )
|
|
394
|
+
this._entity.realm = uriparts[ 1 ]
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if( !this._entity.uri && this._entity.username && this._entity.realm ) {
|
|
399
|
+
this._entity.uri = this._entity.username + "@" + this._entity.realm
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
"username": this._entity.username,
|
|
404
|
+
"realm": this._entity.realm,
|
|
405
|
+
"uri": this._entity.uri,
|
|
406
|
+
"display": this._entity.display?this._entity.display:""
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
360
410
|
/**
|
|
361
411
|
* Returns the entity if known (i.e. outbound or inbound authed).
|
|
362
412
|
* @returns { Promise< entity > }
|
|
@@ -364,32 +414,23 @@ class call {
|
|
|
364
414
|
get entity() {
|
|
365
415
|
|
|
366
416
|
return ( async () => {
|
|
367
|
-
if( !this._entity ) return
|
|
368
|
-
|
|
369
|
-
if( this._entity.uri ) {
|
|
370
|
-
if( !this._entity.username ) {
|
|
371
|
-
const uriparts = this._entity.uri.split( "@" )
|
|
372
|
-
this._entity.username = uriparts[ 0 ]
|
|
373
|
-
if( 1 < uriparts.length )
|
|
374
|
-
this._entity.realm = uriparts[ 1 ]
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
417
|
|
|
378
|
-
|
|
379
|
-
|
|
418
|
+
let e
|
|
419
|
+
if( "uac" == this.type ) {
|
|
420
|
+
e = this.#getentityforuac()
|
|
421
|
+
} else {
|
|
422
|
+
e = this.#getentityforuas()
|
|
380
423
|
}
|
|
381
|
-
|
|
424
|
+
|
|
425
|
+
if( !e ) return
|
|
426
|
+
|
|
382
427
|
const entitycalls = await callstore.getbyentity( this._entity.uri )
|
|
383
428
|
let entitycallcount = 0
|
|
384
429
|
if( false !== entitycalls ) entitycallcount = entitycalls.size
|
|
430
|
+
e.ccc = entitycallcount
|
|
431
|
+
|
|
432
|
+
return e
|
|
385
433
|
|
|
386
|
-
return {
|
|
387
|
-
"username": this._entity.username,
|
|
388
|
-
"realm": this._entity.realm,
|
|
389
|
-
"uri": this._entity.uri,
|
|
390
|
-
"display": this._entity.display?this._entity.display:"",
|
|
391
|
-
"ccc": entitycallcount
|
|
392
|
-
}
|
|
393
434
|
} )()
|
|
394
435
|
}
|
|
395
436
|
|
|
@@ -438,8 +479,6 @@ class call {
|
|
|
438
479
|
parsed = this._req.getParsedHeader( "p-asserted-identity" )
|
|
439
480
|
} else if( this._req.has( "remote-party-id" ) ) {
|
|
440
481
|
parsed = this._req.getParsedHeader( "remote-party-id" )
|
|
441
|
-
} else {
|
|
442
|
-
parsed = this._req.getParsedHeader( "from" )
|
|
443
482
|
}
|
|
444
483
|
return parsed
|
|
445
484
|
}
|
|
@@ -468,119 +507,219 @@ class call {
|
|
|
468
507
|
* We make an outbound call. i.e. we send an INVITE
|
|
469
508
|
*
|
|
470
509
|
* Exceptions
|
|
471
|
-
* clicktocall - we send an INVITE but that is an inbound call
|
|
510
|
+
* partycalled/clicktocall - we send an INVITE but that is an inbound call
|
|
472
511
|
* so the invite is i nthe opposie direction.
|
|
473
512
|
* @returns { "inbound" | "outbound" }
|
|
474
513
|
*/
|
|
475
514
|
get direction() {
|
|
476
|
-
if( this.options.
|
|
515
|
+
if( this.options.partycalled ) return "inbound"
|
|
477
516
|
return "uas"==this.type?"inbound":"outbound"
|
|
478
517
|
}
|
|
479
518
|
|
|
519
|
+
#overridecallerid( startingpoint ) {
|
|
520
|
+
|
|
521
|
+
if( this.options.callerid ) {
|
|
522
|
+
if( "number" in this.options.callerid ) startingpoint.user = this.options.callerid.number
|
|
523
|
+
if( "name" in this.options.callerid ) startingpoint.name = this.options.callerid.name
|
|
524
|
+
if( "host" in this.options.callerid ) startingpoint.host = this.options.callerid.host
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
#overridecalledid( startingpoint ) {
|
|
529
|
+
startingpoint.privacy = this.options.privacy
|
|
530
|
+
|
|
531
|
+
if( this.options.calledid ) {
|
|
532
|
+
if( "number" in this.options.calledid ) {
|
|
533
|
+
startingpoint.user = this.options.calledid.number
|
|
534
|
+
startingpoint.uri = this.options.calledid.number + "@" + startingpoint.host
|
|
535
|
+
}
|
|
536
|
+
if( "name" in this.options.calledid ) startingpoint.name = this.options.calledid.name
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
#fromremoteheaders( startingpoint ) {
|
|
541
|
+
const parsed = this.#fixparseduriobj( this.#getremotefromheaders() )
|
|
542
|
+
if( parsed.uri ) startingpoint.uri = parsed.uri
|
|
543
|
+
if( parsed.user ) startingpoint.user = parsed.user
|
|
544
|
+
if( parsed.host ) startingpoint.host = parsed.host
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
#fromcontact( startingpoint ) {
|
|
548
|
+
const dest = parseuri( this.options.contact )
|
|
549
|
+
if( !dest ) return
|
|
550
|
+
startingpoint.uri = dest.uri
|
|
551
|
+
startingpoint.user = dest.user
|
|
552
|
+
startingpoint.host = dest.host
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
#fromdestination( startingpoint ) {
|
|
556
|
+
const dest = this.destination
|
|
557
|
+
startingpoint.user = dest.user
|
|
558
|
+
startingpoint.host = dest.host
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
#fromoutentity( startingpoint ) {
|
|
562
|
+
|
|
563
|
+
const entity = this.options.entity
|
|
564
|
+
if( entity ) {
|
|
565
|
+
startingpoint.name = entity.display
|
|
566
|
+
startingpoint.uri = entity.uri
|
|
567
|
+
startingpoint.user = entity.username
|
|
568
|
+
startingpoint.host = entity.realm
|
|
569
|
+
return true
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return false
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
#frominentity( startingpoint ) {
|
|
576
|
+
const entity = this._entity
|
|
577
|
+
|
|
578
|
+
if( entity ) {
|
|
579
|
+
startingpoint.name = entity.display
|
|
580
|
+
startingpoint.uri = entity.uri
|
|
581
|
+
startingpoint.user = entity.username
|
|
582
|
+
startingpoint.host = entity.realm
|
|
583
|
+
return true
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return false
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
#fromentity( startingpoint ) {
|
|
590
|
+
|
|
591
|
+
if( this.#fromoutentity( startingpoint ) ) return true
|
|
592
|
+
if( this.#frominentity( startingpoint ) ) return true
|
|
593
|
+
|
|
594
|
+
return false
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
|
|
480
598
|
/**
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
* If we are outbound then this is the entity we are calling
|
|
484
|
-
* @returns { remoteid }
|
|
599
|
+
* We have received an INVITE
|
|
600
|
+
* @param { object } startingpoint
|
|
485
601
|
*/
|
|
486
|
-
|
|
602
|
+
#calledidforuas( startingpoint ) {
|
|
603
|
+
this.#fromdestination( startingpoint )
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* We have sent an INVITE - which could also be 3rd party
|
|
608
|
+
* @param { object } startingpoint
|
|
609
|
+
*/
|
|
610
|
+
#calledidforuac( startingpoint ) {
|
|
611
|
+
if( !this.#fromoutentity( startingpoint ) ) {
|
|
612
|
+
this.#fromcontact( startingpoint )
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* We have sent an INVITE - but it could be 3rd party
|
|
619
|
+
* @param { object } startingpoint
|
|
620
|
+
* @returns
|
|
621
|
+
*/
|
|
622
|
+
#calleridforuac( startingpoint ) {
|
|
623
|
+
if( !this.#fromoutentity( startingpoint ) ) {
|
|
624
|
+
this.#fromcontact( startingpoint )
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* We have received an INVITE - so caller ID comes from headers / auth
|
|
630
|
+
* * @param { object } startingpoint
|
|
631
|
+
*/
|
|
632
|
+
#calleridforuas( startingpoint ) {
|
|
633
|
+
this.#frominentity( startingpoint )
|
|
634
|
+
this.#fromremoteheaders( startingpoint )
|
|
635
|
+
}
|
|
487
636
|
|
|
637
|
+
#callerid() {
|
|
488
638
|
const startingpoint = {
|
|
489
639
|
"name": "",
|
|
490
640
|
"uri": "",
|
|
491
641
|
"user": "0000000000",
|
|
492
642
|
"host": "localhost.localdomain",
|
|
493
643
|
"privacy": true === this.options.privacy,
|
|
494
|
-
"type": "
|
|
644
|
+
"type": "callerid"
|
|
495
645
|
}
|
|
496
646
|
|
|
497
|
-
if( "
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
startingpoint
|
|
501
|
-
startingpoint.host = dest.host
|
|
647
|
+
if( "uas" == this.type ) this.#calleridforuas( startingpoint )
|
|
648
|
+
else {
|
|
649
|
+
if( this.options.partycalled ) {
|
|
650
|
+
this.#calleridforuac( startingpoint )
|
|
502
651
|
} else {
|
|
503
|
-
const
|
|
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
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
startingpoint.privacy = this.options.privacy
|
|
652
|
+
const other = this.other
|
|
521
653
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
654
|
+
if( other ) {
|
|
655
|
+
if( "uas" == other.type ) {
|
|
656
|
+
other.#calleridforuas( startingpoint )
|
|
657
|
+
other.#overridecallerid( startingpoint )
|
|
658
|
+
} else {
|
|
659
|
+
other.#calledidforuac( startingpoint )
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
this.#calleridforuac( startingpoint )
|
|
663
|
+
}
|
|
526
664
|
}
|
|
527
|
-
if( "name" in this.options.calledid ) startingpoint.name = this.options.calledid.name
|
|
528
665
|
}
|
|
529
666
|
|
|
667
|
+
this.#overridecallerid( startingpoint )
|
|
530
668
|
return startingpoint
|
|
531
669
|
}
|
|
532
670
|
|
|
533
671
|
/**
|
|
534
672
|
* @returns { remoteid }
|
|
535
673
|
*/
|
|
536
|
-
// eslint-disable-next-line complexity
|
|
537
674
|
get callerid() {
|
|
675
|
+
return this.#callerid()
|
|
676
|
+
}
|
|
538
677
|
|
|
539
|
-
|
|
678
|
+
#calledid() {
|
|
679
|
+
const startingpoint = {
|
|
540
680
|
"name": "",
|
|
541
681
|
"uri": "",
|
|
542
682
|
"user": "0000000000",
|
|
543
683
|
"host": "localhost.localdomain",
|
|
544
684
|
"privacy": true === this.options.privacy,
|
|
545
|
-
"type": "
|
|
685
|
+
"type": "calledid"
|
|
546
686
|
}
|
|
547
687
|
|
|
548
|
-
if( "
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
688
|
+
if( "uas" == this.type ) this.#calledidforuas( startingpoint )
|
|
689
|
+
else {
|
|
690
|
+
if( !this.options.partycalled ) this.#calledidforuac( startingpoint )
|
|
691
|
+
|
|
692
|
+
const other = this.other
|
|
693
|
+
|
|
694
|
+
if( other ) {
|
|
695
|
+
if( "uas" == other.type ) {
|
|
696
|
+
if( this.options.partycalled ) {
|
|
697
|
+
other.#calleridforuas( startingpoint )
|
|
698
|
+
} else {
|
|
699
|
+
other.#calledidforuas( startingpoint )
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
other.#calledidforuac( startingpoint )
|
|
557
703
|
}
|
|
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
|
|
704
|
+
other.#overridecalledid( startingpoint )
|
|
572
705
|
}
|
|
573
706
|
}
|
|
574
707
|
|
|
575
|
-
|
|
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
|
|
579
|
-
}
|
|
708
|
+
this.#overridecalledid( startingpoint )
|
|
580
709
|
|
|
581
710
|
return startingpoint
|
|
582
711
|
}
|
|
583
712
|
|
|
713
|
+
/**
|
|
714
|
+
* Returns the called object. i.e.
|
|
715
|
+
* If we are inbound then this is the destination
|
|
716
|
+
* If we are outbound then this is the entity we are calling
|
|
717
|
+
* @returns { remoteid }
|
|
718
|
+
*/
|
|
719
|
+
get calledid() {
|
|
720
|
+
return this.#calledid()
|
|
721
|
+
}
|
|
722
|
+
|
|
584
723
|
/**
|
|
585
724
|
* @param { string } c
|
|
586
725
|
*/
|
|
@@ -997,6 +1136,7 @@ class call {
|
|
|
997
1136
|
adopt( other, mix ) {
|
|
998
1137
|
other.parent = this
|
|
999
1138
|
this.children.add( other )
|
|
1139
|
+
other.moh = this.moh
|
|
1000
1140
|
|
|
1001
1141
|
/* maintain privacy */
|
|
1002
1142
|
other.options.privacy = this.options.privacy
|
|
@@ -1196,7 +1336,13 @@ class call {
|
|
|
1196
1336
|
*/
|
|
1197
1337
|
get other() {
|
|
1198
1338
|
if( this.parent ) return this.parent
|
|
1339
|
+
return this.child
|
|
1340
|
+
}
|
|
1199
1341
|
|
|
1342
|
+
/**
|
|
1343
|
+
* Return specifically first child - prefer established otherwise first
|
|
1344
|
+
*/
|
|
1345
|
+
get child() {
|
|
1200
1346
|
/* first established */
|
|
1201
1347
|
for( const child of this.children ) {
|
|
1202
1348
|
if( child.established ) {
|
|
@@ -1714,7 +1860,7 @@ class call {
|
|
|
1714
1860
|
* @returns { Promise } resolves on timeout or when unmix happens
|
|
1715
1861
|
* @private
|
|
1716
1862
|
*/
|
|
1717
|
-
_hold( direction = "
|
|
1863
|
+
_hold( direction = "inactive" ) {
|
|
1718
1864
|
|
|
1719
1865
|
if( this.state.held ) return
|
|
1720
1866
|
this.state.held = true
|
|
@@ -1855,10 +2001,15 @@ class call {
|
|
|
1855
2001
|
Send out pre-modified SDP to get the audio to the new location.
|
|
1856
2002
|
This method might be use, but there are problems - so when it is used
|
|
1857
2003
|
it can be re-written but should use a mthod to create a codec - which is the
|
|
1858
|
-
same as used elsewhere.
|
|
2004
|
+
same as used elsewhere. If a bond has been attached to the call, we will
|
|
2005
|
+
try to reuse an existing channel.
|
|
2006
|
+
@param { object } [ channeldef ]
|
|
1859
2007
|
@private
|
|
1860
2008
|
*/
|
|
1861
|
-
async reinvite() {
|
|
2009
|
+
async reinvite( channeldef ) {
|
|
2010
|
+
|
|
2011
|
+
if ( !channeldef )
|
|
2012
|
+
channeldef = await this.#createchannelremotedef()
|
|
1862
2013
|
|
|
1863
2014
|
const remotesdp = await this._dialog.modify( this.sdp.local.toString() )
|
|
1864
2015
|
.catch( ( e ) => {
|
|
@@ -1872,10 +2023,31 @@ class call {
|
|
|
1872
2023
|
this.sdp.remote.setdynamepayloadtypes( this.sdp.local )
|
|
1873
2024
|
}
|
|
1874
2025
|
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
/**
|
|
2029
|
+
Mix two calls. If the two calls are on a different node
|
|
2030
|
+
the second call is bonded and reinvited.
|
|
2031
|
+
@param { call } othercall - our call object which is early
|
|
2032
|
+
@private
|
|
2033
|
+
*/
|
|
2034
|
+
async mix( othercall ) {
|
|
2035
|
+
if ( othercall.channels.audio
|
|
2036
|
+
&& othercall.channels.audio.connection.instance
|
|
2037
|
+
!= this.channels.audio.connection.instance ) {
|
|
2038
|
+
|
|
2039
|
+
const channeldef = await othercall.#createchannelremotedef()
|
|
2040
|
+
|
|
2041
|
+
const oldchannel = othercall.channels.audio
|
|
2042
|
+
// eslint-disable-next-line require-atomic-updates
|
|
2043
|
+
othercall.channels.audio = await this.channels.audio.openchannel( channeldef, othercall._handlechannelevents.bind( othercall ) )
|
|
2044
|
+
|
|
2045
|
+
await othercall.bond( this ).reinvite( channeldef )
|
|
1878
2046
|
|
|
2047
|
+
await oldchannel.close()
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
await this.channels.audio.mix( othercall.channels.audio )
|
|
1879
2051
|
}
|
|
1880
2052
|
|
|
1881
2053
|
/**
|
|
@@ -2256,19 +2428,24 @@ class call {
|
|
|
2256
2428
|
} )
|
|
2257
2429
|
} )
|
|
2258
2430
|
|
|
2431
|
+
/*
|
|
2432
|
+
TODO - this is wrong. If we want to include this - it is not the REFER CSEQ that jssip
|
|
2433
|
+
is looking for - it is the cseq of the INVITE.
|
|
2259
2434
|
const id = this._req.get( "cseq" ).match( /(\d+)/ )[ 0 ]
|
|
2435
|
+
Leave out for now - as this works for us.
|
|
2436
|
+
*/
|
|
2260
2437
|
try {
|
|
2261
|
-
await this._notifyreferstart(
|
|
2438
|
+
await this._notifyreferstart()
|
|
2262
2439
|
} catch( e ) {
|
|
2263
2440
|
console.trace( e )
|
|
2264
|
-
this._notifyreferfail(
|
|
2441
|
+
this._notifyreferfail()
|
|
2265
2442
|
return
|
|
2266
2443
|
}
|
|
2267
2444
|
|
|
2268
2445
|
/* Link logically and mix */
|
|
2269
2446
|
a_1.adopt( c_1, true )
|
|
2270
2447
|
|
|
2271
|
-
this._notifyrefercomplete(
|
|
2448
|
+
this._notifyrefercomplete()
|
|
2272
2449
|
|
|
2273
2450
|
a_1.state.refered = true
|
|
2274
2451
|
|
|
@@ -2579,7 +2756,7 @@ class call {
|
|
|
2579
2756
|
}
|
|
2580
2757
|
}
|
|
2581
2758
|
|
|
2582
|
-
options.headers[ "
|
|
2759
|
+
options.headers[ "max-forwards" ] = maxforwards
|
|
2583
2760
|
|
|
2584
2761
|
if( !options.orphan && !options.parent ) {
|
|
2585
2762
|
options.parent = this
|
|
@@ -2700,7 +2877,7 @@ class call {
|
|
|
2700
2877
|
/* TODO: this is a hack. projectrtp has become too complicated with both a listen and connect
|
|
2701
2878
|
mechanism. This is causing problems in code like this. There is no interface to
|
|
2702
2879
|
detect which mode the channel is in - but the channels property will exist on a connect
|
|
2703
|
-
style channel. projectrtp will
|
|
2880
|
+
style channel. projectrtp will getrelatives a rewrite to support only one. */
|
|
2704
2881
|
if( relatedcall && relatedcall.channels.audio && relatedcall.channels.audio.channels ) {
|
|
2705
2882
|
this.channels.audio = await this.other.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
|
|
2706
2883
|
return
|
|
@@ -2818,10 +2995,16 @@ class call {
|
|
|
2818
2995
|
}
|
|
2819
2996
|
|
|
2820
2997
|
/**
|
|
2998
|
+
* https://www.ietf.org/proceedings/50/I-D/sip-privacy-01.txt
|
|
2821
2999
|
* @returns { object }
|
|
2822
3000
|
*/
|
|
2823
3001
|
#configcalleridfornewuac() {
|
|
2824
3002
|
|
|
3003
|
+
let party = ";party=calling"
|
|
3004
|
+
if( this.options.partycalled ) {
|
|
3005
|
+
party = ";party=called"
|
|
3006
|
+
}
|
|
3007
|
+
|
|
2825
3008
|
const callerid = this.callerid
|
|
2826
3009
|
const calleridstr = `"${callerid.name}" <sip:${callerid.user}@${callerid.host}>`
|
|
2827
3010
|
|
|
@@ -2834,12 +3017,20 @@ class call {
|
|
|
2834
3017
|
RFC 3325 - should we also consider the P-Preferred-Identity header?
|
|
2835
3018
|
P-Asserted-Identity?
|
|
2836
3019
|
*/
|
|
2837
|
-
this.options.headers[ "
|
|
2838
|
-
this.options.headers[ "
|
|
3020
|
+
this.options.headers[ "remote-party-id" ] = calleridstr + party + ";screen=yes" + privacy
|
|
3021
|
+
this.options.headers[ "from" ] = calleridstr
|
|
2839
3022
|
|
|
2840
3023
|
return { user: callerid.user, realm: callerid.host }
|
|
2841
3024
|
}
|
|
2842
3025
|
|
|
3026
|
+
|
|
3027
|
+
#configureto() {
|
|
3028
|
+
if( this.options.headers[ "to" ] ) return
|
|
3029
|
+
if( !this.options.entity ) return
|
|
3030
|
+
|
|
3031
|
+
this.options.headers[ "to" ] = "<sip:" + this.options.entity.uri + ">"
|
|
3032
|
+
}
|
|
3033
|
+
|
|
2843
3034
|
/**
|
|
2844
3035
|
*
|
|
2845
3036
|
* @param { string } contactstr
|
|
@@ -2848,16 +3039,19 @@ class call {
|
|
|
2848
3039
|
|
|
2849
3040
|
const parts = parseuri( contactstr )
|
|
2850
3041
|
|
|
2851
|
-
if( this.options.clicktocall )
|
|
3042
|
+
if( this.options.clicktocall ) {
|
|
3043
|
+
this.options.partycalled = true
|
|
3044
|
+
this.options.autoanswer = true
|
|
3045
|
+
}
|
|
2852
3046
|
|
|
2853
3047
|
if( !this.options.contactparams ) this.options.contactparams = ""
|
|
2854
3048
|
if( true === this.options.autoanswer ) {
|
|
2855
|
-
this.options.headers[ "
|
|
2856
|
-
this.options.headers[ "
|
|
3049
|
+
this.options.headers[ "call-info" ] = `<sip:${parts.host}>;answer-after=0`
|
|
3050
|
+
this.options.headers[ "alert-info" ] = "auto-answer"
|
|
2857
3051
|
this.options.contactparams += ";intercom=true"
|
|
2858
3052
|
} else if ( "number" == typeof this.options.autoanswer ) {
|
|
2859
|
-
this.options.headers[ "
|
|
2860
|
-
this.options.headers[ "
|
|
3053
|
+
this.options.headers[ "call-info" ] = `<sip:${parts.host}>;answer-after=${this.options.autoanswer}`
|
|
3054
|
+
this.options.headers[ "alert-info" ] = "auto-answer"
|
|
2861
3055
|
this.options.contactparams += ";intercom=true"
|
|
2862
3056
|
}
|
|
2863
3057
|
}
|
|
@@ -2914,6 +3108,7 @@ class call {
|
|
|
2914
3108
|
* @property { object } [ uactimeout ] - override the deault timeout
|
|
2915
3109
|
* @property { true | number } [ autoanswer ] - if true add call-info to auto answer, if number delay to add
|
|
2916
3110
|
* @property { boolean } [ clicktocall ] - if set to true, will set autoanswer to true and swap the source and desination on caller ID
|
|
3111
|
+
* @property { boolean } [ partycalled ] - reverses the direction of the call from the invite
|
|
2917
3112
|
* @property { boolean } [ late ] - late negotiation
|
|
2918
3113
|
* @property { boolean } [ privacy ] - sets the privacy
|
|
2919
3114
|
* @property { entity } [ entity ] - used to store this call against and look up a contact string if not supplied.
|
|
@@ -2964,6 +3159,7 @@ class call {
|
|
|
2964
3159
|
* @param { newuaccallbacks } [ callbacks ]
|
|
2965
3160
|
* @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
3161
|
*/
|
|
3162
|
+
// eslint-disable-next-line complexity
|
|
2967
3163
|
static async newuac( options, callbacks = {} ) {
|
|
2968
3164
|
|
|
2969
3165
|
if( !options.contact && !options.entity ) return false
|
|
@@ -2982,24 +3178,26 @@ class call {
|
|
|
2982
3178
|
|
|
2983
3179
|
newcall.bond( options.bond )
|
|
2984
3180
|
|
|
3181
|
+
// spread is not recursive
|
|
3182
|
+
newcall.options = { ...newcall.options, ...options }
|
|
3183
|
+
const tmpheaders = { ...callmanager.options.headers, ...newcall.options.headers, ...options.headers }
|
|
3184
|
+
newcall.options.headers = keynameslower( tmpheaders )
|
|
3185
|
+
|
|
2985
3186
|
if( options.entity ) {
|
|
2986
3187
|
newcall.entity = options.entity
|
|
2987
3188
|
callstore.set( newcall )
|
|
3189
|
+
|
|
2988
3190
|
}
|
|
2989
3191
|
|
|
2990
|
-
// spread is not recursive
|
|
2991
|
-
newcall.options = { ...newcall.options, ...options }
|
|
2992
|
-
const tmpheaders = { ...callmanager.options.headers, ...newcall.options.headers, ...options.headers }
|
|
2993
|
-
newcall.options.headers = tmpheaders
|
|
2994
|
-
|
|
2995
3192
|
newcall.#configcalleridfornewuac()
|
|
3193
|
+
newcall.#configureto()
|
|
2996
3194
|
newcall.import()
|
|
2997
3195
|
|
|
2998
3196
|
newcall.#configautoanswerfornewuac( options.contact )
|
|
2999
3197
|
|
|
3000
|
-
newcall.options.headers[ "
|
|
3001
|
-
newcall.options.headers[ "
|
|
3002
|
-
newcall.options.headers[ "
|
|
3198
|
+
newcall.options.headers[ "allow-events" ] = "talk, hold, presence, as-feature-event, dialog, call-info, sla, include-session-description, message-summary, refer"
|
|
3199
|
+
newcall.options.headers[ "allow" ] = "INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE"
|
|
3200
|
+
newcall.options.headers[ "supported" ] = "timer, path, replaces"
|
|
3003
3201
|
|
|
3004
3202
|
newcall.#confignetwork( options )
|
|
3005
3203
|
await newcall.#openchannelsfornewuac()
|