@babblevoice/babble-drachtio-callmanager 2.2.2 → 2.2.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/lib/call.js CHANGED
@@ -1105,7 +1105,7 @@ class call {
1105
1105
  .rtcpmux()
1106
1106
  }
1107
1107
 
1108
- this._dialog = await this._dialog.ack( this.sdp.local.toString() )
1108
+ this.#setdialog( await this._dialog.ack( this.sdp.local.toString() ) )
1109
1109
  this._addevents( this._dialog )
1110
1110
 
1111
1111
  await this.#answerparent()
@@ -1478,8 +1478,7 @@ class call {
1478
1478
  }
1479
1479
  } )
1480
1480
 
1481
- this.established = true
1482
- this._dialog = dialog
1481
+ this.#setdialog( dialog )
1483
1482
  this.sip.tags.local = dialog.sip.localTag
1484
1483
  callstore.set( this )
1485
1484
 
@@ -1759,16 +1758,52 @@ class call {
1759
1758
  } )
1760
1759
  }
1761
1760
 
1761
+ swapchannel( other ){
1762
+
1763
+ const this_audio = this.channels.audio
1764
+ const this_sdp = this.sdp.local
1765
+ const this_chem = this.channels.audio.em
1766
+ const other_chem = other.channels.audio.em
1767
+
1768
+ this.channels.audio = other.channels.audio
1769
+ this.channels.audio.em = this_chem
1770
+ this.sdp.local = other.sdp.local
1771
+
1772
+ other.channels.audio = this_audio
1773
+ other.channels.audio.em = other_chem
1774
+ other.sdp.local = this_sdp
1775
+ }
1776
+
1762
1777
  /**
1763
1778
  Send out modified SDP to get the audio to the new location.
1764
1779
  @private
1765
1780
  */
1766
- async _modifyforxfer() {
1767
- this.sdp.local.setaudiodirection( "sendrecv" )
1768
- await this._dialog.modify( this.sdp.local.toString() )
1781
+ async reinvite() {
1782
+
1783
+ this.sdp.local
1784
+ .clearcodecs()
1785
+ .addcodecs( this.selectedcodec )
1786
+ .select( this.selectedcodec )
1787
+ .setaudiodirection( "sendrecv" )
1788
+
1789
+ if( true === callmanager.options.rfc2833 ) {
1790
+ this.sdp.local.addcodecs( "2833" )
1791
+ }
1792
+
1793
+ const remotesdp = await this._dialog.modify( this.sdp.local.toString() )
1769
1794
  .catch( ( e ) => {
1770
1795
  console.trace( e )
1771
1796
  } )
1797
+
1798
+ if( remotesdp )
1799
+ this.sdp.remote = sdpgen.create( remotesdp )
1800
+
1801
+ const target = this.sdp.remote.getaudio()
1802
+ if( target ) /* we should always get in here */
1803
+ this.channels.audio.remote( call._createchannelremotedef( target.address, target.port, this.selectedcodec ).remote )
1804
+
1805
+ /* Now inform our RTP server also - we might need to wait until the target has completed so need a notify mechanism */
1806
+ this.channels.audio.direction( { "send": true, "recv": true } )
1772
1807
  }
1773
1808
 
1774
1809
  /**
@@ -1842,6 +1877,7 @@ class call {
1842
1877
  }, callmanager.options.seexpire )
1843
1878
 
1844
1879
  dialog.on( "destroy", ( /* req */ ) => {
1880
+ if( this._state._hangup ) return
1845
1881
  this._onhangup( "wire" )
1846
1882
  } )
1847
1883
 
