@babblevoice/babble-drachtio-callmanager 2.1.1 → 2.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/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
- const candidates = sdp.media[ 0 ].candidates
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
 
@@ -1037,10 +1046,8 @@ class call {
1037
1046
  } else {
1038
1047
  channeldef = call._createchannelremotedef( target.address, target.port, target.audio.payloads[ 0 ] )
1039
1048
  }
1040
-
1041
- const other = this.other
1042
- if( other && other.channels.audio ) this.channels.audio = await other.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
1043
- else this.channels.audio = await projectrtp.openchannel( channeldef, this._handlechannelevents.bind( this ) )
1049
+
1050
+ await this.#openrelatedchannel()
1044
1051
 
1045
1052
  this.sdp.local = sdpgen.create()
1046
1053
  .addcodecs( this.selectedcodec )
@@ -1069,7 +1076,7 @@ class call {
1069
1076
 
1070
1077
  /**
1071
1078
  Sometimes we don't care who if we are the parent or child - we just want the other party
1072
- @return {object|bool} returns call object or if none false
1079
+ @return { object|bool } returns call object or if none false
1073
1080
  */
1074
1081
  get other() {
1075
1082
  if( this.parent ) return this.parent
@@ -1347,23 +1354,25 @@ class call {
1347
1354
  */
1348
1355
  async #openchannelsforanswer( channeldef ) {
1349
1356
  if( this.channels.audio ) {
1357
+ /* we have already opened a channel (probably early now answering) */
1350
1358
  this.channels.audio.remote( channeldef.remote )
1351
1359
  } else {
1352
- const ch = await projectrtp.openchannel( channeldef, this._handlechannelevents.bind( this ) )
1353
- this.channels.audio = ch
1360
+
1361
+ await this.#openrelatedchannel( channeldef )
1362
+
1354
1363
  this.sdp.local = sdpgen.create()
1355
1364
  .addcodecs( this.selectedcodec )
1356
- .setconnectionaddress( ch.local.address )
1357
- .setaudioport( ch.local.port )
1365
+ .setconnectionaddress( this.channels.audio.local.address )
1366
+ .setaudioport( this.channels.audio.local.port )
1358
1367
 
1359
1368
  if( this.options.rfc2833 ) {
1360
1369
  this.sdp.local.addcodecs( "2833" )
1361
1370
  }
1362
1371
 
1363
1372
  if( this._iswebrtc ) {
1364
- this.sdp.local.addssrc( ch.local.ssrc )
1365
- .secure( ch.local.dtls.fingerprint, channeldef.remote.dtls.mode )
1366
- .addicecandidates( ch.local.address, ch.local.port, ch.local.icepwd )
1373
+ this.sdp.local.addssrc( this.channels.audio.local.ssrc )
1374
+ .secure( this.channels.audio.local.dtls.fingerprint, channeldef.remote.dtls.mode )
1375
+ .addicecandidates( this.channels.audio.local.address, this.channels.audio.local.port, this.channels.audio.local.icepwd )
1367
1376
  .rtcpmux()
1368
1377
  }
1369
1378
  }
@@ -1379,13 +1388,13 @@ class call {
1379
1388
  if( !this.selectedcodec ) {
1380
1389
  return this.hangup( hangupcodes.INCOMPATIBLE_DESTINATION )
1381
1390
  }
1391
+
1392
+ this.sdp.remote.select( this.selectedcodec )
1382
1393
 
1383
1394
  const remoteaudio = this.sdp.remote.getaudio()
1384
1395
  if( !remoteaudio ) {
1385
1396
  return this.hangup( hangupcodes.INCOMPATIBLE_DESTINATION )
1386
1397
  }
1387
-
1388
- this.sdp.remote.select( this.selectedcodec )
1389
1398
 
1390
1399
  await call._parsesdpcandidates( remoteaudio, this.sdp.remote.sdp )
1391
1400
 
@@ -2478,6 +2487,22 @@ class call {
2478
2487
  return child
2479
2488
  }
2480
2489
 
2490
+ /**
2491
+ * If any of our one of our related calls has a channel open
2492
+ * try and use it. NB (other favours the answered if not then the first)
2493
+ * It will use the channel on that call.
2494
+ * @param { object } [ channeldef ]
2495
+ */
2496
+ async #openrelatedchannel( channeldef ) {
2497
+
2498
+ const relatedcall = this.other
2499
+ if( relatedcall && relatedcall.channels.audio )
2500
+ this.channels.audio = await relatedcall.channels.audio.openchannel( channeldef, this._handlechannelevents.bind( this ) )
2501
+ else
2502
+ this.channels.audio = await projectrtp.openchannel( channeldef, this._handlechannelevents.bind( this ) )
2503
+
2504
+ }
2505
+
2481
2506
  /**
2482
2507
  *
2483
2508
  */
@@ -2485,8 +2510,8 @@ class call {
2485
2510
  if( this.options.late ) {
2486
2511
  this.options.noAck = true /* this is a MUST for late negotiation */
2487
2512
  } else {
2488
- if( this.options.parent && this.options.parent.channels.audio ) this.channels.audio = await this.options.parent.channels.audio.openchannel( this._handlechannelevents.bind( this ) )
2489
- else this.channels.audio = await projectrtp.openchannel( this._handlechannelevents.bind( this ) )
2513
+
2514
+ await this.#openrelatedchannel()
2490
2515
 
2491
2516
  this.sdp.local = sdpgen.create().addcodecs( this.options.preferedcodecs )
2492
2517
  this.sdp.local.setaudioport( this.channels.audio.local.port )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babblevoice/babble-drachtio-callmanager",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Call processing to create a PBX",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,8 +1,9 @@
1
1
 
2
2
 
3
3
  const expect = require( "chai" ).expect
4
- const sdp = require( "../../lib/sdp.js" )
5
- const call = require( "../../lib/call.js" )
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,58 @@ 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
+ } )
646
701
  } )