@babblevoice/projectrtp 2.5.35 → 2.6.0
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/.dockerignore +2 -0
- package/Dockerfile +5 -7
- package/Dockerfile.debian +42 -0
- package/README.md +18 -1
- package/asan.options +2 -0
- package/binding.gyp +30 -3
- package/index.js +21 -1
- package/jsconfig.json +1 -1
- package/lib/server.js +26 -10
- package/package.json +6 -6
- package/src/globals.h +3 -0
- package/src/projectrtpbuffer.cpp +3 -0
- package/src/projectrtpchannel.cpp +176 -181
- package/src/projectrtpchannel.h +5 -6
- package/src/projectrtpchannelmux.cpp +45 -46
- package/src/projectrtpchannelmux.h +2 -4
- package/src/projectrtpchannelrecorder.h +4 -4
- package/src/projectrtpcodecx.cpp +36 -56
- package/src/projectrtpnodemain.cpp +3 -0
- package/src/projectrtppacket.cpp +3 -0
- package/src/projectrtprawsound.cpp +30 -11
- package/src/projectrtprawsound.h +3 -1
- package/src/projectrtpsoundfile.cpp +260 -182
- package/src/projectrtpsoundfile.h +14 -3
- package/src/projectrtpsoundsoup.cpp +2 -0
- package/src/projectrtpstun.cpp +3 -0
- package/stress/echorecord.scenario.js +4 -1
- package/stress/index.js +4 -1
- package/stress/playbackrecordtoofast.scenario.js +106 -0
- package/stress/playbackthenmix.scenario.js +70 -0
- package/stress/utils.js +27 -3
- package/test/interface/projectrtpdtmf.js +41 -12
- package/test/interface/projectrtpmix.js +78 -0
- package/test/interface/projectrtprecord.js +1 -1
- package/test/interface/projectrtpsound.js +121 -0
|
@@ -128,13 +128,12 @@ projectrtpchannel::projectrtpchannel( unsigned short port ):
|
|
|
128
128
|
outcodec(),
|
|
129
129
|
incodec(),
|
|
130
130
|
player( nullptr ),
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
playerstash( nullptr ),
|
|
132
|
+
playerlock( false ),
|
|
133
133
|
doecho( false ),
|
|
134
134
|
tick( workercontext ),
|
|
135
135
|
nexttick( std::chrono::high_resolution_clock::now() ),
|
|
136
|
-
|
|
137
|
-
newrecorderslock( false ),
|
|
136
|
+
recorderslock( false ),
|
|
138
137
|
recorders(),
|
|
139
138
|
rtpdtls( nullptr ),
|
|
140
139
|
rtpdtlslock( false ),
|
|
@@ -144,6 +143,7 @@ projectrtpchannel::projectrtpchannel( unsigned short port ):
|
|
|
144
143
|
remoteport( 0 ),
|
|
145
144
|
queueddigits(),
|
|
146
145
|
queuddigitslock( false ),
|
|
146
|
+
dtmfsendcount( 0 ),
|
|
147
147
|
lastdtmfsn( 0 ),
|
|
148
148
|
tickstarttime() {
|
|
149
149
|
|
|
@@ -418,16 +418,17 @@ void projectrtpchannel::doclose( void ) {
|
|
|
418
418
|
if( !this->active ) return;
|
|
419
419
|
this->active = false;
|
|
420
420
|
|
|
421
|
-
|
|
421
|
+
auto self = shared_from_this();
|
|
422
422
|
|
|
423
|
-
|
|
424
|
-
postdatabacktojsfromthread( shared_from_this(), "play", "end", "channelclosed" );
|
|
425
|
-
}
|
|
423
|
+
this->tick.cancel();
|
|
426
424
|
|
|
427
425
|
{
|
|
428
|
-
SpinLockGuard guard( this->
|
|
426
|
+
SpinLockGuard guard( this->playerlock );
|
|
427
|
+
if( nullptr != this->player ) {
|
|
428
|
+
postdatabacktojsfromthread( self, "play", "end", "channelclosed" );
|
|
429
|
+
}
|
|
430
|
+
|
|
429
431
|
this->player = nullptr;
|
|
430
|
-
this->newplaydef = nullptr;
|
|
431
432
|
}
|
|
432
433
|
|
|
433
434
|
/* close our session if we have one */
|
|
@@ -437,11 +438,15 @@ void projectrtpchannel::doclose( void ) {
|
|
|
437
438
|
}
|
|
438
439
|
|
|
439
440
|
/* close up any remaining recorders */
|
|
440
|
-
|
|
441
|
-
|
|
441
|
+
{
|
|
442
|
+
SpinLockGuard guard( this->recorderslock );
|
|
443
|
+
for( auto& rec: this->recorders ) {
|
|
444
|
+
postdatabacktojsfromthread( self, "record", rec->file, "finished.channelclosed" );
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
this->recorders.clear();
|
|
442
448
|
}
|
|
443
449
|
|
|
444
|
-
this->recorders.clear();
|
|
445
450
|
this->resolver.cancel();
|
|
446
451
|
|
|
447
452
|
this->rtpsocket.close();
|
|
@@ -449,7 +454,7 @@ void projectrtpchannel::doclose( void ) {
|
|
|
449
454
|
|
|
450
455
|
this->returnavailableport();
|
|
451
456
|
|
|
452
|
-
postdatabacktojsfromthread(
|
|
457
|
+
postdatabacktojsfromthread( self, "close", this->closereason );
|
|
453
458
|
}
|
|
454
459
|
|
|
455
460
|
bool projectrtpchannel::checkidlerecv( void ) {
|
|
@@ -470,6 +475,13 @@ bool projectrtpchannel::checkidlerecv( void ) {
|
|
|
470
475
|
this->doclose();
|
|
471
476
|
return true;
|
|
472
477
|
}
|
|
478
|
+
} else if( this->active ) {
|
|
479
|
+
/* active but not receiving ie on hold or similar - but there are limits! */
|
|
480
|
+
if( this->hardtickswithnortpcount > ( 50 * 60 * 60 * 2 ) ) { /* 2hr hard timeout */
|
|
481
|
+
this->closereason = "idle";
|
|
482
|
+
this->doclose();
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
473
485
|
}
|
|
474
486
|
return false;
|
|
475
487
|
}
|
|
@@ -486,6 +498,8 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
486
498
|
if( error == boost::asio::error::operation_aborted ) return;
|
|
487
499
|
if( !this->active ) return;
|
|
488
500
|
|
|
501
|
+
auto self = shared_from_this();
|
|
502
|
+
|
|
489
503
|
if( this->_requestclose ) {
|
|
490
504
|
this->doclose();
|
|
491
505
|
return;
|
|
@@ -510,11 +524,15 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
510
524
|
return;
|
|
511
525
|
}
|
|
512
526
|
|
|
513
|
-
this->checkfornewrecorders();
|
|
514
|
-
|
|
515
527
|
this->incodec << codecx::next;
|
|
516
528
|
this->outcodec << codecx::next;
|
|
517
529
|
|
|
530
|
+
soundsoup::pointer ourplayer = nullptr;
|
|
531
|
+
{
|
|
532
|
+
SpinLockGuard guard( this->playerlock );
|
|
533
|
+
ourplayer = this->player;
|
|
534
|
+
}
|
|
535
|
+
|
|
518
536
|
rtppacket *src;
|
|
519
537
|
do {
|
|
520
538
|
{
|
|
@@ -543,36 +561,10 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
543
561
|
this->incodec << *src;
|
|
544
562
|
}
|
|
545
563
|
|
|
546
|
-
/* check for new players */
|
|
547
|
-
{
|
|
548
|
-
bool playerreplaced = false;
|
|
549
|
-
bool playernew = false;
|
|
550
|
-
{
|
|
551
|
-
SpinLockGuard guard( this->newplaylock );
|
|
552
|
-
if( nullptr != this->newplaydef ) {
|
|
553
|
-
this->doecho = false;
|
|
554
|
-
|
|
555
|
-
if( nullptr != this->player ) {
|
|
556
|
-
playerreplaced = true;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
this->player = this->newplaydef;
|
|
560
|
-
this->newplaydef = nullptr;
|
|
561
|
-
playernew = true;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if( playerreplaced ) {
|
|
566
|
-
postdatabacktojsfromthread( shared_from_this(), "play", "end", "replaced" );
|
|
567
|
-
}
|
|
568
|
-
if( playernew ) {
|
|
569
|
-
postdatabacktojsfromthread( shared_from_this(), "play", "start", "new" );
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
564
|
if( this->doecho ) {
|
|
574
|
-
if(
|
|
575
|
-
postdatabacktojsfromthread(
|
|
565
|
+
if( ourplayer ) {
|
|
566
|
+
postdatabacktojsfromthread( self, "play", "end", "doecho" );
|
|
567
|
+
SpinLockGuard guard( this->playerlock );
|
|
576
568
|
this->player = nullptr;
|
|
577
569
|
}
|
|
578
570
|
|
|
@@ -583,20 +575,21 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
583
575
|
dst << this->outcodec;
|
|
584
576
|
this->writepacket( dst );
|
|
585
577
|
}
|
|
586
|
-
} else if(
|
|
578
|
+
} else if( ourplayer ) {
|
|
587
579
|
rtppacket *out = this->gettempoutbuf();
|
|
588
580
|
rawsound r;
|
|
589
|
-
if(
|
|
581
|
+
if( ourplayer->read( r ) ) {
|
|
590
582
|
if( r.size() > 0 ) {
|
|
591
583
|
this->outcodec << r;
|
|
592
584
|
out << this->outcodec;
|
|
593
585
|
this->writepacket( out );
|
|
594
586
|
}
|
|
595
587
|
} else {
|
|
588
|
+
postdatabacktojsfromthread( self, "play", "end", "completed" );
|
|
589
|
+
SpinLockGuard guard( this->playerlock );
|
|
596
590
|
this->player = nullptr;
|
|
597
|
-
postdatabacktojsfromthread( shared_from_this(), "play", "end", "completed" );
|
|
598
591
|
}
|
|
599
|
-
}
|
|
592
|
+
}
|
|
600
593
|
|
|
601
594
|
this->writerecordings();
|
|
602
595
|
|
|
@@ -628,50 +621,47 @@ void projectrtpchannel::setnexttick( void ) {
|
|
|
628
621
|
}
|
|
629
622
|
|
|
630
623
|
void projectrtpchannel::requestplay( soundsoup::pointer newdef ) {
|
|
631
|
-
SpinLockGuard guard( this->
|
|
632
|
-
|
|
624
|
+
SpinLockGuard guard( this->playerlock );
|
|
625
|
+
|
|
626
|
+
auto self = shared_from_this();
|
|
627
|
+
|
|
628
|
+
this->doecho = false;
|
|
629
|
+
|
|
630
|
+
if( nullptr != this->player ) {
|
|
631
|
+
postdatabacktojsfromthread( self, "play", "end", "replaced" );
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
postdatabacktojsfromthread( self, "play", "start", "new" );
|
|
635
|
+
this->player = newdef;
|
|
633
636
|
}
|
|
634
637
|
|
|
635
638
|
/*
|
|
636
639
|
Post a request to record (or modify a param of a record). This function is typically
|
|
637
640
|
called from a control thread (i.e. node).
|
|
638
641
|
*/
|
|
639
|
-
void projectrtpchannel::requestrecord( channelrecorder::pointer
|
|
640
|
-
SpinLockGuard guard( this->
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
*/
|
|
648
|
-
void projectrtpchannel::checkfornewrecorders( void ) {
|
|
649
|
-
channelrecorder::pointer rec;
|
|
650
|
-
SpinLockGuard guard( this->newrecorderslock );
|
|
651
|
-
|
|
652
|
-
for ( auto const& newrec : this->newrecorders ) {
|
|
653
|
-
for( auto& currentrec: this->recorders ) {
|
|
654
|
-
if( currentrec->file == newrec->file ) {
|
|
655
|
-
currentrec->pause = newrec->pause;
|
|
656
|
-
currentrec->requestfinish = newrec->requestfinish;
|
|
657
|
-
goto endofwhileloop;
|
|
658
|
-
}
|
|
642
|
+
void projectrtpchannel::requestrecord( channelrecorder::pointer newrec ) {
|
|
643
|
+
SpinLockGuard guard( this->recorderslock );
|
|
644
|
+
|
|
645
|
+
for( auto& currentrec: this->recorders ) {
|
|
646
|
+
if( currentrec->file == newrec->file ) {
|
|
647
|
+
currentrec->pause.store( newrec->pause );
|
|
648
|
+
currentrec->requestfinish.store( newrec->requestfinish );
|
|
649
|
+
return;
|
|
659
650
|
}
|
|
651
|
+
}
|
|
660
652
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
this->recorders.push_back( newrec );
|
|
653
|
+
newrec->sfile = soundfilewriter::create(
|
|
654
|
+
newrec->file,
|
|
655
|
+
newrec->numchannels,
|
|
656
|
+
soundfile::getsampleratefrompt( this->codec ) );
|
|
667
657
|
|
|
668
|
-
endofwhileloop:;
|
|
669
|
-
}
|
|
670
658
|
|
|
671
|
-
this->
|
|
659
|
+
this->recorders.push_back( newrec );
|
|
672
660
|
}
|
|
673
661
|
|
|
674
|
-
void projectrtpchannel::removeoldrecorders(
|
|
662
|
+
void projectrtpchannel::removeoldrecorders( pointer self ) {
|
|
663
|
+
|
|
664
|
+
SpinLockGuard guard( this->recorderslock );
|
|
675
665
|
|
|
676
666
|
for ( auto const& rec : this->recorders ) {
|
|
677
667
|
if( rec->isactive() ) {
|
|
@@ -686,7 +676,7 @@ void projectrtpchannel::removeoldrecorders( void ) {
|
|
|
686
676
|
if( rec->requestfinish ) {
|
|
687
677
|
rec->completed = true;
|
|
688
678
|
rec->maxsincestartpower = 0;
|
|
689
|
-
postdatabacktojsfromthread(
|
|
679
|
+
postdatabacktojsfromthread( self, "record", rec->file, "finished.requested" );
|
|
690
680
|
continue;
|
|
691
681
|
}
|
|
692
682
|
|
|
@@ -699,14 +689,14 @@ void projectrtpchannel::removeoldrecorders( void ) {
|
|
|
699
689
|
rec->lastpowercalc < rec->finishbelowpower ) {
|
|
700
690
|
rec->completed = true;
|
|
701
691
|
rec->maxsincestartpower = 0;
|
|
702
|
-
postdatabacktojsfromthread(
|
|
692
|
+
postdatabacktojsfromthread( self, "record", rec->file, "finished.belowpower" );
|
|
703
693
|
continue;
|
|
704
694
|
}
|
|
705
695
|
|
|
706
696
|
if( 0 != rec->maxduration && diff.total_milliseconds() > rec->maxduration ) {
|
|
707
697
|
rec->completed = true;
|
|
708
698
|
rec->maxsincestartpower = 0;
|
|
709
|
-
postdatabacktojsfromthread(
|
|
699
|
+
postdatabacktojsfromthread( self, "record", rec->file, "finished.timeout" );
|
|
710
700
|
continue;
|
|
711
701
|
}
|
|
712
702
|
}
|
|
@@ -725,12 +715,15 @@ bool projectrtpchannel::recordercompleted( const channelrecorder::pointer& rec )
|
|
|
725
715
|
*/
|
|
726
716
|
static char dtmfchars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'A', 'B', 'C', 'D', 'F' };
|
|
727
717
|
void projectrtpchannel::sendtelevent( void ) {
|
|
718
|
+
auto self = shared_from_this();
|
|
719
|
+
SpinLockGuard guard( this->playerlock );
|
|
720
|
+
|
|
728
721
|
if( this->player && this->player->doesinterupt() ) {
|
|
729
|
-
postdatabacktojsfromthread(
|
|
722
|
+
postdatabacktojsfromthread( self, "play", "end", "telephone-event" );
|
|
730
723
|
this->player = nullptr;
|
|
731
724
|
}
|
|
732
725
|
|
|
733
|
-
postdatabacktojsfromthread(
|
|
726
|
+
postdatabacktojsfromthread( self, "telephone-event", std::string( 1, dtmfchars[ this->lasttelephoneevent ] ) );
|
|
734
727
|
}
|
|
735
728
|
/*
|
|
736
729
|
## checkfordtmf
|
|
@@ -785,11 +778,22 @@ If our codecs (in and out) have data then write to recorded files.
|
|
|
785
778
|
*/
|
|
786
779
|
void projectrtpchannel::writerecordings( void ) {
|
|
787
780
|
|
|
788
|
-
if(
|
|
781
|
+
if( !this->active ) return;
|
|
782
|
+
|
|
783
|
+
auto self = shared_from_this();
|
|
784
|
+
|
|
785
|
+
chanrecptrlist worklist;
|
|
786
|
+
{
|
|
787
|
+
SpinLockGuard guard( this->recorderslock );
|
|
788
|
+
worklist = this->recorders;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if( 0 == worklist.size() ) return;
|
|
792
|
+
|
|
789
793
|
uint16_t power = 0;
|
|
790
794
|
|
|
791
795
|
/* Decide if we need to calc power as it is expensive */
|
|
792
|
-
for( auto& rec:
|
|
796
|
+
for( auto& rec: worklist ) {
|
|
793
797
|
if( ( !rec->isactive() && 0 != rec->startabovepower ) || 0 != rec->finishbelowpower ) {
|
|
794
798
|
power = this->incodec.power();
|
|
795
799
|
break;
|
|
@@ -797,7 +801,7 @@ void projectrtpchannel::writerecordings( void ) {
|
|
|
797
801
|
}
|
|
798
802
|
|
|
799
803
|
/* Check if we need to trigger the start of any recordings and write */
|
|
800
|
-
for( auto& rec:
|
|
804
|
+
for( auto& rec: worklist ) {
|
|
801
805
|
|
|
802
806
|
if( rec->completed ) continue;
|
|
803
807
|
|
|
@@ -812,11 +816,11 @@ void projectrtpchannel::writerecordings( void ) {
|
|
|
812
816
|
if( !rec->isactive() ) {
|
|
813
817
|
if( 0 == rec->startabovepower ) {
|
|
814
818
|
rec->active();
|
|
815
|
-
postdatabacktojsfromthread(
|
|
819
|
+
postdatabacktojsfromthread( self, "record", rec->file, "recording" );
|
|
816
820
|
} else {
|
|
817
821
|
if( pav > rec->startabovepower ) {
|
|
818
822
|
rec->active();
|
|
819
|
-
postdatabacktojsfromthread(
|
|
823
|
+
postdatabacktojsfromthread( self, "record", rec->file, "recording.abovepower" );
|
|
820
824
|
}
|
|
821
825
|
}
|
|
822
826
|
}
|
|
@@ -826,7 +830,9 @@ void projectrtpchannel::writerecordings( void ) {
|
|
|
826
830
|
}
|
|
827
831
|
}
|
|
828
832
|
|
|
829
|
-
this->
|
|
833
|
+
/* this function is also protected by this->recorderslock - so ensure it is free before calling */
|
|
834
|
+
/* pass in sefl to ensure no gap in destruction/auto ptr destruction */
|
|
835
|
+
this->removeoldrecorders( self );
|
|
830
836
|
}
|
|
831
837
|
|
|
832
838
|
bool projectrtpchannel::dtlsnegotiate( void ) {
|
|
@@ -1148,30 +1154,49 @@ bool projectrtpchannel::mix( projectrtpchannel::pointer other ) {
|
|
|
1148
1154
|
return true;
|
|
1149
1155
|
}
|
|
1150
1156
|
|
|
1151
|
-
|
|
1157
|
+
auto self = shared_from_this();
|
|
1158
|
+
|
|
1159
|
+
{
|
|
1160
|
+
SpinLockGuard guard( this->playerlock );
|
|
1161
|
+
if( nullptr != this->player ) {
|
|
1162
|
+
postdatabacktojsfromthread( self, "play", "end", "channelmixing" );
|
|
1163
|
+
}
|
|
1164
|
+
this->player = nullptr;
|
|
1165
|
+
}
|
|
1166
|
+
{
|
|
1167
|
+
SpinLockGuard guard( other->playerlock );
|
|
1168
|
+
if( nullptr != other->player ) {
|
|
1169
|
+
postdatabacktojsfromthread( other, "play", "end", "channelmixing" );
|
|
1170
|
+
}
|
|
1171
|
+
other->player = nullptr;
|
|
1172
|
+
}
|
|
1152
1173
|
|
|
1153
|
-
|
|
1154
|
-
this->
|
|
1155
|
-
this->mixer->addchannel( shared_from_this() );
|
|
1174
|
+
{
|
|
1175
|
+
SpinLockGuard guard( this->mixerlock );
|
|
1156
1176
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1177
|
+
if( nullptr == this->mixer && nullptr != other->mixer ) {
|
|
1178
|
+
this->mixer = other->mixer;
|
|
1179
|
+
this->mixer->addchannel( self );
|
|
1160
1180
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1181
|
+
} else if ( nullptr != this->mixer && nullptr == other->mixer ) {
|
|
1182
|
+
other->mixer = this->mixer;
|
|
1183
|
+
this->mixer->addchannel( other );
|
|
1164
1184
|
|
|
1165
|
-
this->mixer
|
|
1185
|
+
} else if( nullptr == this->mixer && nullptr == other->mixer ) {
|
|
1186
|
+
this->mixer = projectchannelmux::create( workercontext );
|
|
1187
|
+
other->mixer = this->mixer;
|
|
1166
1188
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1189
|
+
this->mixer->addchannels( self, other );
|
|
1190
|
+
|
|
1191
|
+
this->mixer->go();
|
|
1192
|
+
} else {
|
|
1193
|
+
/* If we get here this and other are already mixing and should be cleaned up first */
|
|
1194
|
+
postdatabacktojsfromthread( self, "mix", "busy" );
|
|
1195
|
+
return false;
|
|
1196
|
+
}
|
|
1172
1197
|
}
|
|
1173
1198
|
|
|
1174
|
-
postdatabacktojsfromthread(
|
|
1199
|
+
postdatabacktojsfromthread( self, "mix", "start" );
|
|
1175
1200
|
postdatabacktojsfromthread( other, "mix", "start" );
|
|
1176
1201
|
|
|
1177
1202
|
return true;
|
|
@@ -1217,6 +1242,12 @@ void projectrtpchannel::dtmf( std::string digits ) {
|
|
|
1217
1242
|
this->queueddigits += digits;
|
|
1218
1243
|
}
|
|
1219
1244
|
|
|
1245
|
+
const char volume = 10;
|
|
1246
|
+
const char endofevent = 0x80;
|
|
1247
|
+
|
|
1248
|
+
const int numevents = 3;
|
|
1249
|
+
const int numendevents = 3;
|
|
1250
|
+
|
|
1220
1251
|
/*
|
|
1221
1252
|
Now send each digit.
|
|
1222
1253
|
*/
|
|
@@ -1231,7 +1262,6 @@ void projectrtpchannel::senddtmf( void ) {
|
|
|
1231
1262
|
SpinLockGuard guard( this->queuddigitslock );
|
|
1232
1263
|
if( this->queueddigits.size() > 0 ) {
|
|
1233
1264
|
tosend = this->queueddigits[ 0 ];
|
|
1234
|
-
this->queueddigits.erase( this->queueddigits.begin() );
|
|
1235
1265
|
}
|
|
1236
1266
|
}
|
|
1237
1267
|
|
|
@@ -1265,77 +1295,42 @@ void projectrtpchannel::senddtmf( void ) {
|
|
|
1265
1295
|
return;
|
|
1266
1296
|
}
|
|
1267
1297
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
dst->
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
dst = this->gettempoutbuf();
|
|
1305
|
-
dst->setpayloadtype( this->rfc2833pt );
|
|
1306
|
-
dst->setmarker();
|
|
1307
|
-
dst->setpayloadlength( 4 );
|
|
1308
|
-
pl = dst->getpayload();
|
|
1309
|
-
pl[ 0 ] = tosend;
|
|
1310
|
-
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1311
|
-
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1312
|
-
*tmp = htons( 640 );
|
|
1313
|
-
|
|
1314
|
-
this->writepacket( dst );
|
|
1315
|
-
|
|
1316
|
-
dst = this->gettempoutbuf();
|
|
1317
|
-
dst->setpayloadtype( this->rfc2833pt );
|
|
1318
|
-
dst->setpayloadlength( 4 );
|
|
1319
|
-
pl = dst->getpayload();
|
|
1320
|
-
pl[ 0 ] = tosend;
|
|
1321
|
-
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1322
|
-
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1323
|
-
*tmp = htons( 640 );
|
|
1324
|
-
|
|
1325
|
-
this->writepacket( dst );
|
|
1326
|
-
|
|
1327
|
-
dst = this->gettempoutbuf();
|
|
1328
|
-
dst->setpayloadtype( this->rfc2833pt );
|
|
1329
|
-
dst->setpayloadlength( 4 );
|
|
1330
|
-
pl = dst->getpayload();
|
|
1331
|
-
pl[ 0 ] = tosend;
|
|
1332
|
-
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1333
|
-
tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1334
|
-
*tmp = htons( 640 );
|
|
1335
|
-
|
|
1336
|
-
this->writepacket( dst );
|
|
1337
|
-
|
|
1338
|
-
this->lastdtmfsn = this->snout;
|
|
1298
|
+
if( this->dtmfsendcount <= numevents ) {
|
|
1299
|
+
rtppacket *dst = this->gettempoutbuf();
|
|
1300
|
+
dst->setpayloadtype( this->rfc2833pt );
|
|
1301
|
+
dst->setpayloadlength( 4 );
|
|
1302
|
+
uint8_t *pl = dst->getpayload();
|
|
1303
|
+
pl[ 0 ] = tosend;
|
|
1304
|
+
pl[ 1 ] = volume; /* end of event & reserved & volume */
|
|
1305
|
+
uint16_t *tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1306
|
+
*tmp = htons( ( this->dtmfsendcount + 1 ) * 160 );
|
|
1307
|
+
|
|
1308
|
+
this->writepacket( dst );
|
|
1309
|
+
|
|
1310
|
+
} else {
|
|
1311
|
+
/* end packet */
|
|
1312
|
+
rtppacket *dst = this->gettempoutbuf();
|
|
1313
|
+
dst->setpayloadtype( this->rfc2833pt );
|
|
1314
|
+
dst->setmarker();
|
|
1315
|
+
dst->setpayloadlength( 4 );
|
|
1316
|
+
uint8_t *pl = dst->getpayload();
|
|
1317
|
+
pl[ 0 ] = tosend;
|
|
1318
|
+
pl[ 1 ] = endofevent | volume; /* end of event & reserved & volume */
|
|
1319
|
+
uint16_t *tmp = ( uint16_t * ) &pl[ 2 ]; /* event duration */
|
|
1320
|
+
*tmp = htons( ( numevents + 2 ) * 160 );
|
|
1321
|
+
|
|
1322
|
+
this->writepacket( dst );
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
if( this->dtmfsendcount >= ( numevents + numendevents ) ) {
|
|
1326
|
+
SpinLockGuard guard( this->queuddigitslock );
|
|
1327
|
+
this->queueddigits.erase( this->queueddigits.begin() );
|
|
1328
|
+
this->lastdtmfsn = this->snout;
|
|
1329
|
+
this->dtmfsendcount = 0;
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
this->dtmfsendcount++;
|
|
1339
1334
|
}
|
|
1340
1335
|
|
|
1341
1336
|
/*
|
package/src/projectrtpchannel.h
CHANGED
|
@@ -196,8 +196,7 @@ private:
|
|
|
196
196
|
void incrtsout( void );
|
|
197
197
|
|
|
198
198
|
bool checkidlerecv( void );
|
|
199
|
-
void
|
|
200
|
-
void removeoldrecorders( void );
|
|
199
|
+
void removeoldrecorders( pointer );
|
|
201
200
|
void writerecordings( void );
|
|
202
201
|
|
|
203
202
|
bool checkfordtmf( rtppacket *src );
|
|
@@ -234,15 +233,14 @@ private:
|
|
|
234
233
|
codecx incodec;
|
|
235
234
|
|
|
236
235
|
soundsoup::pointer player;
|
|
237
|
-
soundsoup::pointer
|
|
238
|
-
std::atomic_bool
|
|
236
|
+
soundsoup::pointer playerstash;
|
|
237
|
+
std::atomic_bool playerlock;
|
|
239
238
|
|
|
240
239
|
std::atomic_bool doecho;
|
|
241
240
|
boost::asio::steady_timer tick;
|
|
242
241
|
std::chrono::high_resolution_clock::time_point nexttick;
|
|
243
242
|
|
|
244
|
-
|
|
245
|
-
std::atomic_bool newrecorderslock;
|
|
243
|
+
std::atomic_bool recorderslock;
|
|
246
244
|
chanrecptrlist recorders;
|
|
247
245
|
|
|
248
246
|
/* DTLS Session */
|
|
@@ -258,6 +256,7 @@ private:
|
|
|
258
256
|
/* outbound DTMF */
|
|
259
257
|
std::string queueddigits;
|
|
260
258
|
std::atomic_bool queuddigitslock;
|
|
259
|
+
uint8_t dtmfsendcount;
|
|
261
260
|
uint16_t lastdtmfsn;
|
|
262
261
|
|
|
263
262
|
boost::posix_time::ptime tickstarttime;
|