@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 +25 -31
- package/package.json +1 -1
- package/test/interface/early.js +143 -2
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 =
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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(
|
|
2948
|
-
this.channels.audio = await this.#openchannel( channeldef,
|
|
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
|
|
2948
|
+
this.channels.audio = await this.#openchannel( channeldef, other )
|
|
2955
2949
|
return
|
|
2956
2950
|
}
|
|
2957
2951
|
}
|
package/package.json
CHANGED
package/test/interface/early.js
CHANGED
|
@@ -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
|
/*
|