@babblevoice/babble-drachtio-callmanager 2.2.3 → 2.2.5
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 +154 -98
- package/lib/callmanager.js +8 -0
- package/lib/store.js +7 -0
- package/package.json +1 -1
- package/test/interface/call.js +16 -7
- package/test/interface/callmanager.js +5 -1
- package/test/mock/srf.js +1 -1
- package/test/unit/call.js +7 -4
package/lib/call.js
CHANGED
|
@@ -116,6 +116,8 @@ class call {
|
|
|
116
116
|
*/
|
|
117
117
|
this.type = "uac"
|
|
118
118
|
|
|
119
|
+
this.privacy = false
|
|
120
|
+
|
|
119
121
|
/**
|
|
120
122
|
@typedef { Object } callstate
|
|
121
123
|
@property { boolean } trying
|
|
@@ -429,7 +431,7 @@ class call {
|
|
|
429
431
|
"uri": this._entity.uri,
|
|
430
432
|
"user": this._entity.username,
|
|
431
433
|
"host": this._entity.realm,
|
|
432
|
-
"privacy":
|
|
434
|
+
"privacy": this.privacy,
|
|
433
435
|
"type": "calledid"
|
|
434
436
|
}
|
|
435
437
|
}
|
|
@@ -441,7 +443,7 @@ class call {
|
|
|
441
443
|
"uri": this.options.contact,
|
|
442
444
|
"user": parseduri.user,
|
|
443
445
|
"host": parseduri.host,
|
|
444
|
-
"privacy":
|
|
446
|
+
"privacy": this.privacy,
|
|
445
447
|
"type": "calledid"
|
|
446
448
|
}
|
|
447
449
|
}
|
|
@@ -452,7 +454,7 @@ class call {
|
|
|
452
454
|
"uri": "",
|
|
453
455
|
"user": "0000000000",
|
|
454
456
|
"host": "localhost.localdomain",
|
|
455
|
-
"privacy":
|
|
457
|
+
"privacy": this.privacy,
|
|
456
458
|
"type": "calledid"
|
|
457
459
|
}
|
|
458
460
|
}
|
|
@@ -892,6 +894,9 @@ class call {
|
|
|
892
894
|
other.parent = this
|
|
893
895
|
this.children.add( other )
|
|
894
896
|
|
|
897
|
+
/* maintain privacy */
|
|
898
|
+
other.privacy = this.privacy
|
|
899
|
+
|
|
895
900
|
if( mix ) {
|
|
896
901
|
this.channels.audio.mix( other.channels.audio )
|
|
897
902
|
|
|
@@ -1105,7 +1110,7 @@ class call {
|
|
|
1105
1110
|
.rtcpmux()
|
|
1106
1111
|
}
|
|
1107
1112
|
|
|
1108
|
-
this
|
|
1113
|
+
this.#setdialog( await this._dialog.ack( this.sdp.local.toString() ) )
|
|
1109
1114
|
this._addevents( this._dialog )
|
|
1110
1115
|
|
|
1111
1116
|
await this.#answerparent()
|
|
@@ -1478,8 +1483,7 @@ class call {
|
|
|
1478
1483
|
}
|
|
1479
1484
|
} )
|
|
1480
1485
|
|
|
1481
|
-
this
|
|
1482
|
-
this._dialog = dialog
|
|
1486
|
+
this.#setdialog( dialog )
|
|
1483
1487
|
this.sip.tags.local = dialog.sip.localTag
|
|
1484
1488
|
callstore.set( this )
|
|
1485
1489
|
|
|
@@ -1759,16 +1763,52 @@ class call {
|
|
|
1759
1763
|
} )
|
|
1760
1764
|
}
|
|
1761
1765
|
|
|
1766
|
+
swapchannel( other ){
|
|
1767
|
+
|
|
1768
|
+
const this_audio = this.channels.audio
|
|
1769
|
+
const this_sdp = this.sdp.local
|
|
1770
|
+
const this_chem = this.channels.audio.em
|
|
1771
|
+
const other_chem = other.channels.audio.em
|
|
1772
|
+
|
|
1773
|
+
this.channels.audio = other.channels.audio
|
|
1774
|
+
this.channels.audio.em = this_chem
|
|
1775
|
+
this.sdp.local = other.sdp.local
|
|
1776
|
+
|
|
1777
|
+
other.channels.audio = this_audio
|
|
1778
|
+
other.channels.audio.em = other_chem
|
|
1779
|
+
other.sdp.local = this_sdp
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1762
1782
|
/**
|
|
1763
1783
|
Send out modified SDP to get the audio to the new location.
|
|
1764
1784
|
@private
|
|
1765
1785
|
*/
|
|
1766
|
-
async
|
|
1767
|
-
|
|
1768
|
-
|
|
1786
|
+
async reinvite() {
|
|
1787
|
+
|
|
1788
|
+
this.sdp.local
|
|
1789
|
+
.clearcodecs()
|
|
1790
|
+
.addcodecs( this.selectedcodec )
|
|
1791
|
+
.select( this.selectedcodec )
|
|
1792
|
+
.setaudiodirection( "sendrecv" )
|
|
1793
|
+
|
|
1794
|
+
if( true === callmanager.options.rfc2833 ) {
|
|
1795
|
+
this.sdp.local.addcodecs( "2833" )
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
const remotesdp = await this._dialog.modify( this.sdp.local.toString() )
|
|
1769
1799
|
.catch( ( e ) => {
|
|
1770
1800
|
console.trace( e )
|
|
1771
1801
|
} )
|
|
1802
|
+
|
|
1803
|
+
if( remotesdp )
|
|
1804
|
+
this.sdp.remote = sdpgen.create( remotesdp )
|
|
1805
|
+
|
|
1806
|
+
const target = this.sdp.remote.getaudio()
|
|
1807
|
+
if( target ) /* we should always get in here */
|
|
1808
|
+
this.channels.audio.remote( call._createchannelremotedef( target.address, target.port, this.selectedcodec ).remote )
|
|
1809
|
+
|
|
1810
|
+
/* Now inform our RTP server also - we might need to wait until the target has completed so need a notify mechanism */
|
|
1811
|
+
this.channels.audio.direction( { "send": true, "recv": true } )
|
|
1772
1812
|
}
|
|
1773
1813
|
|
|
1774
1814
|
/**
|
|
@@ -1842,6 +1882,7 @@ class call {
|
|
|
1842
1882
|
}, callmanager.options.seexpire )
|
|
1843
1883
|
|
|
1844
1884
|
dialog.on( "destroy", ( /* req */ ) => {
|
|
1885
|
+
if( this._state._hangup ) return
|
|
1845
1886
|
this._onhangup( "wire" )
|
|
1846
1887
|
} )
|
|
1847
1888
|
|
|
@@ -1921,7 +1962,13 @@ class call {
|
|
|
1921
1962
|
|
|
1922
1963
|
/* Auth the request - todo make a way of allow un authed refer - but we should nudge to secure */
|
|
1923
1964
|
if( this.referauthrequired ) {
|
|
1924
|
-
|
|
1965
|
+
if( this._auth.has( this._req ) ) {
|
|
1966
|
+
/* If the client has included an auth header check it immediatly */
|
|
1967
|
+
if( ! await this._onauth( this._req, this._res ) ) return
|
|
1968
|
+
} else {
|
|
1969
|
+
await this.auth()
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1925
1972
|
if( this.destroyed ) return
|
|
1926
1973
|
}
|
|
1927
1974
|
|
|
@@ -1973,6 +2020,12 @@ class call {
|
|
|
1973
2020
|
this.detach()
|
|
1974
2021
|
if( this.channels.audio ) this.channels.audio.unmix()
|
|
1975
2022
|
if( othercall.channels.audio ) othercall.channels.audio.unmix()
|
|
2023
|
+
|
|
2024
|
+
await Promise.all( [
|
|
2025
|
+
this.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
|
|
2026
|
+
othercall.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
|
|
2027
|
+
] )
|
|
2028
|
+
|
|
1976
2029
|
if( othercall.channels.audio && this.moh ) othercall.channels.audio.play( this.moh )
|
|
1977
2030
|
|
|
1978
2031
|
res.send( 202 )
|
|
@@ -2040,16 +2093,17 @@ class call {
|
|
|
2040
2093
|
return
|
|
2041
2094
|
}
|
|
2042
2095
|
|
|
2043
|
-
|
|
2044
|
-
|
|
2096
|
+
let b_1
|
|
2097
|
+
try {
|
|
2098
|
+
const searchfor = { "callid": replaces[ 1 ], "tags": { "local": totag[ 1 ], "remote": fromtag[ 1 ] } }
|
|
2099
|
+
b_1 = await callstore.getbycallid( searchfor )
|
|
2100
|
+
} catch( e ) {
|
|
2101
|
+
console.trace( e )
|
|
2102
|
+
res.send( 400, e )
|
|
2103
|
+
return
|
|
2104
|
+
}
|
|
2045
2105
|
|
|
2046
|
-
|
|
2047
|
-
.catch( ( e ) => {
|
|
2048
|
-
console.trace( e )
|
|
2049
|
-
res.send( 400, e )
|
|
2050
|
-
failed = true
|
|
2051
|
-
} )
|
|
2052
|
-
if( failed || !b_1 ) return res.send( 400, "No call matches that call id" )
|
|
2106
|
+
if( !b_1 ) return res.send( 400, "No call matches that call id" )
|
|
2053
2107
|
if( !b_1.sdp.remote ) return res.send( 400, "No remote sdp negotiated (b_1)!" )
|
|
2054
2108
|
const b_2 = this /* so we can follow the above terminology */
|
|
2055
2109
|
|
|
@@ -2073,37 +2127,14 @@ class call {
|
|
|
2073
2127
|
b_2.channels.audio.unmix()
|
|
2074
2128
|
c_1.channels.audio.unmix()
|
|
2075
2129
|
|
|
2076
|
-
|
|
2130
|
+
await Promise.all( [
|
|
2131
|
+
a_1.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
|
|
2132
|
+
b_1.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
|
|
2133
|
+
b_2.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
|
|
2134
|
+
c_1.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
|
|
2135
|
+
] )
|
|
2077
2136
|
|
|
2078
|
-
|
|
2079
|
-
const a_1_audio = a_1.channels.audio
|
|
2080
|
-
const a_1_sdp = a_1.sdp.local
|
|
2081
|
-
const a_1_chem = a_1.channels.audio.em
|
|
2082
|
-
const b_2_chem = b_2.channels.audio.em
|
|
2083
|
-
|
|
2084
|
-
a_1.channels.audio = b_2.channels.audio
|
|
2085
|
-
a_1.channels.audio.em = a_1_chem
|
|
2086
|
-
a_1.sdp.local = b_2.sdp.local
|
|
2087
|
-
|
|
2088
|
-
a_1.sdp.local
|
|
2089
|
-
.clearcodecs()
|
|
2090
|
-
.addcodecs( a_1.selectedcodec )
|
|
2091
|
-
.select( a_1.selectedcodec )
|
|
2092
|
-
.setaudiodirection( "sendrecv" )
|
|
2093
|
-
|
|
2094
|
-
if( true === callmanager.options.rfc2833 ) {
|
|
2095
|
-
a_1.sdp.local.addcodecs( "2833" )
|
|
2096
|
-
}
|
|
2097
|
-
|
|
2098
|
-
/* Link logically */
|
|
2099
|
-
a_1.adopt( c_1 )
|
|
2100
|
-
|
|
2101
|
-
/* this one will be hung up soon anyway - so it to has to close the correct one */
|
|
2102
|
-
b_2.channels.audio = a_1_audio
|
|
2103
|
-
b_2.channels.audio.em = b_2_chem
|
|
2104
|
-
b_2.sdp.local = a_1_sdp
|
|
2105
|
-
|
|
2106
|
-
failed = false
|
|
2137
|
+
a_1.swapchannel( b_2 )
|
|
2107
2138
|
|
|
2108
2139
|
await new Promise( ( resolve ) => {
|
|
2109
2140
|
res.send( 202, "Refering", {}, ( /* err, response */ ) => {
|
|
@@ -2112,32 +2143,20 @@ class call {
|
|
|
2112
2143
|
} )
|
|
2113
2144
|
|
|
2114
2145
|
const id = this._req.get( "cseq" ).match( /(\d+)/ )[ 0 ]
|
|
2115
|
-
|
|
2116
|
-
.
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
if( failed ) return
|
|
2146
|
+
try {
|
|
2147
|
+
await this._notifyreferstart( id )
|
|
2148
|
+
} catch( e ) {
|
|
2149
|
+
console.trace( e )
|
|
2150
|
+
this._notifyreferfail( id )
|
|
2151
|
+
return
|
|
2152
|
+
}
|
|
2123
2153
|
|
|
2124
2154
|
/* modify ports and renegotiate codecs */
|
|
2125
|
-
await a_1.
|
|
2126
|
-
|
|
2127
|
-
const target = a_1.sdp.remote.getaudio()
|
|
2128
|
-
if( target ) {
|
|
2129
|
-
/* we should always get in here */
|
|
2130
|
-
a_1.channels.audio.remote( call._createchannelremotedef( target.address, target.port, a_1.selectedcodec ).remote )
|
|
2155
|
+
await a_1.reinvite()
|
|
2131
2156
|
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
/* Now inform our RTP server also - we might need to wait untl the target has completed so need a notify mechanism */
|
|
2136
|
-
a_1.channels.audio.direction( { "send": false, "recv": false } )
|
|
2137
|
-
|
|
2138
|
-
a_1._em.emit( "call.mix", a_1 )
|
|
2139
|
-
callmanager.options.em.emit( "call.mix", a_1 )
|
|
2140
|
-
}
|
|
2157
|
+
/* there might be situations where mix is not the correct thing - perhaps a pop push application? */
|
|
2158
|
+
/* Link logically and mix */
|
|
2159
|
+
a_1.adopt( c_1, true )
|
|
2141
2160
|
|
|
2142
2161
|
this._notifyrefercomplete( id )
|
|
2143
2162
|
|
|
@@ -2311,15 +2330,17 @@ class call {
|
|
|
2311
2330
|
} )
|
|
2312
2331
|
}
|
|
2313
2332
|
} catch( e ) { console.trace( e ) }
|
|
2314
|
-
} else {
|
|
2315
|
-
|
|
2316
|
-
this._res.send( this.hangup_cause.sip )
|
|
2317
|
-
} catch( e ) { console.trace( e ) }
|
|
2333
|
+
} else if( this._res ) {
|
|
2334
|
+
this._res.send( this.hangup_cause.sip )
|
|
2318
2335
|
}
|
|
2319
2336
|
|
|
2320
2337
|
await this._onhangup( "us", reason )
|
|
2321
2338
|
}
|
|
2322
2339
|
|
|
2340
|
+
/**
|
|
2341
|
+
*
|
|
2342
|
+
* @returns { Promise }
|
|
2343
|
+
*/
|
|
2323
2344
|
async waitforhangup() {
|
|
2324
2345
|
|
|
2325
2346
|
if( !this._promises.promise.hangup ) {
|
|
@@ -2465,17 +2486,20 @@ class call {
|
|
|
2465
2486
|
* @returns { Promise< boolean | object > }
|
|
2466
2487
|
*/
|
|
2467
2488
|
static async #callcontactfornewuac( options, callbacks ) {
|
|
2468
|
-
|
|
2489
|
+
|
|
2490
|
+
if( !( await call.#checkmaxcallsforentity( options ) ) ) return false
|
|
2491
|
+
|
|
2469
2492
|
/* If we have an entity - we need to look them up */
|
|
2470
2493
|
if( !callmanager.options.registrar ) return false
|
|
2471
2494
|
if( !options.entity ) return false
|
|
2472
2495
|
|
|
2473
2496
|
const contactinfo = await callmanager.options.registrar.contacts( options.entity )
|
|
2497
|
+
|
|
2474
2498
|
if( !contactinfo || 0 == contactinfo.contacts.length ) {
|
|
2475
2499
|
return false
|
|
2476
2500
|
}
|
|
2477
2501
|
|
|
2478
|
-
|
|
2502
|
+
let numcontacts = 0
|
|
2479
2503
|
const ourcallbacks = {}
|
|
2480
2504
|
let failcount = 0
|
|
2481
2505
|
|
|
@@ -2505,16 +2529,15 @@ class call {
|
|
|
2505
2529
|
waitonchildrenresolve( c )
|
|
2506
2530
|
waitonchildrenresolve = false
|
|
2507
2531
|
if( callbacks.confirm ) callbacks.confirm( c )
|
|
2508
|
-
return
|
|
2509
2532
|
}
|
|
2510
|
-
c.hangup( hangupcodes.LOSE_RACE )
|
|
2511
|
-
if( callbacks.fail ) callbacks.fail( c )
|
|
2512
2533
|
}
|
|
2513
2534
|
|
|
2514
2535
|
for( const contact of contactinfo.contacts ) {
|
|
2515
2536
|
if( undefined === contact ) continue
|
|
2516
2537
|
const newoptions = { ...options }
|
|
2538
|
+
|
|
2517
2539
|
if( contact.contact && "string" == typeof contact.contact ) {
|
|
2540
|
+
numcontacts++
|
|
2518
2541
|
newoptions.contact = contact.contact
|
|
2519
2542
|
call.newuac( newoptions, ourcallbacks )
|
|
2520
2543
|
}
|
|
@@ -2591,16 +2614,12 @@ class call {
|
|
|
2591
2614
|
* @returns
|
|
2592
2615
|
*/
|
|
2593
2616
|
async #onnewuacsuccess( callbacks ) {
|
|
2594
|
-
clearTimeout( this._timers.newuac )
|
|
2595
|
-
this._timers.newuac = false
|
|
2596
2617
|
|
|
2597
2618
|
if( this.destroyedcancelledorhungup ) {
|
|
2598
|
-
if( callbacks && callbacks.fail ) callbacks.fail( this )
|
|
2599
2619
|
return this
|
|
2600
2620
|
}
|
|
2601
2621
|
|
|
2602
2622
|
this.sdp.remote = sdpgen.create( this._dialog.remote.sdp )
|
|
2603
|
-
this.established = true
|
|
2604
2623
|
|
|
2605
2624
|
if( this.parent ) {
|
|
2606
2625
|
for( const child of this.parent.children ) {
|
|
@@ -2695,6 +2714,14 @@ class call {
|
|
|
2695
2714
|
}
|
|
2696
2715
|
}
|
|
2697
2716
|
|
|
2717
|
+
#confignetwork( options, ) {
|
|
2718
|
+
const addressparts = parseuri( options.contact )
|
|
2719
|
+
if( addressparts ) {
|
|
2720
|
+
this.network.remote.address = addressparts.host
|
|
2721
|
+
if( addressparts.port ) this.network.remote.port = addressparts.port
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2698
2725
|
/**
|
|
2699
2726
|
@summary Creates a new SIP dialog(s). Returns a promise which resolves
|
|
2700
2727
|
when the dialog is either answered (or cancelled for some reason).
|
|
@@ -2761,12 +2788,7 @@ class call {
|
|
|
2761
2788
|
newcall.options = { ...callmanager.options, ...newcall.options, ...options }
|
|
2762
2789
|
newcall.options.headers = tmpheaders
|
|
2763
2790
|
|
|
2764
|
-
|
|
2765
|
-
if( addressparts ) {
|
|
2766
|
-
newcall.network.remote.address = addressparts.host
|
|
2767
|
-
if( addressparts.port ) newcall.network.remote.port = addressparts.port
|
|
2768
|
-
}
|
|
2769
|
-
|
|
2791
|
+
newcall.#confignetwork( options )
|
|
2770
2792
|
await newcall.#openchannelsfornewuac()
|
|
2771
2793
|
|
|
2772
2794
|
let newdialog
|
|
@@ -2776,13 +2798,18 @@ class call {
|
|
|
2776
2798
|
|
|
2777
2799
|
if( !req ) {
|
|
2778
2800
|
newcall.state.destroyed = true
|
|
2801
|
+
newcall.hangup( hangupcodes.SERVER_ERROR )
|
|
2779
2802
|
console.trace( "No req object??", err )
|
|
2780
2803
|
return
|
|
2781
2804
|
}
|
|
2782
2805
|
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2806
|
+
/* set new uac timeout */
|
|
2807
|
+
newcall.uactimeout = newcall.options.uactimeout
|
|
2808
|
+
|
|
2809
|
+
/* extend our parent ring timeout if necasary */
|
|
2810
|
+
if( options.parent ) {
|
|
2811
|
+
options.parent.uactimeout = Math.max( callmanager.options.uactimeout, newcall.options.uactimeout )
|
|
2812
|
+
}
|
|
2786
2813
|
|
|
2787
2814
|
newcall._req = req
|
|
2788
2815
|
newcall.state.trying = true
|
|
@@ -2815,19 +2842,31 @@ class call {
|
|
|
2815
2842
|
} )
|
|
2816
2843
|
} catch ( err ) {
|
|
2817
2844
|
newcall.#onnewuaccatch( err )
|
|
2818
|
-
} finally {
|
|
2819
|
-
newcall.#setdialog( newdialog )
|
|
2820
|
-
await newcall.#onnewuacsuccess( callbacks )
|
|
2821
2845
|
}
|
|
2846
|
+
|
|
2847
|
+
if( !newdialog ) {
|
|
2848
|
+
if( callbacks.fail ) callbacks.fail( newcall )
|
|
2849
|
+
return newcall
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
newcall.#setdialog( newdialog )
|
|
2853
|
+
await newcall.#onnewuacsuccess( callbacks )
|
|
2854
|
+
|
|
2822
2855
|
return newcall
|
|
2823
2856
|
}
|
|
2824
2857
|
|
|
2825
2858
|
/**
|
|
2826
|
-
*
|
|
2859
|
+
* assign our dialog and related items
|
|
2827
2860
|
* @param { object } d
|
|
2828
2861
|
*/
|
|
2829
2862
|
#setdialog( d ) {
|
|
2863
|
+
clearTimeout( this._timers.newuac )
|
|
2864
|
+
this._timers.newuac = false
|
|
2865
|
+
|
|
2866
|
+
if( this.destroyedcancelledorhungup ) return
|
|
2867
|
+
|
|
2830
2868
|
this._dialog = d
|
|
2869
|
+
this.established = true
|
|
2831
2870
|
}
|
|
2832
2871
|
|
|
2833
2872
|
/**
|
|
@@ -2878,6 +2917,9 @@ class call {
|
|
|
2878
2917
|
c.sdp.remote = sdpgen.create( c._req.msg.body )
|
|
2879
2918
|
}
|
|
2880
2919
|
|
|
2920
|
+
/* set a timer using the default */
|
|
2921
|
+
c.uactimeout = callmanager.options.uactimeout
|
|
2922
|
+
|
|
2881
2923
|
return c
|
|
2882
2924
|
|
|
2883
2925
|
}
|
|
@@ -2886,6 +2928,20 @@ class call {
|
|
|
2886
2928
|
static setcallmanager( cm ) {
|
|
2887
2929
|
callmanager = cm
|
|
2888
2930
|
}
|
|
2931
|
+
|
|
2932
|
+
/**
|
|
2933
|
+
* @param { number } ms - timeout for new call
|
|
2934
|
+
*/
|
|
2935
|
+
set uactimeout( ms ) {
|
|
2936
|
+
if( this.established ) return
|
|
2937
|
+
const msi = parseInt( ms )
|
|
2938
|
+
if( isNaN( msi ) ) return
|
|
2939
|
+
|
|
2940
|
+
clearTimeout( this._timers.newuac )
|
|
2941
|
+
this._timers.newuac = setTimeout( () => {
|
|
2942
|
+
this.hangup( hangupcodes.REQUEST_TIMEOUT )
|
|
2943
|
+
}, msi )
|
|
2944
|
+
}
|
|
2889
2945
|
}
|
|
2890
2946
|
|
|
2891
2947
|
module.exports = call
|
package/lib/callmanager.js
CHANGED
package/lib/store.js
CHANGED
|
@@ -103,10 +103,17 @@ function fixentity( c ) {
|
|
|
103
103
|
* @param {string} c.sip.tags.remote - the remote tag
|
|
104
104
|
* @param {object} c.entity - entity object
|
|
105
105
|
* @param {object} c.entity.uri
|
|
106
|
+
* @param {object} c._entity
|
|
107
|
+
* @param {object} [ c._state ]
|
|
108
|
+
* @param {boolean} [ c._state._hangup ]
|
|
106
109
|
* @return {Promise} - which resolves on completion (for future in case we support redis or similar)
|
|
107
110
|
*/
|
|
108
111
|
module.exports.set = async ( c ) => {
|
|
109
112
|
if( !iscallobjectgood( c ) ) return false
|
|
113
|
+
if( c._state && c._state._hangup ) {
|
|
114
|
+
module.exports.delete( c )
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
110
117
|
|
|
111
118
|
storebyuuid.set( c.uuid, c )
|
|
112
119
|
addtocallidset( c )
|
package/package.json
CHANGED
package/test/interface/call.js
CHANGED
|
@@ -298,23 +298,28 @@ describe( "call object", function() {
|
|
|
298
298
|
} )
|
|
299
299
|
|
|
300
300
|
const child = await inboundcall.newuac( { "entity": { "uri": "1000@dummy", "max": 1 } } )
|
|
301
|
-
const child2 = await call.newuac( { "entity": { "uri": "1000@dummy", "max": 1 } } )
|
|
302
301
|
|
|
302
|
+
const child2 = await call.newuac( { "entity": { "uri": "1000@dummy", "max": 1 } } )
|
|
303
303
|
expect( await callstore.stats() ).to.deep.include( {
|
|
304
304
|
"storebycallid": 2,
|
|
305
305
|
"storebyuuid": 2,
|
|
306
306
|
"storebyentity": 1
|
|
307
307
|
} )
|
|
308
308
|
|
|
309
|
-
const
|
|
309
|
+
const child3newcalls = []
|
|
310
|
+
await call.newuac( { "entity": { "uri": "1000@dummy" } }, { early:( c ) => child3newcalls.push( c ) } )
|
|
310
311
|
|
|
311
312
|
expect( await callstore.stats() ).to.deep.include( {
|
|
312
|
-
"storebycallid":
|
|
313
|
-
"storebyuuid":
|
|
313
|
+
"storebycallid": 4,
|
|
314
|
+
"storebyuuid": 4,
|
|
314
315
|
"storebyentity": 1
|
|
315
316
|
} )
|
|
316
317
|
|
|
317
|
-
await
|
|
318
|
+
await Promise.all( [
|
|
319
|
+
child3newcalls[ 0 ].hangup(),
|
|
320
|
+
child3newcalls[ 1 ].hangup()
|
|
321
|
+
] )
|
|
322
|
+
|
|
318
323
|
await inboundcall.hangup()
|
|
319
324
|
|
|
320
325
|
expect( await callstore.stats() ).to.deep.include( {
|
|
@@ -327,7 +332,8 @@ describe( "call object", function() {
|
|
|
327
332
|
expect( child2 ).to.be.false
|
|
328
333
|
|
|
329
334
|
expect( child.state.cleaned ).to.be.true
|
|
330
|
-
expect(
|
|
335
|
+
expect( child3newcalls[ 0 ].state.cleaned ).to.be.true
|
|
336
|
+
expect( child3newcalls[ 1 ].state.cleaned ).to.be.true
|
|
331
337
|
|
|
332
338
|
} )
|
|
333
339
|
|
|
@@ -524,13 +530,14 @@ describe( "call object", function() {
|
|
|
524
530
|
eventhappened = true
|
|
525
531
|
} )
|
|
526
532
|
|
|
527
|
-
await new Promise( ( resolve ) => {
|
|
533
|
+
const inbound = await new Promise( ( resolve ) => {
|
|
528
534
|
srfscenario.oncall( async ( call ) => { resolve( call ) } )
|
|
529
535
|
srfscenario.inbound()
|
|
530
536
|
} )
|
|
531
537
|
|
|
532
538
|
expect( eventhappened ).to.be.true
|
|
533
539
|
|
|
540
|
+
await inbound.hangup()
|
|
534
541
|
} )
|
|
535
542
|
|
|
536
543
|
it( "uas.newuac - ringing event", async function() {
|
|
@@ -555,6 +562,8 @@ describe( "call object", function() {
|
|
|
555
562
|
|
|
556
563
|
expect( eventhappened ).to.be.true
|
|
557
564
|
|
|
565
|
+
await c.hangup()
|
|
566
|
+
|
|
558
567
|
} )
|
|
559
568
|
|
|
560
569
|
it( "uas.newuac - destroyed event", async function() {
|
|
@@ -39,10 +39,12 @@ describe( "callmanager", function() {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
const c = await callmanager.callmanager( options )
|
|
42
|
+
let ourcall
|
|
43
|
+
c.once( "call.new", ( c ) => ourcall = c )
|
|
42
44
|
|
|
43
45
|
expect( usecalled ).to.be.true
|
|
44
46
|
|
|
45
|
-
const res = {}
|
|
47
|
+
const res = { send: () => {} }
|
|
46
48
|
const next = () => {}
|
|
47
49
|
/* present our pretend call */
|
|
48
50
|
await invitecb( req, res, next )
|
|
@@ -53,6 +55,8 @@ describe( "callmanager", function() {
|
|
|
53
55
|
"storebyuuid": 1,
|
|
54
56
|
"storebyentity": 0
|
|
55
57
|
} )
|
|
58
|
+
|
|
59
|
+
await ourcall.hangup()
|
|
56
60
|
} )
|
|
57
61
|
|
|
58
62
|
it( "create new callmanager object test for listening rtp server", async function() {
|
package/test/mock/srf.js
CHANGED
package/test/unit/call.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
|
|
1
2
|
const expect = require( "chai" ).expect
|
|
2
|
-
const callstore = require( "../../lib/call.js" )
|
|
3
3
|
const srf = require( "../mock/srf.js" )
|
|
4
4
|
|
|
5
5
|
describe( "call.js", function() {
|
|
6
6
|
|
|
7
|
-
it(
|
|
8
|
-
|
|
7
|
+
it( "set remote name and id", async function() {
|
|
8
|
+
const srfscenario = new srf.srfscenario()
|
|
9
9
|
|
|
10
10
|
let newcallcalled = false
|
|
11
11
|
srfscenario.options.em.on( "call.new", ( /*newcall*/ ) => {
|
|
12
12
|
newcallcalled = true
|
|
13
13
|
} )
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const call = await new Promise( ( resolve ) => {
|
|
16
16
|
srfscenario.oncall( async ( call ) => { resolve( call ) } )
|
|
17
17
|
srfscenario.inbound()
|
|
18
18
|
} )
|
|
@@ -24,6 +24,9 @@ describe( "call.js", function() {
|
|
|
24
24
|
// the names mismatch and can be confusing, we might consider some polishing here?
|
|
25
25
|
expect(call.remote.name).equals("foo")
|
|
26
26
|
expect(call.remote.user).equals("123456789")
|
|
27
|
+
expect( newcallcalled ).to.be.true
|
|
28
|
+
|
|
29
|
+
await call.hangup()
|
|
27
30
|
} )
|
|
28
31
|
|
|
29
32
|
} )
|