@babblevoice/babble-drachtio-callmanager 2.2.0 → 2.2.2
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 +62 -13
- package/lib/sdp.js +42 -17
- package/package.json +1 -1
- package/test/interface/call.js +1 -1
- package/test/interface/sdp.js +75 -0
package/lib/call.js
CHANGED
|
@@ -5,13 +5,40 @@ const dns = require( "node:dns" )
|
|
|
5
5
|
|
|
6
6
|
const projectrtp = require( "@babblevoice/projectrtp" ).projectrtp
|
|
7
7
|
|
|
8
|
-
const parseuri = require( "drachtio-srf" ).parseUri
|
|
9
8
|
const sdpgen = require( "./sdp.js" )
|
|
10
9
|
const callstore = require( "./store.js" )
|
|
11
10
|
|
|
12
11
|
const sipauth = require( "@babblevoice/babble-drachtio-auth" )
|
|
13
12
|
|
|
14
13
|
const ipv6regex = /^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/gm
|
|
14
|
+
const parseurire = /^(sips?):(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/
|
|
15
|
+
const parseuriparamsre = /([^;=]+)(=([^;=]+))?/g
|
|
16
|
+
const parseuriheadersre = /[^&=]+=[^&=]+/g
|
|
17
|
+
|
|
18
|
+
function parseuri( s ) {
|
|
19
|
+
if( "object" === typeof s )
|
|
20
|
+
return s
|
|
21
|
+
|
|
22
|
+
const r = parseurire.exec( s )
|
|
23
|
+
|
|
24
|
+
if( r ) {
|
|
25
|
+
return {
|
|
26
|
+
schema: r[ 1 ],
|
|
27
|
+
user: r[ 2 ],
|
|
28
|
+
password: r[ 3 ],
|
|
29
|
+
host: r[ 4 ],
|
|
30
|
+
port: +r[ 5 ],
|
|
31
|
+
params: (r[ 6 ].match( parseuriparamsre ) || [] )
|
|
32
|
+
.map( function( s ) { return s.split( "=" ) } )
|
|
33
|
+
.reduce(function(params, x) { params[x[0]]=x[1] || null; return params }, {} ),
|
|
34
|
+
headers: ( ( r[ 7 ] || "" ).match( parseuriheadersre ) || [])
|
|
35
|
+
.map(function(s){ return s.split( "=") } )
|
|
36
|
+
.reduce(function(params, x) { params[ x[ 0 ] ] = x[ 1 ]; return params }, {} )
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {}
|
|
41
|
+
}
|
|
15
42
|
|
|
16
43
|
/*
|
|
17
44
|
Enum for different reasons for hangup.
|
|
@@ -446,10 +473,25 @@ class call {
|
|
|
446
473
|
return parsed
|
|
447
474
|
}
|
|
448
475
|
|
|
476
|
+
#fixparseduriobj( parsed ) {
|
|
477
|
+
|
|
478
|
+
if( !parsed ) parsed = {}
|
|
479
|
+
if( !parsed.uri && parsed.user && parsed.host ) parsed.uri = parsed.user + "@" + parsed.host
|
|
480
|
+
if( parsed.uri && !parsed.user && !parsed.host ) parsed = parseuri( parsed.uri )
|
|
481
|
+
|
|
482
|
+
let parseduri = parseuri( parsed.uri )
|
|
483
|
+
|
|
484
|
+
if( !parseduri ) parseduri = { "user": parsed.user, "host": parsed.host }
|
|
485
|
+
if( !parsed.params ) parsed.params = {}
|
|
486
|
+
|
|
487
|
+
return parsed
|
|
488
|
+
}
|
|
489
|
+
|
|
449
490
|
/**
|
|
450
491
|
*
|
|
451
492
|
* @returns { object }
|
|
452
493
|
*/
|
|
494
|
+
// eslint-disable-next-line complexity
|
|
453
495
|
#getremoteuas() {
|
|
454
496
|
/* uas - inbound */
|
|
455
497
|
let parsed
|
|
@@ -466,16 +508,13 @@ class call {
|
|
|
466
508
|
parsed = this.#getremotefromheaders()
|
|
467
509
|
}
|
|
468
510
|
|
|
469
|
-
|
|
470
|
-
let parseduri = parseuri( parsed.uri )
|
|
471
|
-
if( !parseduri ) parseduri = { "user": parsed.user, "host": parsed.host }
|
|
472
|
-
if( !parsed.params ) parsed.params = {}
|
|
511
|
+
parsed = this.#fixparseduriobj( parsed )
|
|
473
512
|
|
|
474
513
|
return {
|
|
475
514
|
"name": this._remote.name?this._remote.name:( !parsed.name?"":parsed.name.replace( /['"]+/g, "" ) ),
|
|
476
515
|
"uri": parsed.uri,
|
|
477
|
-
"user": this._remote.id?this._remote.id:(
|
|
478
|
-
"host":
|
|
516
|
+
"user": this._remote.id?this._remote.id:(parsed.user),
|
|
517
|
+
"host": parsed.host,
|
|
479
518
|
"privacy": "true" === parsed.params.privacy,
|
|
480
519
|
"type": "callerid"
|
|
481
520
|
}
|
|
@@ -1365,9 +1404,7 @@ class call {
|
|
|
1365
1404
|
.setconnectionaddress( this.channels.audio.local.address )
|
|
1366
1405
|
.setaudioport( this.channels.audio.local.port )
|
|
1367
1406
|
|
|
1368
|
-
|
|
1369
|
-
this.sdp.local.addcodecs( "2833" )
|
|
1370
|
-
}
|
|
1407
|
+
this.#checkandadd2833()
|
|
1371
1408
|
|
|
1372
1409
|
if( this._iswebrtc ) {
|
|
1373
1410
|
this.sdp.local.addssrc( this.channels.audio.local.ssrc )
|
|
@@ -2503,6 +2540,20 @@ class call {
|
|
|
2503
2540
|
|
|
2504
2541
|
}
|
|
2505
2542
|
|
|
2543
|
+
/**
|
|
2544
|
+
* If we have remote sdp we have to check they support 2833 before we add backand our options permit it.
|
|
2545
|
+
* If we have no remote sdp then we only check our options.
|
|
2546
|
+
*/
|
|
2547
|
+
#checkandadd2833() {
|
|
2548
|
+
if( this.sdp.remote ) {
|
|
2549
|
+
if( this.options.rfc2833 && this.sdp.remote.has( "2833" ) ) {
|
|
2550
|
+
this.sdp.local.addcodecs( "2833" )
|
|
2551
|
+
}
|
|
2552
|
+
} else if( this.options.rfc2833 ) {
|
|
2553
|
+
this.sdp.local.addcodecs( "2833" )
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2506
2557
|
/**
|
|
2507
2558
|
*
|
|
2508
2559
|
*/
|
|
@@ -2517,9 +2568,7 @@ class call {
|
|
|
2517
2568
|
this.sdp.local.setaudioport( this.channels.audio.local.port )
|
|
2518
2569
|
.setconnectionaddress( this.channels.audio.local.address )
|
|
2519
2570
|
|
|
2520
|
-
|
|
2521
|
-
this.sdp.local.addcodecs( "2833" )
|
|
2522
|
-
}
|
|
2571
|
+
this.#checkandadd2833()
|
|
2523
2572
|
|
|
2524
2573
|
/* DTLS is only supported ( outbound ) on websocket connections */
|
|
2525
2574
|
this.sip.contact = this.options.contact
|
package/lib/sdp.js
CHANGED
|
@@ -417,6 +417,30 @@ class sdp {
|
|
|
417
417
|
return this
|
|
418
418
|
}
|
|
419
419
|
|
|
420
|
+
/**
|
|
421
|
+
* Gets a list of codecs (that we support) and return as an array of strings.
|
|
422
|
+
* @param { string } type
|
|
423
|
+
* @returns { array< string > } array of codec names in the format [ "pcma" ]
|
|
424
|
+
*/
|
|
425
|
+
#codecs( type = "audio" ) {
|
|
426
|
+
|
|
427
|
+
const audio = this.getmedia( type )
|
|
428
|
+
|
|
429
|
+
/* work out an array of codecs on this side in the format of [ "pcma", "pcmu" ] */
|
|
430
|
+
const ourcodecs = []
|
|
431
|
+
for( const pt of audio.payloads ) {
|
|
432
|
+
if( undefined === codecconv[ pt ] ) continue
|
|
433
|
+
if( 97 == pt ) {
|
|
434
|
+
if( -1 == getconfigforpt( audio, 97 ).indexOf( "mode=30" ) )
|
|
435
|
+
ourcodecs.push( codecconv[ pt ] )
|
|
436
|
+
} else {
|
|
437
|
+
ourcodecs.push( codecconv[ pt ] )
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return ourcodecs
|
|
442
|
+
}
|
|
443
|
+
|
|
420
444
|
/*
|
|
421
445
|
Only allow CODECs supported by both sides.
|
|
422
446
|
other can be:
|
|
@@ -436,23 +460,7 @@ class sdp {
|
|
|
436
460
|
|
|
437
461
|
/* ensure other side is on the format [ "pcma", "pcmu" ] */
|
|
438
462
|
other = alltocodecname( other )
|
|
439
|
-
|
|
440
|
-
let audio = []
|
|
441
|
-
for( const m of this.sdp.media ) {
|
|
442
|
-
if( "audio" == m.type ) audio = m
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
/* work out an array of codecs on this side in the format of [ "pcma", "pcmu" ] */
|
|
446
|
-
const ourcodecs = []
|
|
447
|
-
for( const pt of audio.payloads ) {
|
|
448
|
-
if( undefined === codecconv[ pt ] ) continue
|
|
449
|
-
if( 97 == pt ) {
|
|
450
|
-
if( -1 == getconfigforpt( audio, 97 ).indexOf( "mode=30" ) )
|
|
451
|
-
ourcodecs.push( codecconv[ pt ] )
|
|
452
|
-
} else {
|
|
453
|
-
ourcodecs.push( codecconv[ pt ] )
|
|
454
|
-
}
|
|
455
|
-
}
|
|
463
|
+
const ourcodecs = this.#codecs()
|
|
456
464
|
|
|
457
465
|
/* intersection */
|
|
458
466
|
let retval = other.filter( value => ourcodecs.includes( value ) )
|
|
@@ -469,6 +477,23 @@ class sdp {
|
|
|
469
477
|
return full
|
|
470
478
|
}
|
|
471
479
|
|
|
480
|
+
/**
|
|
481
|
+
* See other param in intersection. Confirms that we have
|
|
482
|
+
* support for at least one of the codecs in codecs
|
|
483
|
+
* @param { array< string > | string } codecs
|
|
484
|
+
*/
|
|
485
|
+
has( codecs ) {
|
|
486
|
+
|
|
487
|
+
const ourcodecs = this.#codecs()
|
|
488
|
+
codecs = alltocodecname( codecs )
|
|
489
|
+
|
|
490
|
+
/* intersection */
|
|
491
|
+
if( undefined === codecs.find( value => ourcodecs.includes( value ) ) ) return false
|
|
492
|
+
|
|
493
|
+
return true
|
|
494
|
+
|
|
495
|
+
}
|
|
496
|
+
|
|
472
497
|
toString() {
|
|
473
498
|
|
|
474
499
|
/* We need to convert payloads back to string to stop a , being added */
|
package/package.json
CHANGED
package/test/interface/call.js
CHANGED
package/test/interface/sdp.js
CHANGED
|
@@ -698,4 +698,79 @@ a=ssrc:222390620 msid:a46039f4-1857-410e-b1cc-215c09878068 ce8c9c25-2ea0-4079-aa
|
|
|
698
698
|
|
|
699
699
|
|
|
700
700
|
} )
|
|
701
|
+
|
|
702
|
+
it( "codec has", async () => {
|
|
703
|
+
|
|
704
|
+
const sdpwith2833 = `v=0
|
|
705
|
+
o=- 4317 0 IN IP4 127.0.0.1
|
|
706
|
+
s=project
|
|
707
|
+
c=IN IP4 13.42.100.66
|
|
708
|
+
t=0 0
|
|
709
|
+
a=msid-semantic: WMS 136f9ec7464dca67065c81da42013e84
|
|
710
|
+
m=audio 10036 UDP/TLS/RTP/SAVPF 9 101
|
|
711
|
+
a=rtpmap:9 G722/8000
|
|
712
|
+
a=rtpmap:101 telephone-event/8000
|
|
713
|
+
a=fmtp:101 0-16
|
|
714
|
+
a=setup:passive
|
|
715
|
+
a=msid:136f9ec7464dca67065c81da42013e84 ff8ebd1be43cdf5170974bf0d1efb772
|
|
716
|
+
a=ptime:20
|
|
717
|
+
a=sendrecv
|
|
718
|
+
a=ice-ufrag:50cf0e6109bad2be
|
|
719
|
+
a=ice-pwd:9Tbl7U92hrzTUluayFbRPYh9
|
|
720
|
+
a=fingerprint:sha-256 12:31:FB:95:BB:00:1A:D8:24:94:71:21:CE:05:57:8F:47:1E:5E:C5:43:41:19:3F:2A:B8:8C:92:07:BB:BC:56
|
|
721
|
+
a=candidate:1 1 udp 255 13.42.100.66 10036 typ host generation 0
|
|
722
|
+
a=ssrc:3127369874 cname:97016b88e9a33a3b465b15cff21fec35
|
|
723
|
+
a=ssrc:3127369874 msid:136f9ec7464dca67065c81da42013e84 ff8ebd1be43cdf5170974bf0d1efb772
|
|
724
|
+
a=ssrc:3127369874 mslabel:136f9ec7464dca67065c81da42013e84
|
|
725
|
+
a=ssrc:3127369874 label:ff8ebd1be43cdf5170974bf0d1efb772
|
|
726
|
+
a=rtcp-mux`
|
|
727
|
+
|
|
728
|
+
const sdpwithout2833 = `v=0
|
|
729
|
+
o=- 4316 0 IN IP4 127.0.0.1
|
|
730
|
+
s=project
|
|
731
|
+
c=IN IP4 18.170.39.61
|
|
732
|
+
t=0 0
|
|
733
|
+
m=audio 10038 RTP/AVP 9 97 0 8
|
|
734
|
+
a=rtpmap:9 G722/8000
|
|
735
|
+
a=rtpmap:97 ilbc/8000
|
|
736
|
+
a=rtpmap:0 PCMU/8000
|
|
737
|
+
a=rtpmap:8 PCMA/8000
|
|
738
|
+
a=fmtp:97 mode=20
|
|
739
|
+
a=ptime:20
|
|
740
|
+
a=sendrecv`
|
|
741
|
+
|
|
742
|
+
const noilbc30 = `v=0
|
|
743
|
+
o=Z 1608292844058 1 IN IP4 192.168.0.141
|
|
744
|
+
s=Z
|
|
745
|
+
c=IN IP4 192.168.0.141
|
|
746
|
+
t=0 0
|
|
747
|
+
m=audio 56802 RTP/AVP 8 0 9 106 101 98 97
|
|
748
|
+
a=rtpmap:106 opus/48000/2
|
|
749
|
+
a=fmtp:106 minptime=20; cbr=1; maxaveragebitrate=40000; useinbandfec=1
|
|
750
|
+
a=rtpmap:101 telephone-event/8000
|
|
751
|
+
a=fmtp:101 0-16
|
|
752
|
+
a=rtpmap:98 telephone-event/48000
|
|
753
|
+
a=fmtp:98 0-16
|
|
754
|
+
a=rtpmap:97 iLBC/8000
|
|
755
|
+
a=fmtp:97 mode=30
|
|
756
|
+
a=sendrecv`
|
|
757
|
+
|
|
758
|
+
const sdpwith2833obj = sdp.create( sdpwith2833 )
|
|
759
|
+
const sdpwithout2833obj = sdp.create( sdpwithout2833 )
|
|
760
|
+
const noilbc30obj = sdp.create( noilbc30 )
|
|
761
|
+
|
|
762
|
+
expect( sdpwith2833obj.has( "2833" ) ).to.be.true
|
|
763
|
+
expect( sdpwith2833obj.has( "pcmu" ) ).to.be.false
|
|
764
|
+
expect( sdpwith2833obj.has( "pcma" ) ).to.be.false
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
expect( sdpwithout2833obj.has( "2833" ) ).to.be.false
|
|
768
|
+
expect( sdpwithout2833obj.has( "g722" ) ).to.be.true
|
|
769
|
+
expect( sdpwithout2833obj.has( "ilbc" ) ).to.be.true
|
|
770
|
+
|
|
771
|
+
expect( noilbc30obj.has( "ilbc" ) ).to.be.false
|
|
772
|
+
expect( noilbc30obj.has( "2833" ) ).to.be.true
|
|
773
|
+
expect( noilbc30obj.has( "g722" ) ).to.be.true
|
|
774
|
+
|
|
775
|
+
} )
|
|
701
776
|
} )
|