@@ -1921,7 +1957,13 @@ class call {
1921
1957
 
1922
1958
  /* Auth the request - todo make a way of allow un authed refer - but we should nudge to secure */
1923
1959
  if( this.referauthrequired ) {
1924
- await this.auth()
1960
+ if( this._auth.has( this._req ) ) {
1961
+ /* If the client has included an auth header check it immediatly */
1962
+ if( ! await this._onauth( this._req, this._res ) ) return
1963
+ } else {
1964
+ await this.auth()
1965
+ }
1966
+
1925
1967
  if( this.destroyed ) return
1926
1968
  }
1927
1969
 
@@ -1973,6 +2015,12 @@ class call {
1973
2015
  this.detach()
1974
2016
  if( this.channels.audio ) this.channels.audio.unmix()
1975
2017
  if( othercall.channels.audio ) othercall.channels.audio.unmix()
2018
+
2019
+ await Promise.all( [
2020
+ this.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
2021
+ othercall.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
2022
+ ] )
2023
+
1976
2024
  if( othercall.channels.audio && this.moh ) othercall.channels.audio.play( this.moh )
1977
2025
 
1978
2026
  res.send( 202 )
@@ -2040,16 +2088,17 @@ class call {
2040
2088
  return
2041
2089
  }
2042
2090
 
2043
- const searchfor = { "callid": replaces[ 1 ], "tags": { "local": totag[ 1 ], "remote": fromtag[ 1 ] } }
2044
- let failed = false
2091
+ let b_1
2092
+ try {
2093
+ const searchfor = { "callid": replaces[ 1 ], "tags": { "local": totag[ 1 ], "remote": fromtag[ 1 ] } }
2094
+ b_1 = await callstore.getbycallid( searchfor )
2095
+ } catch( e ) {
2096
+ console.trace( e )
2097
+ res.send( 400, e )
2098
+ return
2099
+ }
2045
2100
 
2046
- const b_1 = await callstore.getbycallid( searchfor )
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" )
2101
+ if( !b_1 ) return res.send( 400, "No call matches that call id" )
2053
2102
  if( !b_1.sdp.remote ) return res.send( 400, "No remote sdp negotiated (b_1)!" )
2054
2103
  const b_2 = this /* so we can follow the above terminology */
2055
2104
 
@@ -2073,37 +2122,14 @@ class call {
2073
2122
  b_2.channels.audio.unmix()
2074
2123
  c_1.channels.audio.unmix()
2075
2124
 
2076
- /* Swap channels and update */
2077
-
2078
- /* copy all first */
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
2125
+ await Promise.all( [
2126
+ a_1.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
2127
+ b_1.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
2128
+ b_2.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
2129
+ c_1.waitforanyevent( { "action": "mix", "event": "finished" }, 0.5 ),
2130
+ ] )
2083
2131
 
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
2132
+ a_1.swapchannel( b_2 )
2107
2133
 
2108
2134
  await new Promise( ( resolve ) => {
2109
2135
  res.send( 202, "Refering", {}, ( /* err, response */ ) => {
@@ -2112,32 +2138,20 @@ class call {
2112
2138
  } )
2113
2139
 
2114
2140
  const id = this._req.get( "cseq" ).match( /(\d+)/ )[ 0 ]
2115
- await this._notifyreferstart( id )
2116
- .catch( ( e ) => {
2117
- console.trace( e )
2118
- this._notifyreferfail( id )
2119
- failed = true
2120
- } )
2121
-
2122
- if( failed ) return
2141
+ try {
2142
+ await this._notifyreferstart( id )
2143
+ } catch( e ) {
2144
+ console.trace( e )
2145
+ this._notifyreferfail( id )
2146
+ return
2147
+ }
2123
2148
 
2124
2149
  /* modify ports and renegotiate codecs */
2125
- await a_1._modifyforxfer()
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 )
2150
+ await a_1.reinvite()
2131
2151
 
2132
- /* there might be situations where mix is not the correct thing - perhaps a pop push application? */
2133
- a_1.channels.audio.mix( c_1.channels.audio )
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
- }
2152
+ /* there might be situations where mix is not the correct thing - perhaps a pop push application? */
2153
+ /* Link logically and mix */
2154
+ a_1.adopt( c_1, true )
2141
2155
 
2142
2156
  this._notifyrefercomplete( id )
2143
2157
 
@@ -2311,15 +2325,17 @@ class call {
2311
2325
  } )
2312
2326
  }
2313
2327
  } catch( e ) { console.trace( e ) }
2314
- } else {
2315
- try {
2316
- this._res.send( this.hangup_cause.sip )
2317
- } catch( e ) { console.trace( e ) }
2328
+ } else if( this._res ) {
2329
+ this._res.send( this.hangup_cause.sip )
2318
2330
  }
2319
2331
 
2320
2332
  await this._onhangup( "us", reason )
2321
2333
  }
2322
2334
 
