@babblevoice/projectrtp 2.5.26 → 2.5.29
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/README.md +1 -1
- package/index.js +6 -7
- package/lib/message.js +1 -1
- package/lib/node.js +91 -23
- package/lib/server.js +138 -162
- package/package.json +1 -1
- package/src/projectrtpbuffer.cpp +17 -19
- package/src/projectrtpbuffer.h +1 -0
- package/src/projectrtpchannel.cpp +180 -51
- package/src/projectrtpchannel.h +4 -0
- package/src/projectrtpchannelmux.cpp +20 -2
- package/src/projectrtpchannelrecorder.cpp +1 -0
- package/src/projectrtpchannelrecorder.h +1 -0
- package/src/projectrtpcodecx.cpp +3 -2
- package/test/interface/projectrtpdtmf.js +5 -5
- package/test/interface/projectrtpmix.js +5 -5
- package/test/interface/projectrtprecord.js +4 -0
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ If you wish to build outsode of a Docker image, there are npm target scripts for
|
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
62
|
docker buildx prune
|
|
63
|
-
docker buildx build --platform linux/amd64,linux/arm64 -t tinpotnick/projectrtp:2.5.
|
|
63
|
+
docker buildx build --platform linux/amd64,linux/arm64 -t tinpotnick/projectrtp:2.5.29 . --push
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
## Example scripts
|
package/index.js
CHANGED
|
@@ -31,13 +31,13 @@ function gencerts() {
|
|
|
31
31
|
const combined = keypath + "dtls-srtp.pem"
|
|
32
32
|
|
|
33
33
|
const openssl = spawnSync( "openssl", [ "genrsa", "-out", serverkey, "4096" ] )
|
|
34
|
-
if( 0 !== openssl.status ) throw "Failed to genrsa: " + openssl.status
|
|
34
|
+
if( 0 !== openssl.status ) throw new Error( "Failed to genrsa: " + openssl.status )
|
|
35
35
|
|
|
36
36
|
const request = spawnSync( "openssl", [ "req", "-new", "-key", serverkey , "-out", servercsr, "-subj", "/C=GB/CN=projectrtp" ] )
|
|
37
|
-
if( 0 !== request.status ) throw "Failed to generate csr: " + request.status
|
|
37
|
+
if( 0 !== request.status ) throw new Error( "Failed to generate csr: " + request.status )
|
|
38
38
|
|
|
39
39
|
const sign = spawnSync( "openssl", [ "x509", "-req", "-in", servercsr, "-signkey", serverkey, "-out", servercert ] )
|
|
40
|
-
if( 0 !== sign.status ) throw "Failed to sign key: " + sign.status
|
|
40
|
+
if( 0 !== sign.status ) throw new Error( "Failed to sign key: " + sign.status )
|
|
41
41
|
|
|
42
42
|
const serverkeydata = fs.readFileSync( serverkey )
|
|
43
43
|
const servercertdata = fs.readFileSync( servercert )
|
|
@@ -407,9 +407,9 @@ class projectrtp {
|
|
|
407
407
|
run( params ) {
|
|
408
408
|
|
|
409
409
|
if( "win32" == process.platform && "x64" == process.arch ) {
|
|
410
|
-
throw "Platform not currently supported"
|
|
410
|
+
throw new Error( "Platform not currently supported" )
|
|
411
411
|
} else if( "win32" == process.platform && "ia32" == process.arch ) {
|
|
412
|
-
throw "Platform not currently supported"
|
|
412
|
+
throw new Error( "Platform not currently supported" )
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
if( actualprojectrtp ) return
|
|
@@ -445,7 +445,6 @@ class projectrtp {
|
|
|
445
445
|
if( !params.forcelocal && server.interface.get() ) {
|
|
446
446
|
return server.interface.get().openchannel( params, cb )
|
|
447
447
|
} else {
|
|
448
|
-
/* use local */
|
|
449
448
|
const chan = actualprojectrtp.openchannel( params, ( d ) => {
|
|
450
449
|
try{
|
|
451
450
|
if( chan.em ) {
|
|
@@ -471,7 +470,7 @@ class projectrtp {
|
|
|
471
470
|
|
|
472
471
|
/* ensure we are identicle to the node version of this object */
|
|
473
472
|
chan.openchannel = this.openchannel.bind( this )
|
|
474
|
-
|
|
473
|
+
|
|
475
474
|
return chan
|
|
476
475
|
}
|
|
477
476
|
}
|
package/lib/message.js
CHANGED
package/lib/node.js
CHANGED
|
@@ -64,7 +64,7 @@ class rtpnodeconnection {
|
|
|
64
64
|
this._processmessage( modifiedmsg )
|
|
65
65
|
} )
|
|
66
66
|
} catch( e ) {
|
|
67
|
-
console.error( "Unhandled exception in
|
|
67
|
+
console.error( "Unhandled exception in projectrtp", e )
|
|
68
68
|
}
|
|
69
69
|
} )
|
|
70
70
|
}
|
|
@@ -109,16 +109,48 @@ class rtpnodeconnection {
|
|
|
109
109
|
/**
|
|
110
110
|
* Send a message back to the main server, include stats to help with load balancing.
|
|
111
111
|
* @param { object } msg
|
|
112
|
-
* @
|
|
112
|
+
* @param { function } [ cb ]
|
|
113
|
+
* @returns { Promise | undefined }
|
|
113
114
|
*/
|
|
114
115
|
send( msg, cb = undefined ) {
|
|
116
|
+
|
|
117
|
+
let retval
|
|
118
|
+
if( !cb ) retval = new Promise( ( r ) => cb = r )
|
|
115
119
|
this.parent._post( msg, ( modifiedmsg ) => {
|
|
116
|
-
if( this._destroying )
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.
|
|
120
|
-
|
|
120
|
+
if( this._destroying ) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
modifiedmsg.status = this.parent.prtp.stats()
|
|
124
|
+
modifiedmsg.status.instance = instance
|
|
125
|
+
|
|
126
|
+
delete modifiedmsg.forcelocal
|
|
127
|
+
delete modifiedmsg.em
|
|
128
|
+
delete modifiedmsg.openchannel
|
|
129
|
+
delete modifiedmsg.close
|
|
130
|
+
delete modifiedmsg.mix
|
|
131
|
+
delete modifiedmsg.unmix
|
|
132
|
+
delete modifiedmsg.echo
|
|
133
|
+
delete modifiedmsg.play
|
|
134
|
+
delete modifiedmsg.record
|
|
135
|
+
delete modifiedmsg.direction
|
|
136
|
+
delete modifiedmsg.dtmf
|
|
137
|
+
delete modifiedmsg.remote
|
|
138
|
+
|
|
139
|
+
this.connection.write( message.createmessage( modifiedmsg ), () => {
|
|
140
|
+
cb( modifiedmsg )
|
|
141
|
+
} )
|
|
121
142
|
} )
|
|
143
|
+
|
|
144
|
+
return retval
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#cleanup() {
|
|
148
|
+
this.connectionlength -= 1
|
|
149
|
+
|
|
150
|
+
if( 0 == this.connectionlength && "listen" == this.mode ) {
|
|
151
|
+
this.parent.connections.delete( this.connectionid )
|
|
152
|
+
this.connection.destroy()
|
|
153
|
+
}
|
|
122
154
|
}
|
|
123
155
|
|
|
124
156
|
|
|
@@ -131,25 +163,61 @@ class rtpnodeconnection {
|
|
|
131
163
|
this.connectionlength += 1
|
|
132
164
|
msg.forcelocal = true
|
|
133
165
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
166
|
+
const timerid = setTimeout( () => {
|
|
167
|
+
console.trace( "Timeout opening channel", msg )
|
|
168
|
+
process.exit(1)
|
|
169
|
+
}, 4000 )
|
|
170
|
+
|
|
171
|
+
let chan
|
|
172
|
+
try {
|
|
173
|
+
chan = await this.parent.prtp.openchannel( msg, ( cookie ) => {
|
|
174
|
+
|
|
175
|
+
if( !chan ) {
|
|
176
|
+
console.error( "Error opening channel - message before open", msg, cookie )
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// TODO: we might want to ensure the actual event has been written
|
|
181
|
+
// to the server before cleaning up the channel on our side?
|
|
182
|
+
const tosend = { ...{ "id": chan.id, "uuid": chan.uuid }, ...cookie }
|
|
183
|
+
|
|
184
|
+
this.send( tosend,
|
|
185
|
+
() => {
|
|
186
|
+
if ( "close" === cookie.action ) {
|
|
187
|
+
if( !chan ) {
|
|
188
|
+
const closebforeopen = { error: "unknown error opening channel", cookie, msg }
|
|
189
|
+
this.send( closebforeopen, () => {
|
|
190
|
+
this.#cleanup()
|
|
191
|
+
} )
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
channels.delete( chan.uuid )
|
|
195
|
+
this.#cleanup()
|
|
146
196
|
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
} )
|
|
197
|
+
} )
|
|
198
|
+
} )
|
|
199
|
+
} catch( e ) {
|
|
200
|
+
console.error( "Error opening channel", e )
|
|
201
|
+
const opentosend = { error: "unknown error opening channel", msg }
|
|
202
|
+
await this.send( opentosend )
|
|
203
|
+
this.#cleanup()
|
|
204
|
+
return false
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if( !chan ) {
|
|
208
|
+
console.trace( "Error opening channel", msg )
|
|
209
|
+
const opentosend = { error: "unknown error opening channel", msg }
|
|
210
|
+
await this.send( opentosend )
|
|
211
|
+
this.#cleanup()
|
|
212
|
+
return false
|
|
213
|
+
}
|
|
214
|
+
|
|
150
215
|
channels.set( chan.uuid, chan )
|
|
151
|
-
this.send( { ...chan, ...{ "action": "open" } } )
|
|
152
216
|
|
|
217
|
+
clearTimeout( timerid )
|
|
218
|
+
|
|
219
|
+
const opentosend = { ...chan, ...{ "action": "open" } }
|
|
220
|
+
this.send( opentosend )
|
|
153
221
|
return true
|
|
154
222
|
}
|
|
155
223
|
|
package/lib/server.js
CHANGED
|
@@ -4,9 +4,10 @@ const net = require( "net" )
|
|
|
4
4
|
const { v4: uuidv4 } = require( "uuid" )
|
|
5
5
|
|
|
6
6
|
const EventEmitter = require( "events" )
|
|
7
|
-
|
|
8
7
|
const message = require( "./message" )
|
|
9
8
|
|
|
9
|
+
const opentimeout = 5000
|
|
10
|
+
|
|
10
11
|
/**
|
|
11
12
|
* Node host address and port object
|
|
12
13
|
* @typedef { object } nodehost
|
|
@@ -105,12 +106,36 @@ class channel {
|
|
|
105
106
|
*/
|
|
106
107
|
openresolve
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* @private
|
|
111
|
+
* @type { function }
|
|
112
|
+
*/
|
|
113
|
+
closeresolve
|
|
114
|
+
|
|
108
115
|
/**
|
|
109
116
|
* @private
|
|
110
117
|
* @type { function }
|
|
111
118
|
*/
|
|
112
119
|
openreject
|
|
113
120
|
|
|
121
|
+
/**
|
|
122
|
+
* @private
|
|
123
|
+
* @type { function }
|
|
124
|
+
*/
|
|
125
|
+
closereject
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @private
|
|
129
|
+
* @type { NodeJS.Timeout }
|
|
130
|
+
*/
|
|
131
|
+
opentimer
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @private
|
|
135
|
+
* @type { NodeJS.Timeout }
|
|
136
|
+
*/
|
|
137
|
+
closetimer
|
|
138
|
+
|
|
114
139
|
/**
|
|
115
140
|
* Array of messages sent to and from the remote end.
|
|
116
141
|
* @type { Array< any > }
|
|
@@ -152,6 +177,8 @@ class channel {
|
|
|
152
177
|
*/
|
|
153
178
|
_bridge
|
|
154
179
|
|
|
180
|
+
#connected = false
|
|
181
|
+
|
|
155
182
|
/**
|
|
156
183
|
*
|
|
157
184
|
*/
|
|
@@ -206,14 +233,15 @@ class channel {
|
|
|
206
233
|
}
|
|
207
234
|
|
|
208
235
|
/**
|
|
209
|
-
*
|
|
236
|
+
* Connects to a RTP server then creates channel
|
|
210
237
|
* @param { object } options
|
|
211
238
|
* @param { channelcallback } cb
|
|
212
239
|
* @param { function } openresolve
|
|
240
|
+
* @param { function } openreject
|
|
213
241
|
* @returns { Promise< channel > } - resolves when the connection is connected
|
|
214
242
|
* @internal
|
|
215
243
|
*/
|
|
216
|
-
static _createforconnect( options, cb, openresolve
|
|
244
|
+
static _createforconnect( options, cb, openresolve, openreject ) {
|
|
217
245
|
|
|
218
246
|
const newchannel = new channel( options.id )
|
|
219
247
|
if( cb ) newchannel.em.on( "all", cb )
|
|
@@ -228,14 +256,29 @@ class channel {
|
|
|
228
256
|
"type": nodeconnectiontype.connect
|
|
229
257
|
}
|
|
230
258
|
|
|
259
|
+
newchannel.openresolve = openresolve
|
|
260
|
+
newchannel.openreject = openreject
|
|
261
|
+
|
|
231
262
|
newchannel.connection.sock.setKeepAlive( true )
|
|
232
263
|
newchannel.channels = [ newchannel ]
|
|
233
264
|
|
|
234
265
|
newchannel.connection.sock.on( "connect", () => {
|
|
235
266
|
newchannel._write( options )
|
|
267
|
+
newchannel.#connected = true
|
|
236
268
|
if ( connectresolve ) connectresolve( newchannel )
|
|
237
269
|
} )
|
|
238
270
|
|
|
271
|
+
newchannel.opentimer = setTimeout( () => {
|
|
272
|
+
if( newchannel.openreject ) {
|
|
273
|
+
let addmesg = ""
|
|
274
|
+
if( newchannel.#connected ) addmesg = " - post connect"
|
|
275
|
+
newchannel.openreject( new Error( "timed out waiting for open" + addmesg ) )
|
|
276
|
+
delete newchannel.openresolve
|
|
277
|
+
delete newchannel.openreject
|
|
278
|
+
delete newchannel.opentimer
|
|
279
|
+
}
|
|
280
|
+
}, opentimeout )
|
|
281
|
+
|
|
239
282
|
const state = message.newstate()
|
|
240
283
|
newchannel.connection.sock.on( "data", ( data ) => {
|
|
241
284
|
message.parsemessage( state, data, ( /** @type { object } */ receivedmsg ) => {
|
|
@@ -248,8 +291,6 @@ class channel {
|
|
|
248
291
|
if( receivedmsg && receivedmsg.status && receivedmsg.status.instance ) {
|
|
249
292
|
newchannel.connection.instance = receivedmsg.status.instance
|
|
250
293
|
}
|
|
251
|
-
|
|
252
|
-
if ( openresolve ) openresolve( newchannel )
|
|
253
294
|
} )
|
|
254
295
|
} )
|
|
255
296
|
|
|
@@ -259,6 +300,16 @@ class channel {
|
|
|
259
300
|
} )
|
|
260
301
|
|
|
261
302
|
newchannel.connection.sock.on( "close", () => {
|
|
303
|
+
newchannel.channels.forEach( chnl => {
|
|
304
|
+
channels.delete( chnl.id )
|
|
305
|
+
if( chnl.openreject ) {
|
|
306
|
+
chnl.openreject( new Error( "Connection closed whilst waiting for open" ) )
|
|
307
|
+
clearTimeout( chnl.opentimer )
|
|
308
|
+
delete chnl.openresolve
|
|
309
|
+
delete chnl.openreject
|
|
310
|
+
delete chnl.opentimer
|
|
311
|
+
}
|
|
312
|
+
} )
|
|
262
313
|
} )
|
|
263
314
|
} )
|
|
264
315
|
}
|
|
@@ -279,11 +330,8 @@ class channel {
|
|
|
279
330
|
|
|
280
331
|
const resolvepromise = new Promise( ( resolve, reject ) => {
|
|
281
332
|
|
|
282
|
-
if
|
|
283
|
-
|
|
284
|
-
const request = JSON.parse( JSON.stringify( options ) )
|
|
285
|
-
request.channel = "open"
|
|
286
|
-
channel._createforlisten( request, node, cb, resolve, reject )
|
|
333
|
+
if( !this.connection ) {
|
|
334
|
+
reject( new Error( "No connection" ) )
|
|
287
335
|
return
|
|
288
336
|
}
|
|
289
337
|
|
|
@@ -294,7 +342,17 @@ class channel {
|
|
|
294
342
|
newchannel.channels = this.channels
|
|
295
343
|
newchannel.channels.push( newchannel )
|
|
296
344
|
newchannel.openresolve = resolve
|
|
345
|
+
newchannel.openreject = reject
|
|
297
346
|
newchannel._write( options )
|
|
347
|
+
|
|
348
|
+
newchannel.opentimer = setTimeout( () => {
|
|
349
|
+
if( newchannel.openreject ) {
|
|
350
|
+
newchannel.openreject( new Error( "timed out waiting for open" ) )
|
|
351
|
+
delete newchannel.openresolve
|
|
352
|
+
delete newchannel.openreject
|
|
353
|
+
delete newchannel.opentimer
|
|
354
|
+
}
|
|
355
|
+
}, opentimeout )
|
|
298
356
|
} )
|
|
299
357
|
|
|
300
358
|
return resolvepromise
|
|
@@ -314,12 +372,24 @@ class channel {
|
|
|
314
372
|
}
|
|
315
373
|
|
|
316
374
|
/**
|
|
317
|
-
*
|
|
375
|
+
* Closes the channel. It might throw a timeout error if the channel is not closed within 5 seconds.
|
|
376
|
+
* @param { object } [ options ]
|
|
377
|
+
* @param { number } [ options.timeout ] - different timeout to wait
|
|
378
|
+
* @returns { Promise< object > }
|
|
318
379
|
*/
|
|
319
|
-
close() {
|
|
380
|
+
close( options ) {
|
|
320
381
|
|
|
321
|
-
|
|
322
|
-
|
|
382
|
+
let timeout = opentimeout
|
|
383
|
+
if( options && options.timeout ) timeout = options.timeout
|
|
384
|
+
|
|
385
|
+
this.closetimer = setTimeout( () => {
|
|
386
|
+
if( this.closereject ) {
|
|
387
|
+
this.closereject( new Error( "timed out waiting for close" ) )
|
|
388
|
+
delete this.closereject
|
|
389
|
+
delete this.closeresolve
|
|
390
|
+
delete this.closetimer
|
|
391
|
+
}
|
|
392
|
+
}, timeout )
|
|
323
393
|
|
|
324
394
|
/* close us */
|
|
325
395
|
this._write( {
|
|
@@ -327,11 +397,18 @@ class channel {
|
|
|
327
397
|
"uuid": this.uuid
|
|
328
398
|
} )
|
|
329
399
|
|
|
330
|
-
if( this.
|
|
331
|
-
this.
|
|
400
|
+
if( this.openreject ) {
|
|
401
|
+
this.openreject( new Error( "Channel closed before open" ) )
|
|
402
|
+
clearTimeout( this.opentimer )
|
|
332
403
|
delete this.openresolve
|
|
333
404
|
delete this.openreject
|
|
405
|
+
delete this.opentimer
|
|
334
406
|
}
|
|
407
|
+
|
|
408
|
+
return new Promise( ( resolve, reject ) => {
|
|
409
|
+
this.closeresolve = resolve
|
|
410
|
+
this.closereject = reject
|
|
411
|
+
} )
|
|
335
412
|
}
|
|
336
413
|
|
|
337
414
|
/**
|
|
@@ -354,142 +431,6 @@ class channel {
|
|
|
354
431
|
return true
|
|
355
432
|
}
|
|
356
433
|
|
|
357
|
-
/**
|
|
358
|
-
* Add _bridge object to both channel
|
|
359
|
-
* @param { object } other - other channel
|
|
360
|
-
* @returns { void }
|
|
361
|
-
*/
|
|
362
|
-
_createbridges( other ) {
|
|
363
|
-
|
|
364
|
-
if( !this._bridge && !other._bridge ) {
|
|
365
|
-
this._bridge = other._bridge = {
|
|
366
|
-
"bridges": [],
|
|
367
|
-
"main": this.connection.instance
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if( !this._bridge && other._bridge ) this._bridge = other._bridge
|
|
372
|
-
if( this._bridge && !other._bridge ) other._bridge = this._bridge
|
|
373
|
-
|
|
374
|
-
if( this._bridge !== other._bridge )
|
|
375
|
-
throw new Error( "some complex mixing occured and this function needs finishing" )
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Any channels which have been mixed we create an
|
|
380
|
-
* object common to both channels so we can keep track of channels which
|
|
381
|
-
* require tidyin up. We try to maintain a star shaped network.
|
|
382
|
-
* In the example diagram, the out mix method mixes between phone1 and this
|
|
383
|
-
* and phone2 and other.
|
|
384
|
-
* Markdown (mermaid)
|
|
385
|
-
graph TD
|
|
386
|
-
this -->|rtp - our created bridge to link the 2 remote channels| other
|
|
387
|
-
other --> this
|
|
388
|
-
|
|
389
|
-
phone1 --> this
|
|
390
|
-
this --> phone1
|
|
391
|
-
|
|
392
|
-
phone2 --> other
|
|
393
|
-
other --> phone2
|
|
394
|
-
* @private
|
|
395
|
-
* @param { object } other - other channel
|
|
396
|
-
* @returns { Promise< boolean > }
|
|
397
|
-
*/
|
|
398
|
-
async _addbridge( other ) {
|
|
399
|
-
|
|
400
|
-
let leftid = this.connection.instance
|
|
401
|
-
const rightid = other.connection.instance
|
|
402
|
-
|
|
403
|
-
this._createbridges( other )
|
|
404
|
-
|
|
405
|
-
/* nothing more to do if we are on the same node */
|
|
406
|
-
if( rightid === leftid ) return false
|
|
407
|
-
|
|
408
|
-
/* It might have changed now we have linked them up */
|
|
409
|
-
leftid = this._bridge.main
|
|
410
|
-
|
|
411
|
-
let found = false
|
|
412
|
-
for( const bridge of this._bridge.bridges ) {
|
|
413
|
-
if( ( bridge.left.connection.instance === leftid || bridge.right.connection.instance === leftid ) &&
|
|
414
|
-
( bridge.left.connection.instance === rightid || bridge.right.connection.instance === rightid ) ) {
|
|
415
|
-
found = true
|
|
416
|
-
bridge.channels.add( this )
|
|
417
|
-
bridge.channels.add( other )
|
|
418
|
-
|
|
419
|
-
this.mix( bridge.left )
|
|
420
|
-
other.mix( bridge.right )
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if( found ) return
|
|
425
|
-
|
|
426
|
-
const bridge = {
|
|
427
|
-
/* TODO: this will need reworking with to support reverse connection types */
|
|
428
|
-
"left": await serverinterface.get().openchannel( { "nodeinstance": leftid } ),
|
|
429
|
-
"right": await serverinterface.get().openchannel( { "nodeinstance": rightid } ),
|
|
430
|
-
"channels": new Set( [ this, other ] )
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const addressleft = bridge.left.local.privateaddress || bridge.left.local.address
|
|
434
|
-
const addressright = bridge.right.local.privateaddress || bridge.right.local.address
|
|
435
|
-
const g722 = 9
|
|
436
|
-
|
|
437
|
-
bridge.left.remote( { "address": addressright, "port": bridge.right.local.port, "codec": g722 } )
|
|
438
|
-
bridge.right.remote( { "address": addressleft, "port": bridge.left.local.port, "codec": g722 } )
|
|
439
|
-
|
|
440
|
-
this._bridge.bridges.push( bridge )
|
|
441
|
-
|
|
442
|
-
this._write( {
|
|
443
|
-
"channel": "mix",
|
|
444
|
-
"other": {
|
|
445
|
-
"id": bridge.left.id,
|
|
446
|
-
"uuid": bridge.left.uuid
|
|
447
|
-
}
|
|
448
|
-
} )
|
|
449
|
-
|
|
450
|
-
other._write( {
|
|
451
|
-
"channel": "mix",
|
|
452
|
-
"other": {
|
|
453
|
-
"id": bridge.right.id,
|
|
454
|
-
"uuid": bridge.right.uuid
|
|
455
|
-
}
|
|
456
|
-
} )
|
|
457
|
-
|
|
458
|
-
return true
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* We check if we are a remote node (i.e.. not the centre of the star)
|
|
463
|
-
* then we close down the link between the two.
|
|
464
|
-
* @private
|
|
465
|
-
* @returns { boolean }
|
|
466
|
-
*/
|
|
467
|
-
_removebridge() {
|
|
468
|
-
|
|
469
|
-
/* no remote bridges have been created */
|
|
470
|
-
if( !this._bridge || !this._bridge.main ) return
|
|
471
|
-
|
|
472
|
-
const usid = this.connection.instance
|
|
473
|
-
|
|
474
|
-
/* The centre of star cannot remove from the network until last man standing */
|
|
475
|
-
if( usid == this._bridge.main ) return
|
|
476
|
-
|
|
477
|
-
this._bridge.bridges = this._bridge.bridges.filter( ( bridge ) => {
|
|
478
|
-
bridge.channels.delete( this )
|
|
479
|
-
|
|
480
|
-
if( 2 > bridge.channels.size ) {
|
|
481
|
-
|
|
482
|
-
bridge.left._write( { "channel": "unmix" } )
|
|
483
|
-
bridge.left._write( { "channel": "unmix" } )
|
|
484
|
-
|
|
485
|
-
bridge.left.close()
|
|
486
|
-
bridge.right.close()
|
|
487
|
-
return false /* remove */
|
|
488
|
-
}
|
|
489
|
-
return true /* keep */
|
|
490
|
-
} )
|
|
491
|
-
}
|
|
492
|
-
|
|
493
434
|
/**
|
|
494
435
|
@summary Removes us from an existing mix
|
|
495
436
|
@returns { boolean }
|
|
@@ -592,6 +533,7 @@ class channel {
|
|
|
592
533
|
}
|
|
593
534
|
|
|
594
535
|
/**
|
|
536
|
+
* We have received teh open confirm message so we should action it
|
|
595
537
|
* @private
|
|
596
538
|
* @param { object } msg
|
|
597
539
|
* @returns { boolean } - is further processing required
|
|
@@ -605,33 +547,66 @@ class channel {
|
|
|
605
547
|
|
|
606
548
|
if( !this.openresolve ) return true
|
|
607
549
|
this.openresolve( this )
|
|
550
|
+
clearTimeout( this.opentimer )
|
|
608
551
|
delete this.openresolve
|
|
609
552
|
delete this.openreject
|
|
553
|
+
delete this.opentimer
|
|
610
554
|
|
|
611
555
|
return true
|
|
612
556
|
}
|
|
613
557
|
|
|
614
558
|
/**
|
|
615
|
-
*
|
|
559
|
+
* We have received a close message so we should action it
|
|
560
|
+
* @param { object } msg
|
|
616
561
|
* @returns { void }
|
|
617
562
|
* @private
|
|
618
563
|
*/
|
|
619
|
-
_runclose() {
|
|
620
|
-
if(
|
|
621
|
-
|
|
564
|
+
_runclose( msg ) {
|
|
565
|
+
if( this.openreject ) {
|
|
566
|
+
console.error( "Received close before open", msg )
|
|
567
|
+
this.openreject( new Error( "Received close before open" ) )
|
|
568
|
+
clearTimeout( this.opentimer )
|
|
622
569
|
delete this.openresolve
|
|
623
570
|
delete this.openreject
|
|
571
|
+
delete this.opentimer
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if( this.closeresolve ) {
|
|
575
|
+
this.closeresolve( msg )
|
|
576
|
+
clearTimeout( this.closetimer )
|
|
577
|
+
delete this.closeresolve
|
|
578
|
+
delete this.closereject
|
|
579
|
+
delete this.closetimer
|
|
624
580
|
}
|
|
625
581
|
|
|
582
|
+
this.#cleanupsharedchannels()
|
|
583
|
+
channels.delete( this.id )
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
#cleanupsharedchannels() {
|
|
626
587
|
if( this.channels ) {
|
|
627
588
|
// adjust with filter
|
|
628
589
|
const index = this.channels.indexOf( this )
|
|
629
590
|
if( -1 < index ) this.channels.splice( index, 1 )
|
|
630
|
-
if( 0 === this.channels.length && this.connection.sock )
|
|
591
|
+
if( 0 === this.channels.length && this.connection.sock ) {
|
|
592
|
+
this.connection.sock.destroy()
|
|
593
|
+
}
|
|
631
594
|
}
|
|
595
|
+
}
|
|
632
596
|
|
|
597
|
+
#haserror( msg ) {
|
|
598
|
+
if( !msg.error ) return false
|
|
599
|
+
console.error( msg )
|
|
633
600
|
|
|
634
|
-
|
|
601
|
+
if( this.openreject ) {
|
|
602
|
+
this.openreject( new Error( msg.error ) )
|
|
603
|
+
clearTimeout( this.opentimer )
|
|
604
|
+
delete this.openresolve
|
|
605
|
+
delete this.openreject
|
|
606
|
+
delete this.opentimer
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return true
|
|
635
610
|
}
|
|
636
611
|
|
|
637
612
|
/**
|
|
@@ -643,11 +618,12 @@ class channel {
|
|
|
643
618
|
msg.timestamp = ( new Date ).getTime()
|
|
644
619
|
this.history.push( msg )
|
|
645
620
|
if( this._runopen( msg ) ) return
|
|
621
|
+
if( this.#haserror( msg ) ) return
|
|
646
622
|
|
|
647
623
|
this.em.emit( "all", msg )
|
|
648
624
|
this.em.emit( msg.action, msg )
|
|
649
625
|
|
|
650
|
-
if( "close" == msg.action ) this._runclose()
|
|
626
|
+
if( "close" == msg.action ) this._runclose( msg )
|
|
651
627
|
}
|
|
652
628
|
|
|
653
629
|
/**
|
|
@@ -765,16 +741,16 @@ class rtpserver {
|
|
|
765
741
|
|
|
766
742
|
if( 0 === nodes.size && 0 === listeningnodes.length ) {
|
|
767
743
|
console.error( "No available RTP nodes" )
|
|
768
|
-
reject( "No available RTP nodes" )
|
|
744
|
+
reject( new Error( "No available RTP nodes" ) )
|
|
769
745
|
}
|
|
770
746
|
|
|
771
747
|
const request = JSON.parse( JSON.stringify( options ) )
|
|
772
748
|
request.channel = "open"
|
|
773
749
|
|
|
774
750
|
const node = randomenode( options.nodeinstance )
|
|
775
|
-
|
|
751
|
+
|
|
776
752
|
if ( 0 < nodes.size ) channel._createforlisten( request, node, callback, resolve, reject )
|
|
777
|
-
else channel._createforconnect( request, callback, resolve )
|
|
753
|
+
else channel._createforconnect( request, callback, resolve, reject )
|
|
778
754
|
|
|
779
755
|
} )
|
|
780
756
|
}
|