@babblevoice/projectrtp 2.5.35 → 2.5.38

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.
@@ -12,8 +12,7 @@ projectchannelmux::projectchannelmux( boost::asio::io_context &iocontext ):
12
12
  iocontext( iocontext ),
13
13
  tick( iocontext ),
14
14
  nexttick( std::chrono::high_resolution_clock::now() ),
15
- newchannels(),
16
- newchannelslock( false ),
15
+ channelslock( false ),
17
16
  added(),
18
17
  subtracted(),
19
18
  active( false ) {
@@ -99,7 +98,6 @@ void projectchannelmux::mixall( void ) {
99
98
  }
100
99
 
101
100
  if( nullptr != src ) {
102
- chan->incodec << codecx::next;
103
101
  chan->incodec << *src;
104
102
  this->added += chan->incodec;
105
103
  }
@@ -135,7 +133,6 @@ void projectchannelmux::mixall( void ) {
135
133
  }
136
134
  }
137
135
 
138
- chan->outcodec << codecx::next;
139
136
  chan->outcodec << this->subtracted;
140
137
  dst << chan->outcodec;
141
138
  chan->writepacket( dst );
@@ -214,12 +211,12 @@ void projectchannelmux::mix2( void ) {
214
211
  }
215
212
 
216
213
  bool projectchannelmux::channelremoverequested( const projectrtpchannelptr& chan ) {
217
- if( chan->removemixer ) {
214
+ if( chan->removemixer || chan->_requestclose || (!chan->active) ) {
218
215
  chan->dounmix();
219
216
  return true;
220
217
  }
221
218
 
222
- return false;
219
+ return false;
223
220
  }
224
221
 
225
222
  /*
@@ -228,52 +225,65 @@ Our timer handler.
228
225
  void projectchannelmux::handletick( const boost::system::error_code& error ) {
229
226
  if ( error == boost::asio::error::operation_aborted ) return;
230
227
 
231
- if( !this->active ) return;
228
+ /* ensure we are not destroyed during tick */
229
+ auto self = shared_from_this();
232
230
 
233
- this->checkfornewmixes();
231
+ if( !this->active ) return;
234
232
 
235
- /* Check for channels which have request removal */
236
- this->channels.remove_if( channelremoverequested );
233
+ projectchanptrlist workingchannels;
234
+ {
235
+ SpinLockGuard guard( this->channelslock );
236
+ /* Check for channels which have request removal */
237
+ this->channels.remove_if( channelremoverequested );
238
+ /* ensure we have a local copy to maintain life of all objects */
239
+ workingchannels = this->channels;
240
+ }
237
241
 
238
- if( 0 == this->channels.size() ) {
242
+ if( 0 == workingchannels.size() ) {
239
243
  /* We're done */
240
244
  this->active = false;
241
245
  return;
242
246
  }
243
247
 
244
- for( auto& chan: this->channels ) {
248
+ for( auto& chan: workingchannels ) {
249
+ chan->outcodec << codecx::next;
250
+ chan->incodec << codecx::next;
251
+
252
+ {
253
+ SpinLockGuard guard( chan->playerlock );
254
+ /* preserve any players during mix */
255
+ chan->playerstash = chan->player;
256
+ }
257
+
245
258
  chan->startticktimer();
246
- chan->checkfornewrecorders();
247
259
  chan->incrtsout();
248
260
  }
249
261
 
250
- if( 2 == this->channels.size() ) {
262
+ if( 2 == workingchannels.size() ) {
251
263
  this->mix2();
252
- } else if( this->channels.size() > 2 ) {
264
+ } else if( workingchannels.size() > 2 ) {
253
265
  this->mixall();
254
266
  }
255
267
 
256
- for( auto& chan: this->channels ) {
268
+ for( auto& chan: workingchannels ) {
257
269
  chan->senddtmf();
258
- chan->writerecordings();
259
- chan->checkidlerecv();
270
+ chan->writerecordings(); //////////////////// crash here -> channel -> soundfile - there is a problem with the CODEC - this can remove recorders from channel
271
+ chan->checkidlerecv(); // this can call doclose() - recorders might be destroyed now
260
272
  chan->endticktimer();
273
+
274
+ chan->playerstash = nullptr;
261
275
  }
262
276
 
263
277
  /* The last thing we do */
264
- this->setnexttick();
265
-
266
- for( auto& chan: this->channels ) {
267
- chan->endticktimer();
268
- }
278
+ this->setnexttick( self );
269
279
  }
270
280
 
271
- void projectchannelmux::setnexttick( void ) {
281
+ void projectchannelmux::setnexttick( pointer self ) {
272
282
  this->nexttick = this->nexttick + std::chrono::milliseconds( 20 );
273
283
 
274
284
  this->tick.expires_after( this->nexttick - std::chrono::high_resolution_clock::now() );
275
285
  this->tick.async_wait( boost::bind( &projectchannelmux::handletick,
276
- shared_from_this(),
286
+ self,
277
287
  boost::asio::placeholders::error ) );
278
288
  }
279
289
 
@@ -316,35 +326,26 @@ static bool underlyingpointercmp( projectrtpchannelptr l, projectrtpchannelptr r
316
326
  return l.get() > r.get();
317
327
  }
318
328
 
319
- /*
320
- Check for new channels to add to the mix in our own thread.
321
- */
322
- void projectchannelmux::checkfornewmixes( void ) {
323
- SpinLockGuard guard( this->newchannelslock );
329
+ void projectchannelmux::addchannel( projectrtpchannelptr chan ) {
330
+ SpinLockGuard guard( this->channelslock );
324
331
 
325
- for ( auto const& newchan : this->newchannels ) {
326
- this->channels.push_back( newchan );
327
- }
328
- this->newchannels.clear();
332
+ chan->mixing = true;
333
+ this->channels.push_back( chan );
329
334
 
330
335
  this->channels.sort( underlyingpointercmp );
331
336
  this->channels.unique( underlyingpointerequal );
332
337
  }
333
338
 
334
- void projectchannelmux::addchannel( projectrtpchannelptr chan ) {
335
- SpinLockGuard guard( this->newchannelslock );
336
-
337
- chan->mixing = true;
338
- this->newchannels.push_back( chan );
339
- }
340
-
341
339
  void projectchannelmux::addchannels( projectrtpchannelptr chana, projectrtpchannelptr chanb ) {
342
- SpinLockGuard guard( this->newchannelslock );
340
+ SpinLockGuard guard( this->channelslock );
343
341
 
344
342
  chana->mixing = true;
345
343
  chanb->mixing = true;
346
- this->newchannels.push_back( chana );
347
- this->newchannels.push_back( chanb );
344
+ this->channels.push_back( chana );
345
+ this->channels.push_back( chanb );
346
+
347
+ this->channels.sort( underlyingpointercmp );
348
+ this->channels.unique( underlyingpointerequal );
348
349
  }
349
350
 
350
351
  /*
@@ -365,9 +366,7 @@ void projectchannelmux::postrtpdata( projectrtpchannelptr srcchan, projectrtpcha
365
366
  dst->setpayloadtype( dstchan->rfc2833pt );
366
367
  dst->copy( src );
367
368
  } else {
368
- srcchan->incodec << codecx::next;
369
369
  srcchan->incodec << *src;
370
- dstchan->outcodec << codecx::next;
371
370
  dstchan->outcodec << *src;
372
371
  dst << dstchan->outcodec;
373
372
  }
@@ -39,11 +39,10 @@ public:
39
39
 
40
40
  private:
41
41
 
42
- void checkfornewmixes( void );
43
42
  void mix2( void );
44
43
  void mixall( void );
45
44
 
46
- void setnexttick( void );
45
+ void setnexttick( pointer );
47
46
 
48
47
  static bool channelremoverequested( const projectrtpchannelptr& value );
49
48
 
@@ -53,8 +52,7 @@ private:
53
52
  boost::asio::steady_timer tick;
54
53
  std::chrono::high_resolution_clock::time_point nexttick;
55
54
 
56
- projectchanptrlist newchannels;
57
- std::atomic_bool newchannelslock;
55
+ std::atomic_bool channelslock;
58
56
 
59
57
  rawsound added;
60
58
  rawsound subtracted;
@@ -43,15 +43,15 @@ public:
43
43
  boost::posix_time::ptime created;
44
44
  boost::posix_time::ptime activeat;
45
45
 
46
- bool pause;
47
- bool requestfinish;
48
- bool completed; /* indicate clean up required */
46
+ std::atomic_bool pause;
47
+ std::atomic_bool requestfinish;
48
+ std::atomic_bool completed; /* indicate clean up required */
49
49
 
50
50
  private:
51
51
 
52
52
  /* Rolling average of power reads */
53
53
  ma_filter powerfilter;
54
- bool _active;
54
+ std::atomic_bool _active;
55
55
 
56
56
  };
57
57
 
@@ -1,4 +1,7 @@
1
1
 
2
+ /* needed to build on ubuntu */
3
+ #include <utility>
4
+
2
5
  #include <iostream>
3
6
  #include <cstdlib>
4
7
  #include <iomanip>
@@ -223,11 +226,11 @@ bool codecx::g711tol16( void )
223
226
  return false;
224
227
  }
225
228
 
226
- this->l168kref.malloc( G711PAYLOADSAMPLES, sizeof( int16_t ), L168KPAYLOADTYPE );
229
+ this->l168kref.malloc( L16PAYLOADSAMPLES, sizeof( int16_t ), L168KPAYLOADTYPE );
227
230
 
228
231
  int16_t *out = ( int16_t * ) this->l168kref.c_str();
229
232
 
230
- for( size_t i = 0; i < G711PAYLOADSAMPLES; i++ ) {
233
+ for( size_t i = 0; i < L16PAYLOADSAMPLES; i++ ) {
231
234
  *out = convert[ *in ];
232
235
  in++;
233
236
  out++;
@@ -384,8 +387,7 @@ bool codecx::l16tog722( void ) {
384
387
  As it says.
385
388
  */
386
389
  bool codecx::g722tol16( void ) {
387
- if( 0 == this->g722ref.size() ) return false;
388
- if( this->g722ref.isdirty() ) return false;
390
+ if( !this->g722ref.hasdata() ) return false;
389
391
 
390
392
  this->l1616kref.malloc( L1616PAYLOADSAMPLES, sizeof( int16_t ), L1616KPAYLOADTYPE );
391
393
 
@@ -401,7 +403,7 @@ bool codecx::g722tol16( void ) {
401
403
  this->g722ref.c_str(),
402
404
  G722PAYLOADBYTES );
403
405
 
404
- if( 320 != l1616klength ) return false;
406
+ if( L1616PAYLOADSAMPLES != l1616klength ) return false;
405
407
 
406
408
  this->l1616kref.dirty( false );
407
409
  return true;
@@ -460,8 +462,7 @@ Downsample our L16 wideband samples to 8K. Pass through filter then grab every o
460
462
  */
461
463
  bool codecx::l16widetonarrowband( void ) {
462
464
 
463
- if( 0 == this->l1616kref.size() ) return false;
464
- if( this->l1616kref.isdirty() ) return false;
465
+ if( !this->l1616kref.hasdata() ) return false;
465
466
 
466
467
  this->l168kref.malloc( L16PAYLOADSAMPLES, sizeof( int16_t ), L168KPAYLOADTYPE );
467
468
 
@@ -485,9 +486,9 @@ bool codecx::l16widetonarrowband( void ) {
485
486
  Search for the relevent data and convert as necessary.
486
487
  */
487
488
  bool codecx::requirenarrowband( void ) {
488
- if( 0 != this->l168kref.size() && !this->l168kref.isdirty() ) return true;
489
+ if( this->l168kref.hasdata() ) return true;
489
490
 
490
- if( 0 != this->l1616kref.size() && !this->l1616kref.isdirty() ) {
491
+ if( this->l1616kref.hasdata() ) {
491
492
  return this->l16widetonarrowband();
492
493
  }
493
494
 
@@ -501,10 +502,9 @@ bool codecx::requirenarrowband( void ) {
501
502
  ## requirel16
502
503
  Wide or narrow - it doesn't matter - we just need l16
503
504
  */
504
- rawsound& codecx::requirel16( void )
505
- {
506
- if( 0 != this->l168kref.size() && !this->l168kref.isdirty() ) return this->l168kref;
507
- if( 0 != this->l1616kref.size() && !this->l1616kref.isdirty() ) return this->l1616kref;
505
+ rawsound& codecx::requirel16( void ) {
506
+ if( this->l168kref.hasdata() ) return this->l168kref;
507
+ if( this->l1616kref.hasdata() ) return this->l1616kref;
508
508
 
509
509
  if( this->g711tol16() ) return this->l168kref;
510
510
  if( this->ilbctol16() ) return this->l168kref;
@@ -513,77 +513,57 @@ rawsound& codecx::requirel16( void )
513
513
  return this->l168kref;
514
514
  }
515
515
 
516
+ rawsound nullref;
516
517
  /**
517
518
  * Obtain a reference to a rawsound for the codec type pt. i.e. we alrteady have
518
519
  * the input sound and based on the format we want to convert it to that
519
520
  * format.
520
521
  */
521
522
  rawsound& codecx::getref( int pt ) {
522
- /* If we have already have or converted this packet... */
523
- if( PCMAPAYLOADTYPE == pt && 0 != this->pcmaref.size() && !this->pcmaref.isdirty() ) {
524
- return this->pcmaref;
525
- }
526
- else if( PCMUPAYLOADTYPE == pt && 0 != this->pcmuref.size() && !this->pcmuref.isdirty() ) {
527
- return this->pcmuref;
528
- }
529
- else if( ILBCPAYLOADTYPE == pt && 0 != this->ilbcref.size() && !this->ilbcref.isdirty() ) {
530
- return this->ilbcref;
531
- }
532
- else if( G722PAYLOADTYPE == pt && 0 != this->g722ref.size() && !this->g722ref.isdirty() ) {
533
- return this->g722ref;
534
- }
535
- else if( L168KPAYLOADTYPE == pt && 0 != this->l168kref.size() && !this->l168kref.isdirty() ) {
536
- return this->l168kref;
537
- }
538
- else if( L1616KPAYLOADTYPE == pt && 0 != this->l1616kref.size() && !this->l1616kref.isdirty() ) {
539
- return this->l1616kref;
540
- }
541
523
 
542
- /* If we get here we may have L16 but at the wrong sample rate so check and resample - then convert */
543
- /* narrowband targets */
544
524
  switch( pt ) {
545
- case ILBCPAYLOADTYPE: {
546
- this->requirenarrowband();
547
- this->l16toilbc();
548
- return this->ilbcref;
549
- }
550
- case G722PAYLOADTYPE: {
551
- this->requirewideband();
552
- this->l16tog722();
553
-
554
- return this->g722ref;
555
- }
556
- case PCMAPAYLOADTYPE: {
557
- if( !this->pcmuref.isdirty() && this->pcmuref.size() > 0 ) {
525
+ case PCMAPAYLOADTYPE:
526
+ if( this->pcmaref.hasdata() ) return this->pcmaref;
527
+ if( this->pcmuref.hasdata() ) {
558
528
  this->ulaw2alaw();
559
529
  } else {
560
530
  this->requirenarrowband();
561
531
  this->l16topcma();
562
532
  }
563
533
  return this->pcmaref;
564
- }
565
- case PCMUPAYLOADTYPE: {
566
- if( !this->pcmaref.isdirty() && this->pcmaref.size() > 0 ) {
534
+ case PCMUPAYLOADTYPE:
535
+ if( this->pcmuref.hasdata() ) return this->pcmuref;
536
+ if( this->pcmaref.hasdata() ) {
567
537
  this->alaw2ulaw();
568
538
  } else {
569
539
  this->requirenarrowband();
570
540
  this->l16topcmu();
571
541
  }
572
542
  return this->pcmuref;
573
- }
574
- case L168KPAYLOADTYPE: {
543
+ case ILBCPAYLOADTYPE:
544
+ if( this->ilbcref.hasdata() ) return this->ilbcref;
545
+ this->requirenarrowband();
546
+ this->l16toilbc();
547
+ return this->ilbcref;
548
+ case G722PAYLOADTYPE:
549
+ if( this->g722ref.hasdata() ) return this->g722ref;
550
+ this->requirewideband();
551
+ this->l16tog722();
552
+
553
+ return this->g722ref;
554
+ case L168KPAYLOADTYPE:
555
+ if( this->l168kref.hasdata() ) return this->l168kref;
575
556
  this->requirenarrowband();
576
557
  return this->l168kref;
577
- }
578
- case L1616KPAYLOADTYPE: {
558
+ case L1616KPAYLOADTYPE:
559
+ if( this->l1616kref.hasdata() ) return this->l1616kref;
579
560
  this->requirewideband();
580
561
  return this->l1616kref;
581
- }
582
562
  }
583
563
 
584
564
  /* We should ever get here unless an invalid param has been passed in */
585
565
  std::cerr << "codecx::getref call with bad pt: " << pt << std::endl;
586
- return this->pcmuref;
566
+ return nullref;
587
567
  }
588
568
 
589
569
  /*
@@ -1,6 +1,9 @@
1
1
 
2
2
  #ifdef NODE_MODULE
3
3
 
4
+ /* needed to build on ubuntu */
5
+ #include <utility>
6
+
4
7
  #include <node_api.h>
5
8
  #include <string>
6
9
  #include <vector>
@@ -1,4 +1,7 @@
1
1
 
2
+ /* needed to build on ubuntu */
3
+ #include <utility>
4
+
2
5
  #include <iostream>
3
6
  #include <cstdlib>
4
7
  #include <iomanip>
@@ -1,4 +1,7 @@
1
1
 
2
+ /* needed to build on ubuntu */
3
+ #include <utility>
4
+
2
5
  #include <iostream> // cerr
3
6
  #include <cstdlib>
4
7
  #include <iomanip>
@@ -93,21 +96,13 @@ void rawsound::frompt( int payloadtype )
93
96
  case L168KPAYLOADTYPE:
94
97
  {
95
98
  this->samplerate = 8000;
96
- if( 1 == this->bytespersample )
97
- {
98
- this->bytespersample = 2;
99
- this->samples = this->samples / 2;
100
- }
99
+ this->bytespersample = 2;
101
100
  break;
102
101
  }
103
102
  case L1616KPAYLOADTYPE:
104
103
  {
105
104
  this->samplerate = 16000;
106
- if( 1 == this->bytespersample )
107
- {
108
- this->bytespersample = 2;
109
- this->samples = this->samples / 2;
110
- }
105
+ this->bytespersample = 2;
111
106
  break;
112
107
  }
113
108
  }
@@ -225,7 +220,31 @@ void rawsound::malloc( size_t samplecount, size_t bytespersample, int format ) {
225
220
 
226
221
  delete[] this->data;
227
222
  }
228
- this->data = new uint8_t[ requiredsize ];
223
+
224
+ /* make sure data is aligned as ARM and others can throw SIGSEGV on misalignment */
225
+ switch( bytespersample ) {
226
+ case 1:
227
+ {
228
+ this->data = new uint8_t[ samplecount ];
229
+ break;
230
+ }
231
+ case 2:
232
+ {
233
+ this->data = ( uint8_t * ) new uint16_t[ samplecount ];
234
+ break;
235
+ }
236
+ case 4:
237
+ {
238
+ this->data = ( uint8_t * ) new uint32_t[ samplecount ];
239
+ break;
240
+ }
241
+ default:
242
+ {
243
+ /* this shouldn't happen - in fact - please avoid */
244
+ this->data = new uint8_t[ requiredsize ];
245
+ }
246
+ }
247
+
229
248
  this->allocatedlength = requiredsize;
230
249
  }
231
250
 
@@ -26,12 +26,14 @@ public:
26
26
  void malloc( size_t samplecount, size_t bytespersample, int format );
27
27
  void zero( void );
28
28
 
29
+ bool hasdata() { return this->size() != 0 && !this->isdirty(); }
30
+
29
31
  /* needed for << operato on codecx */
30
32
  inline int getpayloadtype( void ) { return this->format; }
31
33
  inline void setpayloadlength( size_t length ) { this->samples = length; };
32
34
  inline void setlength( size_t length ) { this->samples = length; };
33
35
  inline bool isdirty( void ) { return this->dirtydata; }
34
- inline void dirty( bool d = true ) { this->dirtydata = d; }
36
+ inline void dirty( bool d = true ) { this->dirtydata = d; if( d && 0 == allocatedlength ) data = nullptr; }
35
37
  void copy( uint8_t *src, size_t len );
36
38
  void copy( rawsound &other );
37
39