@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.
@@ -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
- this->peekedpopped = this->orderedrtpdata.at( bufindex );
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
- if( out->getsequencenumber() != oldsn ) return nullptr;
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
 
@@ -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
- uint32_t channelscreated = 0;
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::socket_base::reuse_address reuseoption( true );
276
- this->rtpsocket.open( boost::asio::ip::udp::v4() );
277
- this->rtpsocket.set_option( reuseoption );
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( !this->rtpsocket.is_open() || !this->rtcpsocket.is_open() ) {
287
- fprintf( stderr, "No more sockets available - refusing a new channel\n" );
288
- this->requestclose( "error.nosocket" );
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
- AQUIRESPINLOCK( availableportslock );
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
- this->tickswithnortpcount++;
380
- if( this->tickswithnortpcount > ( 50 * 20 ) ) { /* 50 (@20mS ptime)/S = 20S */
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->finishbelowpower > 0 ) {
608
- if( rec->lastpowercalc < rec->finishbelowpower ) {
609
- rec->completed = true;
610
- postdatabacktojsfromthread( shared_from_this(), "record", rec->file, "finished.belowpower" );
611
- continue;
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 ] = 10; /* end of event & reserved & volume */
1178
- pl[ 2 ] = 0; /* event duration high */
1179
- pl[ 3 ] = 160; /* event duration */
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 ] = 10; /* end of event & reserved & volume */
1188
- pl[ 2 ] = 0; /* event duration high */
1189
- pl[ 3 ] = 160; /* event duration */
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 ] = 0x80 | 10; /* end of event & reserved & volume */
1198
- pl[ 2 ] = 0; /* event duration high */
1199
- pl[ 3 ] = 160; /* event duration */
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( ourport );
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, ourport, &nourport ) ||
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
- AQUIRESPINLOCK( availableportslock );
2231
- auto availableportssize = availableports.size();
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;
@@ -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 ) continue;
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->peek();
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
 
@@ -12,6 +12,7 @@ channelrecorder::channelrecorder( std::string file ) :
12
12
  file( file ),
13
13
  poweraveragepackets( 50 ),
14
14
  startabovepower( 0 ),
15
+ maxsincestartpower( 0 ),
15
16
  finishbelowpower( 0 ),
16
17
  minduration( 0 ),
17
18
  maxduration( 0 ),
@@ -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 */
@@ -69,13 +69,14 @@ static const uint8_t alaw_to_ulaw_table[256] =
69
69
  };
70
70
 
71
71
  void gen711convertdata( void ) {
72
- for( int32_t i = 0; i != 65535; i++ ) {
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( uint8_t i = 0; i != 255; i++ ) {
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*3 )
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*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*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*3 )
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( 60, 75 )
975
- expect( endpointbpkcountzero ).to.be.within( 60, 75 )
976
- expect( endpointcpkcountzero ).to.be.within( 60, 75 )
977
- expect( endpointapkcountnotzero ).to.be.within( 4, 12 )
978
- expect( endpointbpkcountnotzero ).to.be.within( 4, 12 )
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 )