@babblevoice/babble-drachtio-callmanager 2.1.2 → 2.2.1
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 +28 -9
- package/lib/sdp.js +42 -17
- package/package.json +1 -1
- package/test/interface/sdp.js +132 -2
package/index.js
CHANGED
|
@@ -12,7 +12,8 @@ const default_options = {
|
|
|
12
12
|
"rfc2833": true, /* Enable RFC 2833 - DTMF */
|
|
13
13
|
"late": false, /* Late negotiation */
|
|
14
14
|
"registrar": false, /* our registrar object or falsey */
|
|
15
|
-
"referauthrequired": true
|
|
15
|
+
"referauthrequired": true,
|
|
16
|
+
"ignoreipv6candidates": true /* ipv6 does not work in projectrtp */
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/**
|
package/lib/call.js
CHANGED
|
@@ -11,6 +11,8 @@ const callstore = require( "./store.js" )
|
|
|
11
11
|
|
|
12
12
|
const sipauth = require( "@babblevoice/babble-drachtio-auth" )
|
|
13
13
|
|
|
14
|
+
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
|
|
15
|
+
|
|
14
16
|
/*
|
|
15
17
|
Enum for different reasons for hangup.
|
|
16
18
|
*/
|
|
@@ -910,8 +912,15 @@ class call {
|
|
|
910
912
|
static async _parsesdpcandidates( target, sdp ) {
|
|
911
913
|
|
|
912
914
|
if( Array.isArray( sdp.media[ 0 ].candidates ) ) {
|
|
913
|
-
|
|
915
|
+
let candidates = sdp.media[ 0 ].candidates
|
|
914
916
|
if( 0 < candidates.length ) {
|
|
917
|
+
if( callmanager.options.ignoreipv6candidates ) {
|
|
918
|
+
candidates = candidates.filter( ( c ) => {
|
|
919
|
+
const ismatch = ipv6regex.test( c.ip )
|
|
920
|
+
return !ismatch
|
|
921
|
+
} )
|
|
922
|
+
}
|
|
923
|
+
|
|
915
924
|
candidates.sort( ( l, r ) => { return r.priority - l.priority } )
|
|
916
925
|
target.port = candidates[ 0 ].port
|
|
917
926
|
|
|
@@ -1356,9 +1365,7 @@ class call {
|
|
|
1356
1365
|
.setconnectionaddress( this.channels.audio.local.address )
|
|
1357
1366
|
.setaudioport( this.channels.audio.local.port )
|
|
1358
1367
|
|
|
1359
|
-
|
|
1360
|
-
this.sdp.local.addcodecs( "2833" )
|
|
1361
|
-
}
|
|
1368
|
+
this.#checkandadd2833()
|
|
1362
1369
|
|
|
1363
1370
|
if( this._iswebrtc ) {
|
|
1364
1371
|
this.sdp.local.addssrc( this.channels.audio.local.ssrc )
|
|
@@ -1379,13 +1386,13 @@ class call {
|
|
|
1379
1386
|
if( !this.selectedcodec ) {
|
|
1380
1387
|
return this.hangup( hangupcodes.INCOMPATIBLE_DESTINATION )
|
|
1381
1388
|
}
|
|
1389
|
+
|
|
1390
|
+
this.sdp.remote.select( this.selectedcodec )
|
|
1382
1391
|
|
|
1383
1392
|
const remoteaudio = this.sdp.remote.getaudio()
|
|
1384
1393
|
if( !remoteaudio ) {
|
|
1385
1394
|
return this.hangup( hangupcodes.INCOMPATIBLE_DESTINATION )
|
|
1386
1395
|
}
|
|
1387
|
-
|
|
1388
|
-
this.sdp.remote.select( this.selectedcodec )
|
|
1389
1396
|
|
|
1390
1397
|
await call._parsesdpcandidates( remoteaudio, this.sdp.remote.sdp )
|
|
1391
1398
|
|
|
@@ -2494,6 +2501,20 @@ class call {
|
|
|
2494
2501
|
|
|
2495
2502
|
}
|
|
2496
2503
|
|
|
2504
|
+
/**
|
|
2505
|
+
* If we have remote sdp we have to check they support 2833 before we add backand our options permit it.
|
|
2506
|
+
* If we have no remote sdp then we only check our options.
|
|
2507
|
+
*/
|
|
2508
|
+
#checkandadd2833() {
|
|
2509
|
+
if( this.sdp.remote ) {
|
|
2510
|
+
if( this.options.rfc2833 && this.sdp.remote.has( "2833" ) ) {
|
|
2511
|
+
this.sdp.local.addcodecs( "2833" )
|
|
2512
|
+
}
|
|
2513
|
+
} else if( this.options.rfc2833 ) {
|
|
2514
|
+
this.sdp.local.addcodecs( "2833" )
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2497
2518
|
/**
|
|
2498
2519
|
*
|
|
2499
2520
|
*/
|
|
@@ -2508,9 +2529,7 @@ class call {
|
|
|
2508
2529
|
this.sdp.local.setaudioport( this.channels.audio.local.port )
|
|
2509
2530
|
.setconnectionaddress( this.channels.audio.local.address )
|
|
2510
2531
|
|
|
2511
|
-
|
|
2512
|
-
this.sdp.local.addcodecs( "2833" )
|
|
2513
|
-
}
|
|
2532
|
+
this.#checkandadd2833()
|
|
2514
2533
|
|
|
2515
2534
|
/* DTLS is only supported ( outbound ) on websocket connections */
|
|
2516
2535
|
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/sdp.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
const expect = require( "chai" ).expect
|
|
4
|
-
const sdp = require( "../../lib/sdp
|
|
5
|
-
const call = require( "../../lib/call
|
|
4
|
+
const sdp = require( "../../lib/sdp" )
|
|
5
|
+
const call = require( "../../lib/call" )
|
|
6
|
+
const callmanager = require( "../../index" )
|
|
6
7
|
|
|
7
8
|
describe( "sdp", function() {
|
|
8
9
|
|
|
@@ -643,4 +644,133 @@ a=rtcp-mux`
|
|
|
643
644
|
expect( bvdesktopinvite200sdpobj.intersection( ourcodecs, true ) ).to.equal( "g722" )
|
|
644
645
|
expect( magrathea200sdpobj.intersection( ourcodecs, true ) ).to.equal( "pcma" )
|
|
645
646
|
} )
|
|
647
|
+
|
|
648
|
+
it( "outbound example - inc ipv6", async () => {
|
|
649
|
+
|
|
650
|
+
const sdpstr = `v=0
|
|
651
|
+
o=- 7873703533563891424 2 IN IP4 127.0.0.1
|
|
652
|
+
s=-
|
|
653
|
+
t=0 0
|
|
654
|
+
a=group:BUNDLE 0
|
|
655
|
+
a=extmap-allow-mixed
|
|
656
|
+
a=msid-semantic: WMS a46039f4-1857-410e-b1cc-215c09878068
|
|
657
|
+
m=audio 41645 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
|
|
658
|
+
c=IN IP4 86.169.150.38
|
|
659
|
+
a=rtcp:9 IN IP4 0.0.0.0
|
|
660
|
+
a=candidate:532873972 1 udp 2122131711 2a00:23c6:e093:a801:6722:f7bb:aeeb:5e04 39087 typ host generation 0 network-id 4 network-cost 10
|
|
661
|
+
a=candidate:226183667 1 udp 1685987071 86.169.150.38 41645 typ srflx raddr 172.17.0.1 rport 41645 generation 0 network-id 2
|
|
662
|
+
a=ice-ufrag:c97P
|
|
663
|
+
a=ice-pwd:sK0NGVPIIx4/qEX+tCVW5dzH
|
|
664
|
+
a=ice-options:trickle
|
|
665
|
+
a=fingerprint:sha-256 0F:37:28:0F:66:1B:7E:D5:36:A4:EB:2D:D4:A8:6E:33:69:31:3B:D4:7B:71:0B:DE:41:09:D1:6C:1E:56:02:1C
|
|
666
|
+
a=setup:actpass
|
|
667
|
+
a=mid:0
|
|
668
|
+
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
|
669
|
+
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
|
670
|
+
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
|
671
|
+
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
|
|
672
|
+
a=sendrecv
|
|
673
|
+
a=msid:a46039f4-1857-410e-b1cc-215c09878068 ce8c9c25-2ea0-4079-aaa5-54f771d53310
|
|
674
|
+
a=rtcp-mux
|
|
675
|
+
a=rtpmap:111 opus/48000/2
|
|
676
|
+
a=rtcp-fb:111 transport-cc
|
|
677
|
+
a=fmtp:111 minptime=10;useinbandfec=1
|
|
678
|
+
a=rtpmap:63 red/48000/2
|
|
679
|
+
a=fmtp:63 111/111
|
|
680
|
+
a=rtpmap:9 G722/8000
|
|
681
|
+
a=rtpmap:0 PCMU/8000
|
|
682
|
+
a=rtpmap:8 PCMA/8000
|
|
683
|
+
a=rtpmap:13 CN/8000
|
|
684
|
+
a=rtpmap:110 telephone-event/48000
|
|
685
|
+
a=rtpmap:126 telephone-event/8000
|
|
686
|
+
a=ssrc:222390620 cname:q7Is0hRbTrTbcMJM
|
|
687
|
+
a=ssrc:222390620 msid:a46039f4-1857-410e-b1cc-215c09878068 ce8c9c25-2ea0-4079-aaa5-54f771d53310
|
|
688
|
+
`
|
|
689
|
+
callmanager.callmanager( { srf: { use: () => {} } } )
|
|
690
|
+
const sdpobj = sdp.create( sdpstr )
|
|
691
|
+
const target = {}
|
|
692
|
+
await call._parsesdpcandidates( target, sdpobj.sdp )
|
|
693
|
+
sdpobj.intersection( "g722", true )
|
|
694
|
+
|
|
695
|
+
/* our default is to ignore IPv6 addresses (until projectrtp supports it) */
|
|
696
|
+
expect( target.port ).to.equal( 41645 )
|
|
697
|
+
expect( target.address ).to.equal( "86.169.150.38" )
|
|
698
|
+
|
|
699
|
+
|
|
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
|
+
} )
|
|
646
776
|
} )
|