@babblevoice/babble-drachtio-callmanager 3.3.4 → 3.3.6

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
@@ -1150,17 +1150,7 @@ class call {
1150
1150
  /* maintain privacy */
1151
1151
  other.options.privacy = this.options.privacy
1152
1152
 
1153
- if( mix ) {
1154
- this.channels.audio.mix( other.channels.audio )
1155
-
1156
- this._em.emit( "call.mix", this )
1157
- callmanager.options.em.emit( "call.mix", this )
1158
- other._em.emit( "call.mix", other )
1159
- callmanager.options.em.emit( "call.mix", other )
1160
-
1161
- this.epochs.mix = Math.floor( +new Date() / 1000 )
1162
- other.epochs.mix = Math.floor( +new Date() / 1000 )
1163
- }
1153
+ if( mix ) this.mix( other )
1164
1154
  return this
1165
1155
  }
1166
1156
 
@@ -1721,7 +1711,7 @@ class call {
1721
1711
  this.channels.count--
1722
1712
 
1723
1713
  if ( 0 === this.channels.count ) {
1724
- this.channels.audio = false
1714
+ this.channels.audio = undefined
1725
1715
 
1726
1716
  if( this._state._onhangup ) {
1727
1717
  this._cleanup()
@@ -2045,7 +2035,7 @@ class call {
2045
2035
 
2046
2036
  /**
2047
2037
  Mix two calls. If the two calls are on a different node
2048
- the second call is bonded and reinvited.
2038
+ the other call is bonded and reinvited.
2049
2039
  @param { call } othercall - our call object which is early
2050
2040
  @private
2051
2041
  */
@@ -2057,8 +2047,7 @@ class call {
2057
2047
  const channeldef = await othercall.#createchannelremotedef()
2058
2048
 
2059
2049
  const oldchannel = othercall.channels.audio
2060
- const newchannel = await this.#openchannel( channeldef, othercall )
2061
-
2050
+ const newchannel = await this.#openchannel( channeldef, this )
2062
2051
  await othercall.bond( this ).reinvite( channeldef, newchannel )
2063
2052
 
2064
2053
  await oldchannel.unmix()
@@ -2066,30 +2055,35 @@ class call {
2066
2055
  }
2067
2056
 
2068
2057
  await this.channels.audio.mix( othercall.channels.audio )
2058
+
2059
+ this._em.emit( "call.mix", this )
2060
+ callmanager.options.em.emit( "call.mix", this )
2061
+ othercall._em.emit( "call.mix", othercall )
2062
+ callmanager.options.em.emit( "call.mix", othercall )
2063
+
2064
+ this.epochs.mix = Math.floor( +new Date() / 1000 )
2065
+ othercall.epochs.mix = Math.floor( +new Date() / 1000 )
2069
2066
  }
2070
2067
 
2071
2068
  /**
2072
2069
  Mix two calls. If the two calls are on a different node
2073
2070
  the second call is bonded and reinvited.
2074
2071
  @param { object } channeldef - our call object which is early
2075
- @param { call } bindcall - the call which will own the channel
2072
+ @param { call } [ bindcall ] - the call which will own the channel
2076
2073
  */
2077
2074
  async #openchannel( channeldef, bindcall ) {
2078
2075
 
2079
- let chan = undefined
2080
-
2081
- if ( !bindcall || !this.channels.audio ) {
2082
- chan = await projectrtp.openchannel(
2076
+ if ( bindcall && bindcall.channels.audio ) {
2077
+ const chan = await bindcall.channels.audio.openchannel(
2083
2078
  channeldef, this._handlechannelevents.bind( this ) )
2084
- } else {
2085
- chan = await this.channels.audio.openchannel(
2086
- channeldef, bindcall._handlechannelevents.bind( bindcall ) )
2087
- }
2088
2079
 
2089
- if ( bindcall )
2090
- bindcall.channels.count++
2091
- else
2092
2080
  this.channels.count++
2081
+ return chan
2082
+ }
2083
+
2084
+ const chan = await projectrtp.openchannel(
2085
+ channeldef, this._handlechannelevents.bind( this ) )
2086
+ this.channels.count++
2093
2087
 
2094
2088
  return chan
2095
2089
  }
@@ -2939,19 +2933,19 @@ class call {
2939
2933
 
2940
2934
  if( this.channels.audio ) return
2941
2935
 
2942
- const relatedcall = this.other
2936
+ const othercall = this.other
2943
2937
  /* TODO: this is a hack. projectrtp has become too complicated with both a listen and connect
2944
2938
  mechanism. This is causing problems in code like this. There is no interface to
2945
2939
  detect which mode the channel is in - but the channels property will exist on a connect
2946
2940
  style channel. projectrtp will getrelatives a rewrite to support only one. */
2947
- if( relatedcall && relatedcall.channels.audio && relatedcall.channels.audio.channels ) {
2948
- this.channels.audio = await this.#openchannel( channeldef, this )
2941
+ if( othercall && othercall.channels.audio ) {
2942
+ this.channels.audio = await this.#openchannel( channeldef, othercall )
2949
2943
  return
2950
2944
  }
2951
2945
 
2952
2946
  for( const other of this.relatives ) {
2953
2947
  if( other.channels && other.channels.audio ) {
2954
- this.channels.audio = await other.#openchannel( channeldef, this )
2948
+ this.channels.audio = await this.#openchannel( channeldef, other )
2955
2949
  return
2956
2950
  }
2957
2951
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babblevoice/babble-drachtio-callmanager",
3
- "version": "3.3.4",
3
+ "version": "3.3.6",
4
4
  "description": "Call processing to create a PBX",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,8 +20,7 @@ describe( "call early", function() {
20
20
  clearcallmanager()
21
21
  } )
22
22
 
23
-
24
- it( "Create call and send 183 - early basic", async () => {
23
+ it( "Create call and send 183 - early basic prtp - listen mode", async () => {
25
24
 
26
25
  /*
27
26
  Phone BV Gateway
@@ -163,6 +162,148 @@ a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n")
163
162
  rtpserver.destroy()
164
163
  } )
165
164
 
165
+
166
+ it( "Create call and send 183 - early basic prtp connect mode", async () => {
167
+
168
+ /*
169
+ Phone BV Gateway
170
+ |---------INVITE------>| |(1)
171
+ | |---------INVITE------>|(2)
172
+ | |<--------183 (w-sdp)--|(3)
173
+ |<--------183 (w-sdp)--| |(4)
174
+
175
+ Phone RTP: 192.168.0.200:18540
176
+ BV RTP: 192.168.0.141
177
+ Gateway RTP: 192.168.0.160:21000
178
+ */
179
+
180
+ /* Setup the mock RTP server */
181
+ const srfscenario = new srf.srfscenario()
182
+ const rtpserver = callmanager.projectrtp.proxy.addnode( { host: "127.0.0.1", port: 9002 } )
183
+
184
+ let connection
185
+ const mockrtp = net.createServer()
186
+ mockrtp.on( "connection", ( c ) => {
187
+ connection = c
188
+
189
+ connection.on( "data", ( data ) => {
190
+ projectrtpmessage.parsemessage( messagestate, data, ( msg ) => {
191
+ try{
192
+ channelmessages.push( msg )
193
+ if( "open" === msg.channel ) {
194
+ if( 0 == opencount ) {
195
+ setTimeout( () =>
196
+ connection.write(
197
+ projectrtpmessage.createmessage(
198
+ {"local":{"port":10008,"dtls":
199
+ {"fingerprint":"Some fingerprint","enabled":false},
200
+ "address":"192.168.0.141"},
201
+ "id": msg.id,
202
+ "uuid": uuidv4(),
203
+ "action":"open",
204
+ "status":{"channel":{"available":4995,"current":5},"workercount":12,"instance":"ca0ef6a9-9174-444d-bdeb-4c9eb54d4566"}
205
+ } ) ), 2 )
206
+ } else {
207
+ setTimeout( () =>
208
+ connection.write(
209
+ projectrtpmessage.createmessage(
210
+ {"local":{"port": 10010,"dtls":
211
+ {"fingerprint":"Some fingerprint","enabled":false},
212
+ "address":"192.168.0.141"},
213
+ "id": msg.id,
214
+ "uuid": uuidv4(),
215
+ "action":"open",
216
+ "status":{"channel":{"available":4995,"current":5},"workercount":12,"instance":"ca0ef6a9-9174-444d-bdeb-4c9eb54d4566"}
217
+ } ) ), 2 )
218
+ }
219
+ opencount++
220
+ } else if ( "close" === msg.channel ) {
221
+ connection.write( projectrtpmessage.createmessage( {"id": msg.id,"uuid":msg.uuid,"action":"close","reason":"requested","stats":{"in":{"mos":4.5,"count":586,"dropped":0,"skip":0},"out":{"count":303,"skip":0},"tick":{"meanus":124,"maxus":508,"count":597}}, "status":{"channel":{"available":4995,"current":5},"workercount":12,"instance":"ca0ef6a9-9174-444d-bdeb-4c9eb54d4566"}
222
+ } ) )
223
+ } else if ( "mix" === msg.channel ) {
224
+ mixing = true
225
+ }
226
+ } catch( e ) {
227
+ console.error( e )
228
+ }
229
+ } )
230
+ } )
231
+ } )
232
+
233
+ await new Promise( resolve => mockrtp.listen( 9002, resolve ) )
234
+
235
+ let mixing
236
+ const messagestate = projectrtpmessage.newstate()
237
+ const channelmessages = []
238
+ let opencount = 0
239
+
240
+ /* ensure we are connected */
241
+ await new Promise( ( resolve ) => setTimeout( () => resolve(), 100 ) )
242
+
243
+ srfscenario.oncreateUAC( async ( contact, options, callbacks ) => {
244
+
245
+ /* Step 3. This is the mocked gateway message back to our newcall. */
246
+ callbacks.cbProvisional( {
247
+ "status": 183,
248
+ "get": () => { return "INVITE, UPDATE, OPTIONS" },
249
+ "msg": {
250
+ "body": `v=0
251
+ o=- 1608235282228 0 IN IP4 127.0.0.1
252
+ s=
253
+ c=IN IP4 192.168.0.160
254
+ t=0 0
255
+ m=audio 21000 RTP/AVP 0 101
256
+ a=rtpmap:101 telephone-event/8000
257
+ a=fmtp:101 0-16
258
+ a=sendrecv`.replace(/(\r\n|\n|\r)/gm, "\r\n")
259
+ }
260
+ } )
261
+
262
+ await new Promise( ( resolve ) => setTimeout( () => resolve(), 100 ) )
263
+ throw { "status": 503 }
264
+ } )
265
+
266
+ /* Step 1. Phone sends INVITE */
267
+ const call = await new Promise( ( resolve ) => {
268
+ srfscenario.oncall( async ( call ) => { resolve( call ) } )
269
+ srfscenario.inbound()
270
+ } )
271
+
272
+ /* Step 4. BV sends 183 back to phone */
273
+ let msgsent, msginfo
274
+ srfscenario.res.onsend( ( c, i ) => {
275
+ msgsent = c
276
+ msginfo = i
277
+ } )
278
+
279
+
280
+ /* Step 2. New INVITE to the remote Gateway */
281
+ const newcall = await call.newuac( { "contact": "callto" } )
282
+
283
+ await call._onhangup( "wire" )
284
+ expect( newcall.state.early ).to.be.true
285
+ expect( call.state.early ).to.be.true
286
+ expect( mixing ).to.be.true
287
+ expect( msgsent ).to.equal( 183 )
288
+
289
+ expect( channelmessages[ 0 ].channel ).to.equal( "open" )
290
+ expect( channelmessages[ 1 ].channel ).to.equal( "remote" )
291
+ expect( channelmessages[ 1 ].remote.port ).to.equal( 21000 )
292
+ expect( channelmessages[ 1 ].remote.address ).to.equal( "192.168.0.160" )
293
+ expect( channelmessages[ 2 ].channel ).to.equal( "open" )
294
+ expect( channelmessages[ 2 ].remote.port ).to.equal( 18540 )
295
+ expect( channelmessages[ 2 ].remote.address ).to.equal( "192.168.0.200" )
296
+ expect( channelmessages[ 3 ].channel ).to.equal( "mix" )
297
+ expect( channelmessages[ 4 ].channel ).to.equal( "close" )
298
+ expect( channelmessages[ 5 ].channel ).to.equal( "close" )
299
+
300
+ expect( msginfo.body ).to.include( "audio 10010 RTP/AVP" )
301
+
302
+ connection.destroy()
303
+ mockrtp.close()
304
+ rtpserver.destroy()
305
+ } )
306
+
166
307
  it( "Create call and send 183 - early - SAVPF", async () => {
167
308
 
168
309
  /*