@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/src/projectrtpbuffer.cpp
CHANGED
|
@@ -53,7 +53,21 @@ Returns the next packet in order - does not modify our structure.
|
|
|
53
53
|
rtppacket* rtpbuffer::peek( void ) {
|
|
54
54
|
if( nullptr != this->peekedpopped ) return this->peekedpopped;
|
|
55
55
|
uint16_t bufindex = this->outsn % this->buffercount;
|
|
56
|
-
|
|
56
|
+
rtppacket *out = this->orderedrtpdata.at( bufindex );
|
|
57
|
+
|
|
58
|
+
if( out == nullptr ) {
|
|
59
|
+
this->outsn++;
|
|
60
|
+
return nullptr;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if( out->getsequencenumber() != this->outsn ) {
|
|
64
|
+
this->orderedrtpdata.at( this->outsn % this->buffercount ) = nullptr;
|
|
65
|
+
this->availablertpdata.push( out );
|
|
66
|
+
this->badsn++;
|
|
67
|
+
return nullptr;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this->peekedpopped = out;
|
|
57
71
|
return this->peekedpopped;
|
|
58
72
|
}
|
|
59
73
|
|
|
@@ -72,7 +86,7 @@ rtppacket* rtpbuffer::poppeeked( void ) {
|
|
|
72
86
|
this->availablertpdata.push( out );
|
|
73
87
|
}
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
this->popped++;
|
|
76
90
|
return out;
|
|
77
91
|
}
|
|
78
92
|
|
|
@@ -81,25 +95,9 @@ Returns the next packet in order.
|
|
|
81
95
|
*/
|
|
82
96
|
rtppacket* rtpbuffer::pop( void ) {
|
|
83
97
|
rtppacket *out = this->peek();
|
|
84
|
-
uint16_t oldsn = this->outsn;
|
|
85
|
-
this->outsn++;
|
|
86
|
-
|
|
87
|
-
this->peekedpopped = nullptr;
|
|
88
98
|
if( nullptr == out ) return nullptr;
|
|
99
|
+
this->poppeeked();
|
|
89
100
|
|
|
90
|
-
uint16_t bufindex = oldsn % this->buffercount;
|
|
91
|
-
if( nullptr != this->orderedrtpdata.at( bufindex ) ) {
|
|
92
|
-
this->orderedrtpdata.at( bufindex ) = nullptr;
|
|
93
|
-
this->availablertpdata.push( out );
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
auto outsn = out->getsequencenumber();
|
|
97
|
-
if( outsn != oldsn ) {
|
|
98
|
-
this->badsn++;
|
|
99
|
-
return nullptr;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this->popped++;
|
|
103
101
|
return out;
|
|
104
102
|
}
|
|
105
103
|
|
package/src/projectrtpbuffer.h
CHANGED
|
@@ -48,6 +48,7 @@ public:
|
|
|
48
48
|
int waterlevel = BUFFERPACKETCAP /* the level we build up before allowing a read */ );
|
|
49
49
|
|
|
50
50
|
rtppacket* peek( void );
|
|
51
|
+
rtppacket* peeked( void ) { return this->peekedpopped; }
|
|
51
52
|
rtppacket* poppeeked( void );
|
|
52
53
|
rtppacket* pop( void );
|
|
53
54
|
void push( void );
|
|
@@ -19,7 +19,49 @@
|
|
|
19
19
|
extern boost::asio::io_context workercontext;
|
|
20
20
|
std::queue < unsigned short >availableports;
|
|
21
21
|
std::atomic_bool availableportslock( false );
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
std::atomic< std::uint32_t > channelscreated{ 0 };
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the next available port.
|
|
27
|
+
*/
|
|
28
|
+
unsigned short getavailableport( void ) {
|
|
29
|
+
AQUIRESPINLOCK( availableportslock );
|
|
30
|
+
auto ourport = availableports.front();
|
|
31
|
+
availableports.pop();
|
|
32
|
+
RELEASESPINLOCK( availableportslock );
|
|
33
|
+
|
|
34
|
+
channelscreated.fetch_add( 1 );
|
|
35
|
+
|
|
36
|
+
return ourport;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns the number of ports we still have available.
|
|
41
|
+
* @returns { size_t }
|
|
42
|
+
*/
|
|
43
|
+
auto getvailableportsize() {
|
|
44
|
+
AQUIRESPINLOCK( availableportslock );
|
|
45
|
+
auto availableportssize = availableports.size();
|
|
46
|
+
RELEASESPINLOCK( availableportslock );
|
|
47
|
+
|
|
48
|
+
return availableportssize;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Return a port number to the available list (to the back) and clear our value
|
|
53
|
+
* so we cannot return it twice.
|
|
54
|
+
*/
|
|
55
|
+
void projectrtpchannel::returnavailableport( void ) {
|
|
56
|
+
|
|
57
|
+
if( 0 == this->port ) return;
|
|
58
|
+
AQUIRESPINLOCK( availableportslock );
|
|
59
|
+
availableports.push( this->port );
|
|
60
|
+
this->port = 0;
|
|
61
|
+
RELEASESPINLOCK( availableportslock );
|
|
62
|
+
|
|
63
|
+
channelscreated.fetch_sub( 1 );
|
|
64
|
+
}
|
|
23
65
|
|
|
24
66
|
/* useful for random string generation */
|
|
25
67
|
const char alphanumsecret[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
|
@@ -53,6 +95,7 @@ projectrtpchannel::projectrtpchannel( unsigned short port ):
|
|
|
53
95
|
totalticktime( 0 ),
|
|
54
96
|
totaltickcount( 0 ),
|
|
55
97
|
tickswithnortpcount( 0 ),
|
|
98
|
+
hardtickswithnortpcount( 0 ),
|
|
56
99
|
outpkwritecount( 0 ),
|
|
57
100
|
outpkcount( 0 ),
|
|
58
101
|
outpkskipcount( 0 ),
|
|
@@ -107,8 +150,6 @@ projectrtpchannel::projectrtpchannel( unsigned short port ):
|
|
|
107
150
|
lastdtmfsn( 0 ),
|
|
108
151
|
tickstarttime() {
|
|
109
152
|
|
|
110
|
-
channelscreated++;
|
|
111
|
-
|
|
112
153
|
gnutls_rnd( GNUTLS_RND_RANDOM, &this->ssrcout, 4 );
|
|
113
154
|
|
|
114
155
|
char localicepwd[ 25 ];
|
|
@@ -241,6 +282,7 @@ void projectrtpchannel::handleremoteresolve (
|
|
|
241
282
|
|
|
242
283
|
this->confirmedrtpsenderendpoint = *it;
|
|
243
284
|
this->remoteconfirmed = true;
|
|
285
|
+
this->hardtickswithnortpcount = 0;
|
|
244
286
|
|
|
245
287
|
/* allow us to re-auto correct */
|
|
246
288
|
this->autoadjust = true;
|
|
@@ -264,29 +306,65 @@ uint32_t projectrtpchannel::requestopen( void ) {
|
|
|
264
306
|
return this->ssrcout;
|
|
265
307
|
}
|
|
266
308
|
|
|
309
|
+
/**
|
|
310
|
+
* handle errors on socket open
|
|
311
|
+
*/
|
|
312
|
+
void projectrtpchannel::badsocketopen( const char *err ) {
|
|
313
|
+
|
|
314
|
+
fprintf( stderr, "Socket issue - refusing a new channel: %s\n", err );
|
|
315
|
+
|
|
316
|
+
if( this->rtpsocket.is_open() ) {
|
|
317
|
+
this->rtpsocket.close();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if( !this->rtcpsocket.is_open() ) {
|
|
321
|
+
this->rtcpsocket.close();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
this->returnavailableport();
|
|
325
|
+
|
|
326
|
+
postdatabacktojsfromthread( shared_from_this(), "close", "error.nosocket" );
|
|
327
|
+
}
|
|
328
|
+
|
|
267
329
|
/**
|
|
268
330
|
* Must be called in the workercontext.
|
|
269
331
|
*/
|
|
270
332
|
void projectrtpchannel::doopen( void ) {
|
|
271
333
|
|
|
334
|
+
boost::system::error_code ec;
|
|
335
|
+
|
|
272
336
|
this->outcodec.reset();
|
|
273
337
|
this->incodec.reset();
|
|
274
338
|
|
|
275
|
-
boost::asio::
|
|
276
|
-
|
|
277
|
-
|
|
339
|
+
this->rtpsocket.open( boost::asio::ip::udp::v4(), ec );
|
|
340
|
+
|
|
341
|
+
if( ec ) {
|
|
342
|
+
this->badsocketopen( "failed to open rtp socket" );
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
278
346
|
this->rtpsocket.bind( boost::asio::ip::udp::endpoint(
|
|
279
|
-
boost::asio::ip::udp::v4(), this->port ) );
|
|
347
|
+
boost::asio::ip::udp::v4(), this->port ), ec );
|
|
348
|
+
|
|
349
|
+
if( ec ) {
|
|
350
|
+
auto err = std::string( "failed to bind rtp socket: " ) + std::to_string( this->port ) + std::string( ": " ) + ec.message();
|
|
351
|
+
this->badsocketopen( err.c_str() );
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
this->rtcpsocket.open( boost::asio::ip::udp::v4(), ec );
|
|
356
|
+
|
|
357
|
+
if( ec ) {
|
|
358
|
+
this->badsocketopen( "failed to open rtcp socket" );
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
280
361
|
|
|
281
|
-
this->rtcpsocket.open( boost::asio::ip::udp::v4() );
|
|
282
|
-
this->rtcpsocket.set_option( reuseoption );
|
|
283
362
|
this->rtcpsocket.bind( boost::asio::ip::udp::endpoint(
|
|
284
|
-
boost::asio::ip::udp::v4(), this->port + 1 ) );
|
|
363
|
+
boost::asio::ip::udp::v4(), this->port + 1 ), ec );
|
|
285
364
|
|
|
286
|
-
if(
|
|
287
|
-
|
|
288
|
-
this->
|
|
289
|
-
this->doclose();
|
|
365
|
+
if( ec ) {
|
|
366
|
+
auto err = std::string( "failed to bind rtcp socket: " ) + std::to_string( this->port + 1 ) + std::string( ": " ) + ec.message();
|
|
367
|
+
this->badsocketopen( err.c_str() );
|
|
290
368
|
return;
|
|
291
369
|
}
|
|
292
370
|
|
|
@@ -333,11 +411,15 @@ void projectrtpchannel::requestecho( bool e ) {
|
|
|
333
411
|
this->doecho = e;
|
|
334
412
|
}
|
|
335
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Worker thread to perform teh close. It will only run if the channel has
|
|
416
|
+
* been active (i.e. the sockets have been opened sucsessfully)
|
|
417
|
+
*/
|
|
336
418
|
void projectrtpchannel::doclose( void ) {
|
|
337
419
|
|
|
338
420
|
if( !this->active ) return;
|
|
339
|
-
|
|
340
421
|
this->active = false;
|
|
422
|
+
|
|
341
423
|
this->tick.cancel();
|
|
342
424
|
|
|
343
425
|
if( nullptr != this->player ) {
|
|
@@ -365,25 +447,30 @@ void projectrtpchannel::doclose( void ) {
|
|
|
365
447
|
this->rtpsocket.close();
|
|
366
448
|
this->rtcpsocket.close();
|
|
367
449
|
|
|
368
|
-
|
|
369
|
-
availableports.push( this->getport() );
|
|
370
|
-
RELEASESPINLOCK( availableportslock );
|
|
371
|
-
|
|
372
|
-
channelscreated--;
|
|
450
|
+
this->returnavailableport();
|
|
373
451
|
|
|
374
452
|
postdatabacktojsfromthread( shared_from_this(), "close", this->closereason );
|
|
375
453
|
}
|
|
376
454
|
|
|
377
455
|
bool projectrtpchannel::checkidlerecv( void ) {
|
|
378
456
|
if( this->recv && this->active ) {
|
|
379
|
-
|
|
380
|
-
|
|
457
|
+
|
|
458
|
+
this->hardtickswithnortpcount++;
|
|
459
|
+
if( this->remoteconfirmed ) {
|
|
460
|
+
|
|
461
|
+
this->tickswithnortpcount++;
|
|
462
|
+
if( this->tickswithnortpcount > ( 50 * 20 ) ) { /* 50 (@20mS ptime)/S = 20S */
|
|
463
|
+
this->closereason = "idle";
|
|
464
|
+
this->doclose();
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
} else if( this->hardtickswithnortpcount > ( 50 * 60 * 60 ) ) { /* 1hr hard timeout */
|
|
381
469
|
this->closereason = "idle";
|
|
382
470
|
this->doclose();
|
|
383
471
|
return true;
|
|
384
472
|
}
|
|
385
473
|
}
|
|
386
|
-
|
|
387
474
|
return false;
|
|
388
475
|
}
|
|
389
476
|
|
|
@@ -600,20 +687,27 @@ void projectrtpchannel::removeoldrecorders( void ) {
|
|
|
600
687
|
|
|
601
688
|
if( rec->requestfinish ) {
|
|
602
689
|
rec->completed = true;
|
|
690
|
+
rec->maxsincestartpower = 0;
|
|
603
691
|
postdatabacktojsfromthread( shared_from_this(), "record", rec->file, "finished.requested" );
|
|
604
692
|
continue;
|
|
605
693
|
}
|
|
606
694
|
|
|
607
|
-
if( rec->
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
695
|
+
if( rec->lastpowercalc > rec->maxsincestartpower ) {
|
|
696
|
+
rec->maxsincestartpower = rec->lastpowercalc;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if( rec->finishbelowpower > 0 &&
|
|
700
|
+
rec->maxsincestartpower > rec->finishbelowpower &&
|
|
701
|
+
rec->lastpowercalc < rec->finishbelowpower ) {
|
|
702
|
+
rec->completed = true;
|
|
703
|
+
rec->maxsincestartpower = 0;
|
|
704
|
+
postdatabacktojsfromthread( shared_from_this(), "record", rec->file, "finished.belowpower" );
|
|
705
|
+
continue;
|
|
613
706
|
}
|
|
614
707
|
|
|
615
708
|
if( 0 != rec->maxduration && diff.total_milliseconds() > rec->maxduration ) {
|
|
616
709
|
rec->completed = true;
|
|
710
|
+
rec->maxsincestartpower = 0;
|
|
617
711
|
postdatabacktojsfromthread( shared_from_this(), "record", rec->file, "finished.timeout" );
|
|
618
712
|
continue;
|
|
619
713
|
}
|
|
@@ -802,6 +896,7 @@ void projectrtpchannel::correctaddress( void ) {
|
|
|
802
896
|
if( this->autoadjust ) {
|
|
803
897
|
this->confirmedrtpsenderendpoint = this->rtpsenderendpoint;
|
|
804
898
|
this->remoteconfirmed = true;
|
|
899
|
+
this->hardtickswithnortpcount = 0;
|
|
805
900
|
this->autoadjust = false;
|
|
806
901
|
}
|
|
807
902
|
}
|
|
@@ -905,6 +1000,7 @@ void projectrtpchannel::readsomertp( void ) {
|
|
|
905
1000
|
*/
|
|
906
1001
|
|
|
907
1002
|
this->tickswithnortpcount = 0;
|
|
1003
|
+
this->hardtickswithnortpcount = 0;
|
|
908
1004
|
|
|
909
1005
|
/* dynamic payload types */
|
|
910
1006
|
auto pt = buf->getpayloadtype();
|
|
@@ -1168,25 +1264,52 @@ void projectrtpchannel::senddtmf( void ) {
|
|
|
1168
1264
|
return;
|
|
1169
1265
|
}
|
|
1170
1266
|
|
|
1267
|
+
const char volume = 15;
|
|
1268
|
+
const char endofevent = 0x80;
|
|
1269
|
+
|
|
1171
1270
|
rtppacket *dst = this->gettempoutbuf();
|
|
1172
1271
|
dst->setpayloadtype( this->rfc2833pt );
|
|
1173
|
-
dst->setmarker();
|
|
1174
1272
|
dst->setpayloadlength( 4 );
|
|
1175
1273
|
uint8_t *pl = dst->getpayload();
|
|
1176
1274
|
pl[ 0 ] = tosend;
|
|
1177
|
-
pl[ 1 ] =
|
|
1178
|
-
pl[ 2 ]
|
|
1179
|
-
|
|
1275
|
+
pl[ 1 ] = volume; /* end of event & reserved & volume */
|
|
1276
|
+
uint16_t *tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1277
|
+
*tmp = htons( 160 );
|
|
1278
|
+
|
|
1279
|
+
this->writepacket( dst );
|
|
1280
|
+
|
|
1281
|
+
dst = this->gettempoutbuf();
|
|
1282
|
+
dst->setpayloadtype( this->rfc2833pt );
|
|
1283
|
+
dst->setpayloadlength( 4 );
|
|
1284
|
+
pl = dst->getpayload();
|
|
1285
|
+
pl[ 0 ] = tosend;
|
|
1286
|
+
pl[ 1 ] = volume; /* end of event & reserved & volume */
|
|
1287
|
+
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1288
|
+
*tmp = htons( 320 );
|
|
1289
|
+
|
|
1290
|
+
this->writepacket( dst );
|
|
1291
|
+
|
|
1292
|
+
dst = this->gettempoutbuf();
|
|
1293
|
+
dst->setpayloadtype( this->rfc2833pt );
|
|
1294
|
+
dst->setpayloadlength( 4 );
|
|
1295
|
+
pl = dst->getpayload();
|
|
1296
|
+
pl[ 0 ] = tosend;
|
|
1297
|
+
pl[ 1 ] = volume; /* end of event & reserved & volume */
|
|
1298
|
+
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1299
|
+
*tmp = htons( 480 );
|
|
1300
|
+
|
|
1180
1301
|
this->writepacket( dst );
|
|
1181
1302
|
|
|
1182
1303
|
dst = this->gettempoutbuf();
|
|
1183
1304
|
dst->setpayloadtype( this->rfc2833pt );
|
|
1305
|
+
dst->setmarker();
|
|
1184
1306
|
dst->setpayloadlength( 4 );
|
|
1185
1307
|
pl = dst->getpayload();
|
|
1186
1308
|
pl[ 0 ] = tosend;
|
|
1187
|
-
pl[ 1 ] =
|
|
1188
|
-
pl[ 2 ]
|
|
1189
|
-
|
|
1309
|
+
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1310
|
+
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1311
|
+
*tmp = htons( 640 );
|
|
1312
|
+
|
|
1190
1313
|
this->writepacket( dst );
|
|
1191
1314
|
|
|
1192
1315
|
dst = this->gettempoutbuf();
|
|
@@ -1194,9 +1317,21 @@ void projectrtpchannel::senddtmf( void ) {
|
|
|
1194
1317
|
dst->setpayloadlength( 4 );
|
|
1195
1318
|
pl = dst->getpayload();
|
|
1196
1319
|
pl[ 0 ] = tosend;
|
|
1197
|
-
pl[ 1 ] =
|
|
1198
|
-
pl[ 2 ]
|
|
1199
|
-
|
|
1320
|
+
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1321
|
+
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1322
|
+
*tmp = htons( 640 );
|
|
1323
|
+
|
|
1324
|
+
this->writepacket( dst );
|
|
1325
|
+
|
|
1326
|
+
dst = this->gettempoutbuf();
|
|
1327
|
+
dst->setpayloadtype( this->rfc2833pt );
|
|
1328
|
+
dst->setpayloadlength( 4 );
|
|
1329
|
+
pl = dst->getpayload();
|
|
1330
|
+
pl[ 0 ] = tosend;
|
|
1331
|
+
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1332
|
+
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1333
|
+
*tmp = htons( 640 );
|
|
1334
|
+
|
|
1200
1335
|
this->writepacket( dst );
|
|
1201
1336
|
|
|
1202
1337
|
this->lastdtmfsn = this->snout;
|
|
@@ -1928,10 +2063,6 @@ static napi_value channelcreate( napi_env env, napi_callback_info info ) {
|
|
|
1928
2063
|
napi_value nremote;
|
|
1929
2064
|
|
|
1930
2065
|
napi_value result;
|
|
1931
|
-
AQUIRESPINLOCK( availableportslock );
|
|
1932
|
-
auto ourport = availableports.front();
|
|
1933
|
-
availableports.pop();
|
|
1934
|
-
RELEASESPINLOCK( availableportslock );
|
|
1935
2066
|
|
|
1936
2067
|
size_t bytescopied;
|
|
1937
2068
|
|
|
@@ -1949,7 +2080,7 @@ static napi_value channelcreate( napi_env env, napi_callback_info info ) {
|
|
|
1949
2080
|
return NULL;
|
|
1950
2081
|
}
|
|
1951
2082
|
|
|
1952
|
-
projectrtpchannel::pointer p = projectrtpchannel::create(
|
|
2083
|
+
projectrtpchannel::pointer p = projectrtpchannel::create( getavailableport() );
|
|
1953
2084
|
|
|
1954
2085
|
/* optional - remote */
|
|
1955
2086
|
dtlssession::mode dtlsmode = dtlssession::none;
|
|
@@ -2196,7 +2327,7 @@ nodtls:
|
|
|
2196
2327
|
if( napi_ok != napi_create_object( env, &nlocal ) ||
|
|
2197
2328
|
napi_ok != napi_set_named_property( env, result, "local", nlocal ) ||
|
|
2198
2329
|
|
|
2199
|
-
napi_ok != napi_create_int32( env,
|
|
2330
|
+
napi_ok != napi_create_int32( env, p->getport(), &nourport ) ||
|
|
2200
2331
|
napi_ok != napi_set_named_property( env, nlocal, "port", nourport ) ||
|
|
2201
2332
|
|
|
2202
2333
|
napi_ok != napi_create_uint32( env, ssrc, &nssrc ) ||
|
|
@@ -2227,12 +2358,8 @@ void getchannelstats( napi_env env, napi_value &result ) {
|
|
|
2227
2358
|
|
|
2228
2359
|
napi_value av, chcount;
|
|
2229
2360
|
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
RELEASESPINLOCK( availableportslock );
|
|
2233
|
-
|
|
2234
|
-
if( napi_ok != napi_create_double( env, availableportssize, &av ) ) return;
|
|
2235
|
-
if( napi_ok != napi_create_double( env, channelscreated, &chcount ) ) return;
|
|
2361
|
+
if( napi_ok != napi_create_double( env, getvailableportsize(), &av ) ) return;
|
|
2362
|
+
if( napi_ok != napi_create_double( env, channelscreated.load(), &chcount ) ) return;
|
|
2236
2363
|
|
|
2237
2364
|
if( napi_ok != napi_set_named_property( env, channel, "available", av ) ) return;
|
|
2238
2365
|
if( napi_ok != napi_set_named_property( env, channel, "current", chcount ) ) return;
|
|
@@ -2241,10 +2368,12 @@ void getchannelstats( napi_env env, napi_value &result ) {
|
|
|
2241
2368
|
void initrtpchannel( napi_env env, napi_value &result, int32_t startport, int32_t endport ) {
|
|
2242
2369
|
napi_value ccreate;
|
|
2243
2370
|
|
|
2371
|
+
AQUIRESPINLOCK( availableportslock );
|
|
2244
2372
|
while(!availableports.empty()) availableports.pop();
|
|
2245
2373
|
for( int i = (int) startport; i < (int) endport; i = i + 2 ) {
|
|
2246
2374
|
availableports.push( i );
|
|
2247
2375
|
}
|
|
2376
|
+
RELEASESPINLOCK( availableportslock );
|
|
2248
2377
|
|
|
2249
2378
|
if( napi_ok != napi_create_function( env, "exports", NAPI_AUTO_LENGTH, channelcreate, nullptr, &ccreate ) ) return;
|
|
2250
2379
|
if( napi_ok != napi_set_named_property( env, result, "openchannel", ccreate ) ) return;
|
package/src/projectrtpchannel.h
CHANGED
|
@@ -133,6 +133,7 @@ public:
|
|
|
133
133
|
std::atomic_uint64_t totalticktime;
|
|
134
134
|
std::atomic_uint64_t totaltickcount;
|
|
135
135
|
std::atomic_uint16_t tickswithnortpcount;
|
|
136
|
+
std::atomic_uint16_t hardtickswithnortpcount;
|
|
136
137
|
|
|
137
138
|
std::atomic_uint64_t outpkwritecount;
|
|
138
139
|
std::atomic_uint64_t outpkcount;
|
|
@@ -220,6 +221,9 @@ private:
|
|
|
220
221
|
static bool recordercompleted( const channelrecorder::pointer& value );
|
|
221
222
|
void dounmix( void );
|
|
222
223
|
|
|
224
|
+
void badsocketopen( const char *err );
|
|
225
|
+
void returnavailableport( void );
|
|
226
|
+
|
|
223
227
|
std::atomic_bool mixerlock;
|
|
224
228
|
projectchannelmuxptr mixer;
|
|
225
229
|
std::atomic_bool mixing;
|
|
@@ -60,6 +60,8 @@ void projectchannelmux::mixall( void ) {
|
|
|
60
60
|
src = chan->inbuff->peek();
|
|
61
61
|
RELEASESPINLOCK( chan->rtpbufferlock );
|
|
62
62
|
|
|
63
|
+
if( nullptr == src ) break;
|
|
64
|
+
|
|
63
65
|
AQUIRESPINLOCK( chan->rtpdtlslock );
|
|
64
66
|
dtlssession::pointer currentdtlssession = chan->rtpdtls;
|
|
65
67
|
RELEASESPINLOCK( chan->rtpdtlslock );
|
|
@@ -68,6 +70,11 @@ void projectchannelmux::mixall( void ) {
|
|
|
68
70
|
if( !currentdtlssession->unprotect( src ) ) {
|
|
69
71
|
chan->receivedpkskip++;
|
|
70
72
|
src = nullptr;
|
|
73
|
+
|
|
74
|
+
AQUIRESPINLOCK( chan->rtpbufferlock );
|
|
75
|
+
chan->inbuff->poppeeked();
|
|
76
|
+
RELEASESPINLOCK( chan->rtpbufferlock );
|
|
77
|
+
break;
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
|
|
@@ -93,7 +100,12 @@ void projectchannelmux::mixall( void ) {
|
|
|
93
100
|
|
|
94
101
|
/* Now we subtract this channel to send to this channel. */
|
|
95
102
|
for( auto& chan: this->channels ) {
|
|
96
|
-
if( !chan->send )
|
|
103
|
+
if( !chan->send ) {
|
|
104
|
+
AQUIRESPINLOCK( chan->rtpbufferlock );
|
|
105
|
+
chan->inbuff->poppeeked();
|
|
106
|
+
RELEASESPINLOCK( chan->rtpbufferlock );
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
97
109
|
|
|
98
110
|
rtppacket *dst = chan->gettempoutbuf();
|
|
99
111
|
|
|
@@ -102,7 +114,7 @@ void projectchannelmux::mixall( void ) {
|
|
|
102
114
|
|
|
103
115
|
if( chan->recv ) {
|
|
104
116
|
AQUIRESPINLOCK( chan->rtpbufferlock );
|
|
105
|
-
rtppacket *src = chan->inbuff->
|
|
117
|
+
rtppacket *src = chan->inbuff->peeked();
|
|
106
118
|
RELEASESPINLOCK( chan->rtpbufferlock );
|
|
107
119
|
if( nullptr != src ) {
|
|
108
120
|
this->subtracted -= chan->incodec;
|
|
@@ -136,6 +148,8 @@ void projectchannelmux::mix2( void ) {
|
|
|
136
148
|
src = chan1->inbuff->pop();
|
|
137
149
|
RELEASESPINLOCK( chan1->rtpbufferlock );
|
|
138
150
|
|
|
151
|
+
if( nullptr == src ) break;
|
|
152
|
+
|
|
139
153
|
AQUIRESPINLOCK( chan1->rtpdtlslock );
|
|
140
154
|
dtlssession::pointer currentdtlssession = chan1->rtpdtls;
|
|
141
155
|
RELEASESPINLOCK( chan1->rtpdtlslock );
|
|
@@ -144,6 +158,7 @@ void projectchannelmux::mix2( void ) {
|
|
|
144
158
|
if( !currentdtlssession->unprotect( src ) ) {
|
|
145
159
|
chan1->receivedpkskip++;
|
|
146
160
|
src = nullptr;
|
|
161
|
+
break;
|
|
147
162
|
}
|
|
148
163
|
}
|
|
149
164
|
|
|
@@ -157,6 +172,8 @@ void projectchannelmux::mix2( void ) {
|
|
|
157
172
|
src = chan2->inbuff->pop();
|
|
158
173
|
RELEASESPINLOCK( chan2->rtpbufferlock );
|
|
159
174
|
|
|
175
|
+
if( nullptr == src ) break;
|
|
176
|
+
|
|
160
177
|
AQUIRESPINLOCK( chan2->rtpdtlslock );
|
|
161
178
|
dtlssession::pointer currentdtlssession = chan2->rtpdtls;
|
|
162
179
|
RELEASESPINLOCK( chan2->rtpdtlslock );
|
|
@@ -165,6 +182,7 @@ void projectchannelmux::mix2( void ) {
|
|
|
165
182
|
if( !currentdtlssession->unprotect( src ) ) {
|
|
166
183
|
chan2->receivedpkskip++;
|
|
167
184
|
src = nullptr;
|
|
185
|
+
break;
|
|
168
186
|
}
|
|
169
187
|
}
|
|
170
188
|
|
|
@@ -30,6 +30,7 @@ public:
|
|
|
30
30
|
/* must have started for this to kick in */
|
|
31
31
|
uint16_t startabovepower;
|
|
32
32
|
/* must have started for this to kick in */
|
|
33
|
+
uint16_t maxsincestartpower;
|
|
33
34
|
uint16_t finishbelowpower;
|
|
34
35
|
/* used in conjunction with finishbelowpower */
|
|
35
36
|
uint32_t minduration; /* mSeconds */
|
package/src/projectrtpcodecx.cpp
CHANGED
|
@@ -69,13 +69,14 @@ static const uint8_t alaw_to_ulaw_table[256] =
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
void gen711convertdata( void ) {
|
|
72
|
-
|
|
72
|
+
int32_t i;
|
|
73
|
+
for( i = 0; i != 65536; i++ ) {
|
|
73
74
|
int16_t l16val = i - 32768;
|
|
74
75
|
_l16topcmu[ i ] = linear_to_ulaw( l16val );
|
|
75
76
|
_l16topcma[ i ] = linear_to_alaw( l16val );
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
for(
|
|
79
|
+
for( i = 0; i != 256; i++ ) {
|
|
79
80
|
_pcmatol16[ i ] = alaw_to_linear( i );
|
|
80
81
|
_pcmutol16[ i ] = ulaw_to_linear( i );
|
|
81
82
|
}
|
|
@@ -149,7 +149,7 @@ describe( "dtmf", function() {
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
it( "single channel and request rtp server to send 2833", function( done ) {
|
|
152
|
-
|
|
152
|
+
/* TODO - check tre fuller structure of an RTP event (duration, volume, etc) */
|
|
153
153
|
/* create our RTP/UDP endpoint */
|
|
154
154
|
const server = dgram.createSocket( "udp4" )
|
|
155
155
|
let dtmfpkcount = 0
|
|
@@ -182,7 +182,7 @@ describe( "dtmf", function() {
|
|
|
182
182
|
|
|
183
183
|
if( "close" === d.action ) {
|
|
184
184
|
server.close()
|
|
185
|
-
expect( dtmfpkcount ).to.equal( 2*
|
|
185
|
+
expect( dtmfpkcount ).to.equal( 2*6 )
|
|
186
186
|
done()
|
|
187
187
|
}
|
|
188
188
|
} )
|
|
@@ -263,7 +263,7 @@ describe( "dtmf", function() {
|
|
|
263
263
|
clienta.close()
|
|
264
264
|
clientb.close()
|
|
265
265
|
|
|
266
|
-
expect( dtmfpkcount ).to.equal( 3*
|
|
266
|
+
expect( dtmfpkcount ).to.equal( 3*6 )
|
|
267
267
|
} )
|
|
268
268
|
|
|
269
269
|
it( "2 channels mixing and request rtp server to send 2833 to one with dynamic payloadtype", async function() {
|
|
@@ -331,7 +331,7 @@ describe( "dtmf", function() {
|
|
|
331
331
|
clienta.close()
|
|
332
332
|
clientb.close()
|
|
333
333
|
|
|
334
|
-
expect( dtmfpkcount ).to.equal( 3*
|
|
334
|
+
expect( dtmfpkcount ).to.equal( 3*6 )
|
|
335
335
|
} )
|
|
336
336
|
|
|
337
337
|
it( "3 channels mixing and request rtp server to send 2833 to one", async function() {
|
|
@@ -414,7 +414,7 @@ describe( "dtmf", function() {
|
|
|
414
414
|
clientb.close()
|
|
415
415
|
clientc.close()
|
|
416
416
|
|
|
417
|
-
expect( dtmfpkcount ).to.equal( 5*
|
|
417
|
+
expect( dtmfpkcount ).to.equal( 5*6 )
|
|
418
418
|
|
|
419
419
|
await finished
|
|
420
420
|
} )
|
|
@@ -971,11 +971,11 @@ describe( "channel mix", function() {
|
|
|
971
971
|
endpointb.close()
|
|
972
972
|
endpointc.close()
|
|
973
973
|
|
|
974
|
-
expect( endpointapkcountzero ).to.be.within(
|
|
975
|
-
expect( endpointbpkcountzero ).to.be.within(
|
|
976
|
-
expect( endpointcpkcountzero ).to.be.within(
|
|
977
|
-
expect( endpointapkcountnotzero ).to.be.within( 4,
|
|
978
|
-
expect( endpointbpkcountnotzero ).to.be.within( 4,
|
|
974
|
+
expect( endpointapkcountzero ).to.be.within( 55, 75 )
|
|
975
|
+
expect( endpointbpkcountzero ).to.be.within( 55, 75 )
|
|
976
|
+
expect( endpointcpkcountzero ).to.be.within( 55, 75 )
|
|
977
|
+
expect( endpointapkcountnotzero ).to.be.within( 4, 18 )
|
|
978
|
+
expect( endpointbpkcountnotzero ).to.be.within( 4, 18 )
|
|
979
979
|
expect( endpointcpkcountnotzero ).to.be.below( 2 )
|
|
980
980
|
|
|
981
981
|
await finished
|
|
@@ -67,11 +67,13 @@ describe( "record", function() {
|
|
|
67
67
|
this.timeout( 1500 )
|
|
68
68
|
this.slow( 1200 )
|
|
69
69
|
|
|
70
|
+
let endclose = 0
|
|
70
71
|
server.bind()
|
|
71
72
|
server.on( "listening", async function() {
|
|
72
73
|
|
|
73
74
|
channel = await prtp.projectrtp.openchannel( { "remote": { "address": "localhost", "port": server.address().port, "codec": 0 } }, function( d ) {
|
|
74
75
|
if( "close" === d.action ) {
|
|
76
|
+
endclose = Date.now()
|
|
75
77
|
server.close()
|
|
76
78
|
}
|
|
77
79
|
} )
|
|
@@ -89,6 +91,7 @@ describe( "record", function() {
|
|
|
89
91
|
} )
|
|
90
92
|
|
|
91
93
|
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 1300 ) } )
|
|
94
|
+
const startclose = Date.now()
|
|
92
95
|
channel.close()
|
|
93
96
|
await new Promise( resolve => { server.on( "close", resolve ) } )
|
|
94
97
|
|
|
@@ -102,6 +105,7 @@ describe( "record", function() {
|
|
|
102
105
|
expect( wavinfo.chunksize ).to.be.within( 28000, 33000 )
|
|
103
106
|
expect( wavinfo.fmtchunksize ).to.equal( 16 )
|
|
104
107
|
expect( wavinfo.subchunksize ).to.be.within( 28000, 33000 )
|
|
108
|
+
expect( endclose - startclose ).to.be.below( 100 )
|
|
105
109
|
|
|
106
110
|
const ourfile = await fspromises.open( "/tmp/ourrecording.wav", "r" )
|
|
107
111
|
const buffer = Buffer.alloc( 28204 )
|