@babblevoice/babble-drachtio-callmanager 3.3.2 → 3.3.4
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/jsconfig.json +2 -2
- package/lib/call.js +102 -40
- package/package.json +1 -1
- package/test/interface/call.js +14 -11
- package/test/interface/sdp.js +75 -0
package/jsconfig.json
CHANGED
package/lib/call.js
CHANGED
|
@@ -10,7 +10,7 @@ const callstore = require( "./store.js" )
|
|
|
10
10
|
|
|
11
11
|
const sipauth = require( "@babblevoice/babble-drachtio-auth" )
|
|
12
12
|
|
|
13
|
-
const ipv6regex = /^(?:
|
|
13
|
+
const ipv6regex = /^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/
|
|
14
14
|
const parseurire = /^(sips?):(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/
|
|
15
15
|
const parseuriparamsre = /([^;=]+)(=([^;=]+))?/g
|
|
16
16
|
const parseuriheadersre = /[^&=]+=[^&=]+/g
|
|
@@ -218,7 +218,8 @@ class call {
|
|
|
218
218
|
"audio": undefined,
|
|
219
219
|
"closed": {
|
|
220
220
|
"audio": []
|
|
221
|
-
}
|
|
221
|
+
},
|
|
222
|
+
"count": 0
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
/**
|
|
@@ -554,9 +555,9 @@ class call {
|
|
|
554
555
|
#fromcontact( startingpoint ) {
|
|
555
556
|
const dest = parseuri( this.options.contact )
|
|
556
557
|
if( !dest ) return
|
|
557
|
-
startingpoint.uri = dest.uri
|
|
558
|
-
startingpoint.user = dest.user
|
|
559
|
-
startingpoint.host = dest.host
|
|
558
|
+
if( dest.uri ) startingpoint.uri = dest.uri
|
|
559
|
+
if( dest.user ) startingpoint.user = dest.user
|
|
560
|
+
if( dest.host ) startingpoint.host = dest.host
|
|
560
561
|
}
|
|
561
562
|
|
|
562
563
|
#fromdestination( startingpoint ) {
|
|
@@ -657,7 +658,6 @@ class call {
|
|
|
657
658
|
this.#calleridforuac( startingpoint )
|
|
658
659
|
} else {
|
|
659
660
|
const other = this.other
|
|
660
|
-
|
|
661
661
|
if( other ) {
|
|
662
662
|
if( "uas" == other.type ) {
|
|
663
663
|
other.#calleridforuas( startingpoint )
|
|
@@ -731,6 +731,9 @@ class call {
|
|
|
731
731
|
* @param { string } c
|
|
732
732
|
*/
|
|
733
733
|
set callerid( c ) {
|
|
734
|
+
|
|
735
|
+
if( undefined == c ) return
|
|
736
|
+
|
|
734
737
|
if( !this.options.callerid ) this.options.callerid = {}
|
|
735
738
|
if( !this.options.callerid.number ) this.options.callerid.number = ""
|
|
736
739
|
|
|
@@ -742,6 +745,8 @@ class call {
|
|
|
742
745
|
*/
|
|
743
746
|
set calleridname( c ) {
|
|
744
747
|
|
|
748
|
+
if( undefined == c ) return
|
|
749
|
+
|
|
745
750
|
if( !this.options.callerid ) this.options.callerid = {}
|
|
746
751
|
if( !this.options.callerid.name ) this.options.callerid.name = ""
|
|
747
752
|
|
|
@@ -1713,13 +1718,20 @@ class call {
|
|
|
1713
1718
|
this.channels.closed.audio.push( e )
|
|
1714
1719
|
}
|
|
1715
1720
|
|
|
1716
|
-
this.channels.
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
}
|
|
1721
|
+
this.channels.count--
|
|
1722
|
+
|
|
1723
|
+
if ( 0 === this.channels.count ) {
|
|
1724
|
+
this.channels.audio = false
|
|
1721
1725
|
|
|
1722
|
-
|
|
1726
|
+
if( this._state._onhangup ) {
|
|
1727
|
+
this._cleanup()
|
|
1728
|
+
return
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// This will handle _cleanup() later
|
|
1732
|
+
// based on the above flag
|
|
1733
|
+
this.hangup()
|
|
1734
|
+
}
|
|
1723
1735
|
}
|
|
1724
1736
|
|
|
1725
1737
|
/**
|
|
@@ -2006,9 +2018,13 @@ class call {
|
|
|
2006
2018
|
same as used elsewhere. If a bond has been attached to the call, we will
|
|
2007
2019
|
try to reuse an existing channel.
|
|
2008
2020
|
@param { object } [ channeldef ]
|
|
2021
|
+
@param { object } [ newchannel ]
|
|
2009
2022
|
@private
|
|
2010
2023
|
*/
|
|
2011
|
-
async reinvite( channeldef ) {
|
|
2024
|
+
async reinvite( channeldef, newchannel ) {
|
|
2025
|
+
|
|
2026
|
+
if ( newchannel )
|
|
2027
|
+
this.channels.audio = newchannel
|
|
2012
2028
|
|
|
2013
2029
|
if ( !channeldef )
|
|
2014
2030
|
channeldef = await this.#createchannelremotedef()
|
|
@@ -2041,17 +2057,43 @@ class call {
|
|
|
2041
2057
|
const channeldef = await othercall.#createchannelremotedef()
|
|
2042
2058
|
|
|
2043
2059
|
const oldchannel = othercall.channels.audio
|
|
2044
|
-
|
|
2045
|
-
othercall.channels.audio = await this.channels.audio.openchannel( channeldef, othercall._handlechannelevents.bind( othercall ) )
|
|
2060
|
+
const newchannel = await this.#openchannel( channeldef, othercall )
|
|
2046
2061
|
|
|
2047
|
-
await othercall.bond( this ).reinvite( channeldef )
|
|
2062
|
+
await othercall.bond( this ).reinvite( channeldef, newchannel )
|
|
2048
2063
|
|
|
2049
|
-
await oldchannel.
|
|
2064
|
+
await oldchannel.unmix()
|
|
2065
|
+
oldchannel.close()
|
|
2050
2066
|
}
|
|
2051
2067
|
|
|
2052
2068
|
await this.channels.audio.mix( othercall.channels.audio )
|
|
2053
2069
|
}
|
|
2054
2070
|
|
|
2071
|
+
/**
|
|
2072
|
+
Mix two calls. If the two calls are on a different node
|
|
2073
|
+
the second call is bonded and reinvited.
|
|
2074
|
+
@param { object } channeldef - our call object which is early
|
|
2075
|
+
@param { call } bindcall - the call which will own the channel
|
|
2076
|
+
*/
|
|
2077
|
+
async #openchannel( channeldef, bindcall ) {
|
|
2078
|
+
|
|
2079
|
+
let chan = undefined
|
|
2080
|
+
|
|
2081
|
+
if ( !bindcall || !this.channels.audio ) {
|
|
2082
|
+
chan = await projectrtp.openchannel(
|
|
2083
|
+
channeldef, this._handlechannelevents.bind( this ) )
|
|
2084
|
+
} else {
|
|
2085
|
+
chan = await this.channels.audio.openchannel(
|
|
2086
|
+
channeldef, bindcall._handlechannelevents.bind( bindcall ) )
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
if ( bindcall )
|
|
2090
|
+
bindcall.channels.count++
|
|
2091
|
+
else
|
|
2092
|
+
this.channels.count++
|
|
2093
|
+
|
|
2094
|
+
return chan
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2055
2097
|
/**
|
|
2056
2098
|
*
|
|
2057
2099
|
* @param { object } req
|
|
@@ -2152,20 +2194,32 @@ class call {
|
|
|
2152
2194
|
RTP stall timer will kick in first, but if a call is placed on hold followed
|
|
2153
2195
|
by AWOL... */
|
|
2154
2196
|
this._timers.seinterval = setInterval( async () => {
|
|
2155
|
-
const opts = {
|
|
2156
|
-
"method": "INVITE",
|
|
2157
|
-
"body": this.sdp.local.toString()
|
|
2158
|
-
}
|
|
2159
2197
|
|
|
2160
|
-
|
|
2161
|
-
.catch( ( e ) => {
|
|
2162
|
-
console.trace( e )
|
|
2163
|
-
this.hangup( hangupcodes.USER_GONE )
|
|
2164
|
-
} )
|
|
2198
|
+
try{
|
|
2165
2199
|
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2200
|
+
if( this.destroyed ) {
|
|
2201
|
+
/* this should be done - but we are still running */
|
|
2202
|
+
clearInterval( this._timers.seinterval )
|
|
2203
|
+
return
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
if( "function" != typeof dialog.request ) return
|
|
2207
|
+
|
|
2208
|
+
const opts = {
|
|
2209
|
+
"method": "INVITE",
|
|
2210
|
+
"body": this.sdp.local.toString()
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
const res = await dialog.request( opts )
|
|
2214
|
+
.catch( ( e ) => {
|
|
2215
|
+
console.trace( e )
|
|
2216
|
+
this.hangup( hangupcodes.USER_GONE )
|
|
2217
|
+
} )
|
|
2218
|
+
|
|
2219
|
+
if( !this.destroyed && 200 != res.msg.status ) {
|
|
2220
|
+
this.hangup( hangupcodes.USER_GONE )
|
|
2221
|
+
}
|
|
2222
|
+
} catch( e ) { /* empty */ }
|
|
2169
2223
|
|
|
2170
2224
|
}, callmanager.options.seexpire )
|
|
2171
2225
|
|
|
@@ -2563,7 +2617,6 @@ class call {
|
|
|
2563
2617
|
@private
|
|
2564
2618
|
*/
|
|
2565
2619
|
_cleanup() {
|
|
2566
|
-
|
|
2567
2620
|
if( this.state.cleaned ) return
|
|
2568
2621
|
this.state.cleaned = true
|
|
2569
2622
|
|
|
@@ -2621,7 +2674,7 @@ class call {
|
|
|
2621
2674
|
}
|
|
2622
2675
|
this._state._onhangup = true
|
|
2623
2676
|
|
|
2624
|
-
/* hangup our children */
|
|
2677
|
+
/* hangup our children but, no other relations - i.e. children of our parent */
|
|
2625
2678
|
const hangups = []
|
|
2626
2679
|
for( const child of this.children ) {
|
|
2627
2680
|
hangups.push( child.hangup( this.hangup_cause ) )
|
|
@@ -2639,7 +2692,7 @@ class call {
|
|
|
2639
2692
|
if( this.channels.audio ) {
|
|
2640
2693
|
this.channels.audio.close()
|
|
2641
2694
|
this._timers.cleanup = setTimeout( () => {
|
|
2642
|
-
console.trace( "Timeout waiting for channel close, cleaning up anyway
|
|
2695
|
+
console.trace( this.uuid + " Timeout waiting for channel close, cleaning up anyway, chan uuid: " + this.channels.audio.uuid + ", channel count: " + this.channels.count )
|
|
2643
2696
|
this._cleanup()
|
|
2644
2697
|
}, 60 * 1000 )
|
|
2645
2698
|
|
|
@@ -2704,12 +2757,19 @@ class call {
|
|
|
2704
2757
|
* Send an UPDATE. Use to updated called id, caller id, sdp etc. Send in dialog - TODO look how to send
|
|
2705
2758
|
* early as this is recomended in the RFC.
|
|
2706
2759
|
*/
|
|
2707
|
-
async update() {
|
|
2760
|
+
async update( remote ) {
|
|
2708
2761
|
|
|
2709
2762
|
/* if we are asked to update it suggests we have received new information and overrides should go */
|
|
2710
2763
|
delete this.options.callerid
|
|
2711
2764
|
delete this.options.calledid
|
|
2712
2765
|
|
|
2766
|
+
if( remote ) {
|
|
2767
|
+
if( remote.callerid ) {
|
|
2768
|
+
this.callerid = remote.callerid.number
|
|
2769
|
+
this.calleridname = remote.callerid.name
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2713
2773
|
this._em.emit( "call.updated", this )
|
|
2714
2774
|
callmanager.options.em.emit( "call.updated", this )
|
|
2715
2775
|
|
|
@@ -2841,11 +2901,11 @@ class call {
|
|
|
2841
2901
|
if( callbacks.prebridge ) return callbacks.prebridge( c )
|
|
2842
2902
|
}
|
|
2843
2903
|
|
|
2844
|
-
ourcallbacks.confirm = ( c,
|
|
2904
|
+
ourcallbacks.confirm = ( /** @type { call } */ c, /** @type { any } */ cookie ) => {
|
|
2845
2905
|
if( false !== waitonchildrenresolve ) {
|
|
2846
2906
|
waitonchildrenresolve( c )
|
|
2847
2907
|
waitonchildrenresolve = false
|
|
2848
|
-
if( callbacks.confirm ) callbacks.confirm( c,
|
|
2908
|
+
if( callbacks.confirm ) callbacks.confirm( c, cookie )
|
|
2849
2909
|
}
|
|
2850
2910
|
}
|
|
2851
2911
|
|
|
@@ -2885,18 +2945,18 @@ class call {
|
|
|
2885
2945
|
detect which mode the channel is in - but the channels property will exist on a connect
|
|
2886
2946
|
style channel. projectrtp will getrelatives a rewrite to support only one. */
|
|
2887
2947
|
if( relatedcall && relatedcall.channels.audio && relatedcall.channels.audio.channels ) {
|
|
2888
|
-
this.channels.audio = await this
|
|
2948
|
+
this.channels.audio = await this.#openchannel( channeldef, this )
|
|
2889
2949
|
return
|
|
2890
2950
|
}
|
|
2891
2951
|
|
|
2892
2952
|
for( const other of this.relatives ) {
|
|
2893
2953
|
if( other.channels && other.channels.audio ) {
|
|
2894
|
-
this.channels.audio = await other
|
|
2954
|
+
this.channels.audio = await other.#openchannel( channeldef, this )
|
|
2895
2955
|
return
|
|
2896
2956
|
}
|
|
2897
2957
|
}
|
|
2898
2958
|
|
|
2899
|
-
this.channels.audio = await
|
|
2959
|
+
this.channels.audio = await this.#openchannel( channeldef )
|
|
2900
2960
|
}
|
|
2901
2961
|
|
|
2902
2962
|
/**
|
|
@@ -2953,17 +3013,19 @@ class call {
|
|
|
2953
3013
|
return this
|
|
2954
3014
|
}
|
|
2955
3015
|
|
|
3016
|
+
const hangups = []
|
|
2956
3017
|
if( this.parent ) {
|
|
2957
3018
|
for( const child of this.parent.children ) {
|
|
2958
|
-
if( child
|
|
3019
|
+
if( child !== this ) {
|
|
2959
3020
|
child.detach()
|
|
2960
3021
|
/* do not await - we do not want to delay the winner in
|
|
2961
3022
|
connecting by waiting for the completion of the hangups */
|
|
2962
|
-
child.hangup( hangupcodes.LOSE_RACE )
|
|
3023
|
+
hangups.push( child.hangup( hangupcodes.LOSE_RACE ) )
|
|
2963
3024
|
}
|
|
2964
3025
|
}
|
|
2965
3026
|
}
|
|
2966
3027
|
|
|
3028
|
+
await Promise.all( hangups )
|
|
2967
3029
|
callstore.set( this )
|
|
2968
3030
|
|
|
2969
3031
|
if ( this._dialog.sip )
|
package/package.json
CHANGED
package/test/interface/call.js
CHANGED
|
@@ -237,6 +237,7 @@ describe( "call object", function() {
|
|
|
237
237
|
"type": "callerid"
|
|
238
238
|
} )
|
|
239
239
|
|
|
240
|
+
/* when newuacv returns, only one of the contacts should hacve succeeded */
|
|
240
241
|
const child = await call.newuac( { "entity": { "uri": "1000@dummy" } } )
|
|
241
242
|
|
|
242
243
|
expect( await callstore.stats() ).to.deep.include( {
|
|
@@ -257,7 +258,7 @@ describe( "call object", function() {
|
|
|
257
258
|
child.update()
|
|
258
259
|
|
|
259
260
|
expect( requestoptions.method ).to.equal( "UPDATE" )
|
|
260
|
-
expect( requestoptions.headers[ "
|
|
261
|
+
expect( requestoptions.headers[ "remote-party-id" ] ).to.equal( "\"\" <sip:0123456789@someotherrealm.com>;party=calling;screen=yes" )
|
|
261
262
|
|
|
262
263
|
await call.hangup()
|
|
263
264
|
|
|
@@ -404,8 +405,8 @@ describe( "call object", function() {
|
|
|
404
405
|
expect( children[ 0 ].hangup_cause.reason ).equal( "USER_BUSY" )
|
|
405
406
|
|
|
406
407
|
expect( await callstore.stats() ).to.deep.include( {
|
|
407
|
-
"storebycallid":
|
|
408
|
-
"storebyuuid":
|
|
408
|
+
"storebycallid": 2,
|
|
409
|
+
"storebyuuid": 2,
|
|
409
410
|
"storebyentity": 0
|
|
410
411
|
} )
|
|
411
412
|
|
|
@@ -446,6 +447,9 @@ describe( "call object", function() {
|
|
|
446
447
|
expect( children[ 0 ].hangup_cause.reason ).equal( "REQUEST_TIMEOUT" )
|
|
447
448
|
expect( children[ 0 ].hangup_cause.src ).equal( "us" )
|
|
448
449
|
|
|
450
|
+
/* when we get here the clean up is on teh event loop */
|
|
451
|
+
await new Promise( resolve => setTimeout( resolve, 100 ) )
|
|
452
|
+
|
|
449
453
|
expect( await callstore.stats() ).to.deep.include( {
|
|
450
454
|
"storebycallid": 1,
|
|
451
455
|
"storebyuuid": 1,
|
|
@@ -785,7 +789,7 @@ describe( "call object", function() {
|
|
|
785
789
|
|
|
786
790
|
await call.newuac( options, { "early": ( c ) => c.hangup() } )
|
|
787
791
|
|
|
788
|
-
expect( createuacoptions.headers[ "
|
|
792
|
+
expect( createuacoptions.headers[ "remote-party-id" ] ).to.equal( "\"\" <sip:0000000000@localhost.localdomain>;party=calling;screen=yes" )
|
|
789
793
|
expect( createuacoptions.late ).to.be.true
|
|
790
794
|
} )
|
|
791
795
|
|
|
@@ -836,17 +840,16 @@ describe( "call object", function() {
|
|
|
836
840
|
let requestoptions
|
|
837
841
|
c._dialog.on( "request", ( options ) => requestoptions = options )
|
|
838
842
|
|
|
839
|
-
await c.update( { "
|
|
840
|
-
"
|
|
841
|
-
"
|
|
842
|
-
"username": "kermy"
|
|
843
|
+
await c.update( { "callerid": {
|
|
844
|
+
"name": "Kermit",
|
|
845
|
+
"number": "kermy"
|
|
843
846
|
} } )
|
|
844
847
|
|
|
845
848
|
c.hangup()
|
|
846
849
|
|
|
847
850
|
expect( requestoptions.method ).to.equal( "UPDATE" )
|
|
848
851
|
expect( requestoptions.body ).to.be.a( "string" )
|
|
849
|
-
expect( requestoptions.headers[ "
|
|
852
|
+
expect( requestoptions.headers[ "remote-party-id" ] ).to.equal( "\"Kermit\" <sip:kermy@localhost.localdomain>;party=calling;screen=yes" )
|
|
850
853
|
|
|
851
854
|
} )
|
|
852
855
|
|
|
@@ -1148,7 +1151,7 @@ describe( "call object", function() {
|
|
|
1148
1151
|
const c = await call.newuac( options )
|
|
1149
1152
|
|
|
1150
1153
|
/* no default configured */
|
|
1151
|
-
expect( c.options.headers[ "
|
|
1154
|
+
expect( c.options.headers[ "remote-party-id" ] ).to.equal( "\"Hello\" <sip:0000000000@localhost.localdomain>;party=calling;screen=yes" )
|
|
1152
1155
|
|
|
1153
1156
|
c._onhangup( "wire" )
|
|
1154
1157
|
|
|
@@ -1169,7 +1172,7 @@ describe( "call object", function() {
|
|
|
1169
1172
|
|
|
1170
1173
|
|
|
1171
1174
|
/* no default configured */
|
|
1172
|
-
expect( c.options.headers[ "
|
|
1175
|
+
expect( c.options.headers[ "remote-party-id" ] ).to.equal( "\"\" <sip:012345789@localhost.localdomain>;party=calling;screen=yes" )
|
|
1173
1176
|
|
|
1174
1177
|
c._onhangup( "wire" )
|
|
1175
1178
|
|
package/test/interface/sdp.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const expect = require( "chai" ).expect
|
|
4
4
|
const sdp = require( "../../lib/sdp" )
|
|
5
5
|
|
|
6
|
+
const dns = require( "node:dns" )
|
|
7
|
+
|
|
6
8
|
describe( "sdp", function() {
|
|
7
9
|
|
|
8
10
|
it( "create new sdp object", async function() {
|
|
@@ -927,4 +929,77 @@ a=rtpmap:127 telephone-event/8000
|
|
|
927
929
|
expect( outsdpstring ).include( outsdpstring, "a=rtpmap:110 ilbc/8000" )
|
|
928
930
|
|
|
929
931
|
} )
|
|
932
|
+
|
|
933
|
+
it( "SDP IP V6 candidate", async () => {
|
|
934
|
+
const wsssdp = `v=0
|
|
935
|
+
o=- 4684977919666729506 2 IN IP4 127.0.0.1
|
|
936
|
+
s=-
|
|
937
|
+
t=0 0
|
|
938
|
+
a=group:BUNDLE 0
|
|
939
|
+
a=extmap-allow-mixed
|
|
940
|
+
a=msid-semantic: WMS 2e008e23-265a-42a0-ba6f-d147a9d0ca42
|
|
941
|
+
m=audio 28022 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
|
|
942
|
+
c=IN IP4 209.35.84.57
|
|
943
|
+
a=rtcp:9 IN IP4 0.0.0.0
|
|
944
|
+
a=candidate:1446275835 1 udp 2122129151 192.168.1.108 52396 typ host generation 0 network-id 1
|
|
945
|
+
a=candidate:1833640547 1 udp 2122063615 172.25.160.1 52397 typ host generation 0 network-id 4
|
|
946
|
+
a=candidate:3642338680 1 udp 2122262783 2a01:4b00:ea24:b300:10a8:8a7e:234c:3161 52398 typ host generation 0 network-id 2
|
|
947
|
+
a=candidate:4227024272 1 udp 2122197247 2a01:4b00:ea24:b300:f50b:e799:7a1:8cc3 52399 typ host generation 0 network-id 3
|
|
948
|
+
a=candidate:2218323828 1 udp 1685921535 209.35.84.57 28022 typ srflx raddr 192.168.1.108 rport 52396 generation 0 network-id 1
|
|
949
|
+
a=ice-ufrag:5emx
|
|
950
|
+
a=ice-pwd:T78uDKroul30L+4WytFCzZiv
|
|
951
|
+
a=ice-options:trickle
|
|
952
|
+
a=fingerprint:sha-256 AE:24:0F:8F:23:5C:EE:D5:F8:BD:EB:2C:86:15:13:44:A2:D1:30:9E:74:68:87:8C:50:80:F7:9A:6A:D9:3A:56
|
|
953
|
+
a=setup:actpass
|
|
954
|
+
a=mid:0
|
|
955
|
+
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
|
956
|
+
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
|
957
|
+
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
|
958
|
+
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
|
|
959
|
+
a=sendrecv
|
|
960
|
+
a=msid:2e008e23-265a-42a0-ba6f-d147a9d0ca42 ff52617f-a48b-454e-9d50-47367329f318
|
|
961
|
+
a=rtcp-mux
|
|
962
|
+
a=rtpmap:111 opus/48000/2
|
|
963
|
+
a=rtcp-fb:111 transport-cc
|
|
964
|
+
a=fmtp:111 minptime=10;useinbandfec=1
|
|
965
|
+
a=rtpmap:63 red/48000/2
|
|
966
|
+
a=fmtp:63 111/111
|
|
967
|
+
a=rtpmap:9 G722/8000
|
|
968
|
+
a=rtpmap:0 PCMU/8000
|
|
969
|
+
a=rtpmap:8 PCMA/8000
|
|
970
|
+
a=rtpmap:13 CN/8000
|
|
971
|
+
a=rtpmap:110 telephone-event/48000
|
|
972
|
+
a=rtpmap:126 telephone-event/8000
|
|
973
|
+
a=ssrc:2953770750 cname:/DZABa/Op+oV703F
|
|
974
|
+
a=ssrc:2953770750 msid:2e008e23-265a-42a0-ba6f-d147a9d0ca42 ff52617f-a48b-454e-9d50-47367329f318
|
|
975
|
+
`.replace( /\r\n/g, "\n" ).replace( /\n/g, "\r\n" )
|
|
976
|
+
|
|
977
|
+
const sdpobj = sdp.create( wsssdp )
|
|
978
|
+
const target = sdpobj.getaudio()
|
|
979
|
+
const ignoreipv6candidates = true
|
|
980
|
+
const ipv6regex = /^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/
|
|
981
|
+
|
|
982
|
+
let candidates = sdpobj.sdp.media[ 0 ].candidates
|
|
983
|
+
if( 0 < candidates.length ) {
|
|
984
|
+
if( ignoreipv6candidates ) {
|
|
985
|
+
candidates = candidates.filter( ( c ) => {
|
|
986
|
+
const ismatch = ipv6regex.test( c.ip )
|
|
987
|
+
return !ismatch
|
|
988
|
+
} )
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
candidates.sort( ( l, r ) => { return r.priority - l.priority } )
|
|
992
|
+
target.port = candidates[ 0 ].port
|
|
993
|
+
|
|
994
|
+
await new Promise( ( resolve ) => {
|
|
995
|
+
dns.lookup( candidates[ 0 ].ip, ( err, result ) => {
|
|
996
|
+
if( !err ) target.address = result
|
|
997
|
+
resolve()
|
|
998
|
+
} )
|
|
999
|
+
} )
|
|
1000
|
+
|
|
1001
|
+
expect( target.address ).to.equal( "192.168.1.108" )
|
|
1002
|
+
expect( target.port ).to.equal( 52396 )
|
|
1003
|
+
}
|
|
1004
|
+
} )
|
|
930
1005
|
} )
|