2335
+ /**
2336
+ *
2337
+ * @returns { Promise }
2338
+ */
2323
2339
  async waitforhangup() {
2324
2340
 
2325
2341
  if( !this._promises.promise.hangup ) {
@@ -2465,17 +2481,20 @@ class call {
2465
2481
  * @returns { Promise< boolean | object > }
2466
2482
  */
2467
2483
  static async #callcontactfornewuac( options, callbacks ) {
2468
- if( !await call.#checkmaxcallsforentity( options ) ) return false
2484
+
2485
+ if( !( await call.#checkmaxcallsforentity( options ) ) ) return false
2486
+
2469
2487
  /* If we have an entity - we need to look them up */
2470
2488
  if( !callmanager.options.registrar ) return false
2471
2489
  if( !options.entity ) return false
2472
2490
 
2473
2491
  const contactinfo = await callmanager.options.registrar.contacts( options.entity )
2492
+
2474
2493
  if( !contactinfo || 0 == contactinfo.contacts.length ) {
2475
2494
  return false
2476
2495
  }
2477
2496
 
2478
- const numcontacts = contactinfo.contacts.length
2497
+ let numcontacts = 0
2479
2498
  const ourcallbacks = {}
2480
2499
  let failcount = 0
2481
2500
 
@@ -2505,16 +2524,15 @@ class call {
2505
2524
  waitonchildrenresolve( c )
2506
2525
  waitonchildrenresolve = false
2507
2526
  if( callbacks.confirm ) callbacks.confirm( c )
2508
- return
2509
2527
  }
2510
- c.hangup( hangupcodes.LOSE_RACE )
2511
- if( callbacks.fail ) callbacks.fail( c )
2512
2528
  }
2513
2529
 
2514
2530
  for( const contact of contactinfo.contacts ) {
2515
2531
  if( undefined === contact ) continue
2516
2532
  const newoptions = { ...options }
2533
+
2517
2534
  if( contact.contact && "string" == typeof contact.contact ) {
2535
+ numcontacts++
2518
2536
  newoptions.contact = contact.contact
2519
2537
  call.newuac( newoptions, ourcallbacks )
2520
2538
  }
@@ -2591,16 +2609,12 @@ class call {
2591
2609
  * @returns
2592
2610
  */
2593
2611
  async #onnewuacsuccess( callbacks ) {
2594
- clearTimeout( this._timers.newuac )
2595
- this._timers.newuac = false
2596
2612
 
2597
2613
  if( this.destroyedcancelledorhungup ) {
2598
- if( callbacks && callbacks.fail ) callbacks.fail( this )
2599
2614
  return this
2600
2615
  }
2601
2616
 
2602
2617
  this.sdp.remote = sdpgen.create( this._dialog.remote.sdp )
2603
- this.established = true
2604
2618
 
2605
2619
  if( this.parent ) {
2606
2620
  for( const child of this.parent.children ) {
@@ -2695,6 +2709,14 @@ class call {
2695
2709
  }
2696
2710
  }
2697
2711
 
2712
+ #confignetwork( options, ) {
2713
+ const addressparts = parseuri( options.contact )
2714
+ if( addressparts ) {
2715
+ this.network.remote.address = addressparts.host
2716
+ if( addressparts.port ) this.network.remote.port = addressparts.port
2717
+ }
2718
+ }
2719
+
2698
2720
  /**
2699
2721
  @summary Creates a new SIP dialog(s). Returns a promise which resolves
2700
2722
  when the dialog is either answered (or cancelled for some reason).
@@ -2761,12 +2783,7 @@ class call {
2761
2783
  newcall.options = { ...callmanager.options, ...newcall.options, ...options }
2762
2784
  newcall.options.headers = tmpheaders
2763
2785
 
2764
- const addressparts = parseuri( options.contact )
2765
- if( addressparts ) {
2766
- newcall.network.remote.address = addressparts.host
2767
- if( addressparts.port ) newcall.network.remote.port = addressparts.port
2768
- }
2769
-
2786
+ newcall.#confignetwork( options )
2770
2787
  await newcall.#openchannelsfornewuac()
2771
2788
 
2772
2789
  let newdialog
@@ -2776,13 +2793,18 @@ class call {
2776
2793
 
2777
2794
  if( !req ) {
2778
2795
  newcall.state.destroyed = true
2796
+ newcall.hangup( hangupcodes.SERVER_ERROR )
2779
2797
  console.trace( "No req object??", err )
2780
2798
  return
2781
2799
  }
2782
2800
 
2783
- newcall._timers.newuac = setTimeout( () => {
2784
- newcall.hangup( hangupcodes.REQUEST_TIMEOUT )
2785
- }, newcall.options.uactimeout )
2801
+ /* set new uac timeout */
2802
+ newcall.uactimeout = newcall.options.uactimeout
2803
+
2804
+ /* extend our parent ring timeout if necasary */
2805
+ if( options.parent ) {
2806
+ options.parent.uactimeout = Math.max( callmanager.options.uactimeout, newcall.options.uactimeout )
2807
+ }
2786
2808
 
2787
2809
  newcall._req = req
2788
2810
  newcall.state.trying = true
@@ -2815,19 +2837,31 @@ class call {
2815
2837
  } )
2816
2838
  } catch ( err ) {
2817
2839
  newcall.#onnewuaccatch( err )
2818
- } finally {
2819
- newcall.#setdialog( newdialog )
2820
- await newcall.#onnewuacsuccess( callbacks )
2821
2840
  }
2841
+
2842
+ if( !newdialog ) {
2843
+ if( callbacks.fail ) callbacks.fail( newcall )
2844
+ return newcall
2845
+ }
2846
+
2847
+ newcall.#setdialog( newdialog )
2848
+ await newcall.#onnewuacsuccess( callbacks )
2849
+
2822
2850
  return newcall
2823
2851
  }
2824
2852
 
2825
2853
  /**
2826
- * Helper to indicate not race condition
2854
+ * assign our dialog and related items
2827
2855
  * @param { object } d
2828
2856
  */
2829
2857
  #setdialog( d ) {
2858
+ clearTimeout( this._timers.newuac )
2859
+ this._timers.newuac = false
2860
+
2861
+ if( this.destroyedcancelledorhungup ) return
2862
+
2830
2863
  this._dialog = d
2864
+ this.established = true
2831
2865
  }
2832
2866
 
2833
2867
  /**
@@ -2862,13 +2896,15 @@ class call {
2862
2896
  @private
2863
2897
  */
2864
2898
  c._req = req
2865
- c._req.on( "cancel", () => c._oncanceled.bind( c ) )
2899
+
2866
2900
  /**
2867
2901
  @member
2868
2902
  @private
2869
2903
  */
2870
2904
  c._res = res
2871
2905
 
2906
+ c._req.on( "cancel", () => c._oncanceled.bind( c ) )
2907
+
2872
2908
  await callstore.set( c )
2873
2909
  callmanager.options.em.emit( "call.new", c )
2874
2910
 
@@ -2876,6 +2912,9 @@ class call {
2876
2912
  c.sdp.remote = sdpgen.create( c._req.msg.body )
2877
2913
  }
2878
2914
 
2915
+ /* set a timer using the default */
2916
+ c.uactimeout = callmanager.options.uactimeout
2917
+
2879
2918
  return c
2880
2919
 
2881
2920
  }
@@ -2884,6 +2923,20 @@ class call {
2884
2923
  static setcallmanager( cm ) {
2885
2924
  callmanager = cm
2886
2925
  }
2926
+
2927
+ /**
2928
+ * @param { number } ms - timeout for new call
2929
+ */
2930
+ set uactimeout( ms ) {
2931
+ if( this.established ) return
2932
+ const msi = parseInt( ms )
2933
+ if( isNaN( msi ) ) return
2934
+
2935
+ clearTimeout( this._timers.newuac )
2936
+ this._timers.newuac = setTimeout( () => {
2937
+ this.hangup( hangupcodes.REQUEST_TIMEOUT )
2938
+ }, msi )
2939
+ }
2887
2940
  }
2888
2941
 
2889
2942
  module.exports = call
@@ -80,6 +80,14 @@ class callmanager {
80
80
  this.options.em.on( event, cb )
81
81
  }
82
82
 
83
+ once( event, cb ) {
84
+ this.options.em.once( event, cb )
85
+ }
86
+
87
+ off( event, cb ) {
88
+ this.options.em.off( event, cb )
89
+ }
90
+
83
91
  /**
84
92
  Return dict of hangup-codes
85
93
  */
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babblevoice/babble-drachtio-callmanager",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "description": "Call processing to create a PBX",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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 child3 = await call.newuac( { "entity": { "uri": "1000@dummy" } } )
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": 3,
313
- "storebyuuid": 3,
313
+ "storebycallid": 4,
314
+ "storebyuuid": 4,
314
315
  "storebyentity": 1
315
316
  } )
316
317
 
317
- await child3.hangup()
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( child3.state.cleaned ).to.be.true
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
@@ -368,7 +368,7 @@ class dialog {
368
368
  }
369
369
 
370
370
  return new Promise( ( resolve ) => {
371
- resolve( this )
371
+ resolve( this.remote.sdp )
372
372
  } )
373
373
  }
374
374
  }
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( `set remote name and id`, async function() {
8
- let srfscenario = new srf.srfscenario()
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
- let call = await new Promise( ( resolve ) => {
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
  } )