@babblevoice/projectrtp 2.4.11 → 2.4.15
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/lib/server.js +7 -2
- package/package.json +1 -1
- package/src/projectrtpchannel.cpp +22 -11
- package/src/projectrtpcodecx.cpp +106 -53
- package/test/codectests.js +10 -0
- package/test/interface/projectrtpdtmf.js +9 -8
- package/test/interface/projectrtpfullserver.js +4 -4
- package/test/interface/projectrtpmix.js +95 -0
package/lib/server.js
CHANGED
|
@@ -244,6 +244,11 @@ class channel {
|
|
|
244
244
|
if ( receivedmsg.id === chnl.id ) chnl._on( receivedmsg )
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
/* correct the instance id - i.e. in a proxy enviroment (docker swarm) instance may differ */
|
|
248
|
+
if( receivedmsg && receivedmsg.status && receivedmsg.status.instance ) {
|
|
249
|
+
newchannel.connection.instance = receivedmsg.status.instance
|
|
250
|
+
}
|
|
251
|
+
|
|
247
252
|
if ( openresolve ) openresolve( newchannel )
|
|
248
253
|
} )
|
|
249
254
|
} )
|
|
@@ -272,7 +277,7 @@ class channel {
|
|
|
272
277
|
|
|
273
278
|
options.channel = "open"
|
|
274
279
|
|
|
275
|
-
const resolvepromise = new Promise( (
|
|
280
|
+
const resolvepromise = new Promise( ( resolve ) => {
|
|
276
281
|
|
|
277
282
|
const newchannel = new channel()
|
|
278
283
|
if( cb ) newchannel.em.on( "all", cb )
|
|
@@ -280,7 +285,7 @@ class channel {
|
|
|
280
285
|
newchannel.connection = this.connection
|
|
281
286
|
newchannel.channels = this.channels
|
|
282
287
|
newchannel.channels.push( newchannel )
|
|
283
|
-
newchannel.openresolve =
|
|
288
|
+
newchannel.openresolve = resolve
|
|
284
289
|
newchannel._write( options )
|
|
285
290
|
} )
|
|
286
291
|
|
package/package.json
CHANGED
|
@@ -121,11 +121,13 @@ projectrtpchannel::projectrtpchannel( unsigned short port ):
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
void projectrtpchannel::requestclose( std::string reason ) {
|
|
124
|
-
if( !this->_requestclose.exchange( true, std::memory_order_acquire ) ) {
|
|
125
|
-
this->closereason = reason;
|
|
126
|
-
}
|
|
127
124
|
|
|
128
|
-
this->
|
|
125
|
+
this->closereason = reason;
|
|
126
|
+
if( this->mixing ) {
|
|
127
|
+
this->removemixer = true;
|
|
128
|
+
} else {
|
|
129
|
+
this->_requestclose.exchange( true, std::memory_order_acquire );
|
|
130
|
+
}
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
void projectrtpchannel::remote( std::string address,
|
|
@@ -390,6 +392,11 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
390
392
|
if( error == boost::asio::error::operation_aborted ) return;
|
|
391
393
|
if( !this->active ) return;
|
|
392
394
|
|
|
395
|
+
if( this->_requestclose ) {
|
|
396
|
+
this->doclose();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
393
400
|
if( this->dtlsnegotiate() ) {
|
|
394
401
|
this->setnexttick();
|
|
395
402
|
return;
|
|
@@ -400,11 +407,6 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
400
407
|
return;
|
|
401
408
|
};
|
|
402
409
|
|
|
403
|
-
if( this->_requestclose ) {
|
|
404
|
-
this->doclose();
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
410
|
this->startticktimer();
|
|
409
411
|
|
|
410
412
|
this->incrtsout();
|
|
@@ -1029,7 +1031,7 @@ bool projectrtpchannel::mix( projectrtpchannel::pointer other ) {
|
|
|
1029
1031
|
} else if ( nullptr != this->mixer && nullptr == other->mixer ) {
|
|
1030
1032
|
other->mixer = this->mixer;
|
|
1031
1033
|
this->mixer->addchannel( other );
|
|
1032
|
-
postdatabacktojsfromthread(
|
|
1034
|
+
postdatabacktojsfromthread( other, "mix", "start" );
|
|
1033
1035
|
} else if( nullptr == this->mixer && nullptr == other->mixer ) {
|
|
1034
1036
|
this->mixer = projectchannelmux::create( workercontext );
|
|
1035
1037
|
other->mixer = this->mixer;
|
|
@@ -1039,6 +1041,7 @@ bool projectrtpchannel::mix( projectrtpchannel::pointer other ) {
|
|
|
1039
1041
|
postdatabacktojsfromthread( other, "mix", "start" );
|
|
1040
1042
|
} else {
|
|
1041
1043
|
/* If we get here this and other are already mixing and should be cleaned up first */
|
|
1044
|
+
postdatabacktojsfromthread( shared_from_this(), "mix", "busy" );
|
|
1042
1045
|
RELEASESPINLOCK( this->mixerlock );
|
|
1043
1046
|
return false;
|
|
1044
1047
|
}
|
|
@@ -1059,7 +1062,11 @@ Add the other to a mixer - both channels have access to the same mixer.
|
|
|
1059
1062
|
n way relationship. Adds to queue for when our main thread calls into us.
|
|
1060
1063
|
*/
|
|
1061
1064
|
bool projectrtpchannel::unmix( void ) {
|
|
1062
|
-
|
|
1065
|
+
|
|
1066
|
+
AQUIRESPINLOCK( this->mixerlock );
|
|
1067
|
+
if( nullptr != this->mixer ) this->removemixer = true;
|
|
1068
|
+
RELEASESPINLOCK( this->mixerlock );
|
|
1069
|
+
|
|
1063
1070
|
return true;
|
|
1064
1071
|
}
|
|
1065
1072
|
|
|
@@ -1075,6 +1082,10 @@ void projectrtpchannel::dounmix( void ) {
|
|
|
1075
1082
|
RELEASESPINLOCK( this->mixerlock );
|
|
1076
1083
|
|
|
1077
1084
|
postdatabacktojsfromthread( shared_from_this(), "mix", "finished" );
|
|
1085
|
+
|
|
1086
|
+
if( this->closereason.length() > 0 ) {
|
|
1087
|
+
this->_requestclose.exchange( true, std::memory_order_acquire );
|
|
1088
|
+
}
|
|
1078
1089
|
}
|
|
1079
1090
|
|
|
1080
1091
|
/*
|
package/src/projectrtpcodecx.cpp
CHANGED
|
@@ -559,7 +559,7 @@ rawsound& codecx::getref( int pt ) {
|
|
|
559
559
|
}
|
|
560
560
|
case PCMAPAYLOADTYPE: {
|
|
561
561
|
if( this->pcmuref.size() > 0 ) {
|
|
562
|
-
this->
|
|
562
|
+
this->ulaw2alaw();
|
|
563
563
|
} else {
|
|
564
564
|
this->requirenarrowband();
|
|
565
565
|
this->l16topcma();
|
|
@@ -568,7 +568,7 @@ rawsound& codecx::getref( int pt ) {
|
|
|
568
568
|
}
|
|
569
569
|
case PCMUPAYLOADTYPE: {
|
|
570
570
|
if( this->pcmaref.size() > 0 ) {
|
|
571
|
-
this->
|
|
571
|
+
this->alaw2ulaw();
|
|
572
572
|
} else {
|
|
573
573
|
this->requirenarrowband();
|
|
574
574
|
this->l16topcmu();
|
|
@@ -697,8 +697,7 @@ codecx& operator << ( codecx& c, const char& a )
|
|
|
697
697
|
|
|
698
698
|
|
|
699
699
|
|
|
700
|
-
void codectests( void )
|
|
701
|
-
{
|
|
700
|
+
void codectests( void ) {
|
|
702
701
|
/* init transcoding stuff */
|
|
703
702
|
gen711convertdata();
|
|
704
703
|
|
|
@@ -715,8 +714,7 @@ void codectests( void )
|
|
|
715
714
|
|
|
716
715
|
|
|
717
716
|
g722_decode_state_t *g722decoder = g722_decode_init( NULL, 64000, G722_PACKED );
|
|
718
|
-
if( nullptr == g722decoder )
|
|
719
|
-
{
|
|
717
|
+
if( nullptr == g722decoder ) {
|
|
720
718
|
std::cerr << "Failed to init G722 decoder" << std::endl;
|
|
721
719
|
}
|
|
722
720
|
|
|
@@ -727,15 +725,13 @@ void codectests( void )
|
|
|
727
725
|
g722samplepk,
|
|
728
726
|
160 );
|
|
729
727
|
std::cout << "g722_decode returned " << l1616klength << " for an in packet of 160 bytes" << std::endl;
|
|
730
|
-
if( 320 != l1616klength )
|
|
731
|
-
{
|
|
728
|
+
if( 320 != l1616klength ) {
|
|
732
729
|
std::cerr << "ERROR - decoded length is not 320 bytes" << std::endl;
|
|
733
730
|
}
|
|
734
731
|
g722_decode_free( g722decoder );
|
|
735
732
|
|
|
736
733
|
std::cout << "L16 OUT (g722_decode) =" << std::endl;
|
|
737
|
-
for( int i = 0; i < 160; i ++ )
|
|
738
|
-
{
|
|
734
|
+
for( int i = 0; i < 160; i ++ ) {
|
|
739
735
|
std::cout << unsigned( outbuf[ i ] ) << " ";
|
|
740
736
|
}
|
|
741
737
|
std::cout << std::endl;
|
|
@@ -744,66 +740,123 @@ void codectests( void )
|
|
|
744
740
|
/*
|
|
745
741
|
Move onto test our interface.
|
|
746
742
|
*/
|
|
747
|
-
|
|
748
|
-
|
|
743
|
+
{
|
|
744
|
+
rawsound r( g722samplepk, sizeof( g722samplepk ), G722PAYLOADTYPE, 16000 );
|
|
745
|
+
std::cout << "G722 raw packet size " << r.size() << " with a format of " << r.getformat() << " and sample rate " << r.getsamplerate() << std::endl;
|
|
749
746
|
|
|
750
|
-
|
|
747
|
+
codecx ourcodec;
|
|
751
748
|
|
|
752
|
-
|
|
753
|
-
|
|
749
|
+
ourcodec << codecx::next;
|
|
750
|
+
ourcodec << r;
|
|
754
751
|
|
|
755
|
-
|
|
756
|
-
outpk.setpayloadtype( PCMAPAYLOADTYPE );
|
|
757
|
-
outpk.setpayloadlength( 160 );
|
|
758
|
-
outpk.setsequencenumber( 0 );
|
|
759
|
-
outpk.settimestamp( 0 );
|
|
760
|
-
outpk << ourcodec;
|
|
752
|
+
|
|
761
753
|
|
|
762
|
-
|
|
763
|
-
|
|
754
|
+
rtppacket outpk;
|
|
755
|
+
outpk.setpayloadtype( PCMAPAYLOADTYPE );
|
|
756
|
+
outpk.setpayloadlength( 160 );
|
|
757
|
+
outpk.setsequencenumber( 0 );
|
|
758
|
+
outpk.settimestamp( 0 );
|
|
759
|
+
outpk << ourcodec;
|
|
764
760
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
761
|
+
std::cout << "PCMA OUT =" << std::endl;
|
|
762
|
+
uint8_t *pl = outpk.getpayload();
|
|
763
|
+
|
|
764
|
+
for( int i = 0; i < 160; i ++ ) {
|
|
765
|
+
std::cout << unsigned( pl[ i ] ) << " ";
|
|
766
|
+
}
|
|
767
|
+
std::cout << std::endl;
|
|
768
|
+
|
|
769
|
+
if( 213 != pl[ 0 ] ) std::cout << "ERROR ERROR First byte should be 213???" << std::endl;
|
|
770
|
+
if( 85 != pl[ 9 ] ) std::cout << "ERROR ERROR 9th byte should be 85???" << std::endl;
|
|
771
|
+
|
|
772
|
+
rawsound &ref8k = ourcodec.getref( L168KPAYLOADTYPE );
|
|
773
|
+
|
|
774
|
+
if( ref8k.isdirty() ) std::cout << "ERROR our 8k out ref should not be dirty" << std::endl;
|
|
775
|
+
|
|
776
|
+
/* Repeat as this will use a different bit of code getting cached bit */
|
|
777
|
+
ref8k = ourcodec.getref( L168KPAYLOADTYPE );
|
|
778
|
+
if( ref8k.isdirty() ) std::cout << "ERROR our 8k out ref should not be dirty" << std::endl;
|
|
779
|
+
|
|
780
|
+
std::cout << "8k is dirty: " << std::boolalpha << ref8k.isdirty() << std::endl;
|
|
781
|
+
std::cout << "8k size: " << ref8k.size() << std::endl;
|
|
782
|
+
std::cout << "8k bytes per sample (should be 2): " << ref8k.getbytespersample() << std::endl;
|
|
770
783
|
|
|
771
|
-
|
|
772
|
-
|
|
784
|
+
/* 2 bytes per sample */
|
|
785
|
+
int16_t *pl16 = ( int16_t * ) ref8k.c_str();
|
|
786
|
+
for( size_t i = 0; i < ref8k.size(); i ++ ) {
|
|
787
|
+
std::cout << static_cast<int16_t>( pl16[ i ] ) << " ";
|
|
788
|
+
}
|
|
789
|
+
std::cout << std::endl;
|
|
773
790
|
|
|
774
|
-
rawsound &ref8k = ourcodec.getref( L168KPAYLOADTYPE );
|
|
775
791
|
|
|
776
|
-
|
|
792
|
+
rawsound &ref16k = ourcodec.getref( L1616KPAYLOADTYPE );
|
|
793
|
+
if( ref16k.isdirty() ) std::cout << "ERROR our 16k out ref should not be dirty" << std::endl;
|
|
794
|
+
std::cout << "16k is dirty: " << std::boolalpha << ref16k.isdirty() << std::endl;
|
|
795
|
+
std::cout << "16k size: " << ref16k.size() << std::endl;
|
|
796
|
+
std::cout << "16k bytes per sample (should be 2): " << ref16k.getbytespersample() << std::endl;
|
|
777
797
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
798
|
+
pl16 = ( int16_t * ) ref16k.c_str();
|
|
799
|
+
for( size_t i = 0; i < ref16k.size(); i ++ ) {
|
|
800
|
+
std::cout << static_cast<int16_t>( pl16[ i ] ) << " ";
|
|
801
|
+
}
|
|
802
|
+
std::cout << std::endl;
|
|
803
|
+
}
|
|
781
804
|
|
|
782
|
-
std::cout << "8k is dirty: " << std::boolalpha << ref8k.isdirty() << std::endl;
|
|
783
|
-
std::cout << "8k size: " << ref8k.size() << std::endl;
|
|
784
|
-
std::cout << "8k bytes per sample (should be 2): " << ref8k.getbytespersample() << std::endl;
|
|
785
805
|
|
|
786
|
-
/* 2 bytes per sample */
|
|
787
|
-
int16_t *pl16 = ( int16_t * ) ref8k.c_str();
|
|
788
|
-
for( size_t i = 0; i < ref8k.size(); i ++ )
|
|
789
806
|
{
|
|
790
|
-
|
|
807
|
+
/* problem with converting pcmu to pcma */
|
|
808
|
+
/* use the same data, but pretend it is PCMU */
|
|
809
|
+
rawsound r( g722samplepk, sizeof( g722samplepk ), PCMUPAYLOADTYPE, 8000 );
|
|
810
|
+
|
|
811
|
+
codecx ourcodec;
|
|
812
|
+
|
|
813
|
+
ourcodec << codecx::next;
|
|
814
|
+
ourcodec << r;
|
|
815
|
+
|
|
816
|
+
rtppacket outpk;
|
|
817
|
+
outpk.setpayloadtype( PCMAPAYLOADTYPE );
|
|
818
|
+
outpk.setpayloadlength( 160 );
|
|
819
|
+
outpk.setsequencenumber( 0 );
|
|
820
|
+
outpk.settimestamp( 0 );
|
|
821
|
+
outpk << ourcodec;
|
|
822
|
+
|
|
823
|
+
std::cout << "PCMA OUT (it should not be all zeros) = " << std::endl;
|
|
824
|
+
|
|
825
|
+
uint8_t *pl = outpk.getpayload();
|
|
826
|
+
|
|
827
|
+
for( int i = 0; i < 160; i ++ ) {
|
|
828
|
+
std::cout << unsigned( pl[ i ] ) << " ";
|
|
829
|
+
}
|
|
830
|
+
std::cout << std::endl;
|
|
791
831
|
}
|
|
792
|
-
std::cout << std::endl;
|
|
793
832
|
|
|
833
|
+
{
|
|
834
|
+
/* problem with converting pcmu to pcma */
|
|
835
|
+
/* use the same data, but pretend it is PCMU */
|
|
836
|
+
rawsound r( g722samplepk, sizeof( g722samplepk ), PCMAPAYLOADTYPE, 8000 );
|
|
794
837
|
|
|
795
|
-
|
|
796
|
-
if( ref16k.isdirty() ) std::cout << "ERROR our 16k out ref should not be dirty" << std::endl;
|
|
797
|
-
std::cout << "16k is dirty: " << std::boolalpha << ref16k.isdirty() << std::endl;
|
|
798
|
-
std::cout << "16k size: " << ref16k.size() << std::endl;
|
|
799
|
-
std::cout << "16k bytes per sample (should be 2): " << ref16k.getbytespersample() << std::endl;
|
|
838
|
+
codecx ourcodec;
|
|
800
839
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
840
|
+
ourcodec << codecx::next;
|
|
841
|
+
ourcodec << r;
|
|
842
|
+
|
|
843
|
+
rtppacket outpk;
|
|
844
|
+
outpk.setpayloadtype( PCMUPAYLOADTYPE );
|
|
845
|
+
outpk.setpayloadlength( 160 );
|
|
846
|
+
outpk.setsequencenumber( 0 );
|
|
847
|
+
outpk.settimestamp( 0 );
|
|
848
|
+
outpk << ourcodec;
|
|
849
|
+
|
|
850
|
+
std::cout << "PCMU OUT (it should not be all zeros) = " << std::endl;
|
|
851
|
+
|
|
852
|
+
uint8_t *pl = outpk.getpayload();
|
|
853
|
+
|
|
854
|
+
for( int i = 0; i < 160; i ++ ) {
|
|
855
|
+
std::cout << unsigned( pl[ i ] ) << " ";
|
|
856
|
+
}
|
|
857
|
+
std::cout << std::endl;
|
|
805
858
|
}
|
|
806
|
-
|
|
859
|
+
|
|
807
860
|
}
|
|
808
861
|
|
|
809
862
|
#ifdef NODE_MODULE
|
|
@@ -620,6 +620,7 @@ describe( "dtmf", function() {
|
|
|
620
620
|
expect( receivedmessages[ 1 ].action ).to.equal( "telephone-event" )
|
|
621
621
|
expect( receivedmessages[ 2 ].action ).to.equal( "telephone-event" )
|
|
622
622
|
expect( receivedmessages[ 3 ].action ).to.equal( "mix" )
|
|
623
|
+
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
|
|
623
624
|
expect( receivedmessages[ 4 ].action ).to.equal( "close" )
|
|
624
625
|
|
|
625
626
|
expect( receivedmessages[ 0 ].event ).to.equal( "start" )
|
|
@@ -807,17 +808,17 @@ describe( "dtmf", function() {
|
|
|
807
808
|
expect( dtmfcpkcount ).to.be.within( 4, 8 )
|
|
808
809
|
|
|
809
810
|
expect( receveiedmessages[ 0 ].action ).to.equal( "mix" )
|
|
810
|
-
expect( receveiedmessages[ 1 ].action ).to.equal( "mix" )
|
|
811
|
+
//expect( receveiedmessages[ 1 ].action ).to.equal( "mix" )
|
|
812
|
+
expect( receveiedmessages[ 1 ].action ).to.equal( "telephone-event" )
|
|
811
813
|
expect( receveiedmessages[ 2 ].action ).to.equal( "telephone-event" )
|
|
812
|
-
expect( receveiedmessages[ 3 ].action ).to.equal( "
|
|
813
|
-
expect( receveiedmessages[ 4 ].action ).to.equal( "
|
|
814
|
-
expect( receveiedmessages[ 5 ].action ).to.equal( "close" )
|
|
814
|
+
expect( receveiedmessages[ 3 ].action ).to.equal( "mix" )
|
|
815
|
+
expect( receveiedmessages[ 4 ].action ).to.equal( "close" )
|
|
815
816
|
|
|
817
|
+
//expect( receveiedmessages[ 0 ].event ).to.equal( "start" )
|
|
816
818
|
expect( receveiedmessages[ 0 ].event ).to.equal( "start" )
|
|
817
|
-
expect( receveiedmessages[ 1 ].event ).to.equal( "
|
|
818
|
-
expect( receveiedmessages[ 2 ].event ).to.equal( "
|
|
819
|
-
expect( receveiedmessages[ 3 ].event ).to.equal( "
|
|
820
|
-
expect( receveiedmessages[ 4 ].event ).to.equal( "finished" )
|
|
819
|
+
expect( receveiedmessages[ 1 ].event ).to.equal( "4" )
|
|
820
|
+
expect( receveiedmessages[ 2 ].event ).to.equal( "5" )
|
|
821
|
+
expect( receveiedmessages[ 3 ].event ).to.equal( "finished" )
|
|
821
822
|
|
|
822
823
|
} )
|
|
823
824
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const prtp = require( "../../index" )
|
|
3
3
|
const node = require( "../../lib/node" )
|
|
4
4
|
const expect = require( "chai" ).expect
|
|
5
|
+
const fs = require( "node:fs" )
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Test file to run tests acting as a remote note. Starts a babble-rtp node in the background
|
|
@@ -25,7 +26,7 @@ describe( "server connect interface", () => {
|
|
|
25
26
|
|
|
26
27
|
it( "server connect and open channel", async function () {
|
|
27
28
|
this.timeout( 6000 )
|
|
28
|
-
this.slow(
|
|
29
|
+
this.slow( 30000 )
|
|
29
30
|
|
|
30
31
|
const totalotherchannelcount = 100
|
|
31
32
|
let chanclosecount = 0
|
|
@@ -37,6 +38,8 @@ describe( "server connect interface", () => {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
// A very short wav file
|
|
41
|
+
await fs.promises.rm( "/tmp/serverconnecttestwav.wav", { force: true } )
|
|
42
|
+
await fs.promises.rm( "/tmp/otherserverconnecttestwav.wav", { force: true } )
|
|
40
43
|
prtp.projectrtp.tone.generate( "350+440*0.5:100", "/tmp/serverconnecttestwav.wav" )
|
|
41
44
|
prtp.projectrtp.tone.generate( "350+440*0.5:100", "/tmp/otherserverconnecttestwav.wav" )
|
|
42
45
|
|
|
@@ -48,16 +51,13 @@ describe( "server connect interface", () => {
|
|
|
48
51
|
for( let i = 0; 3 > i; i++ ) {
|
|
49
52
|
let done
|
|
50
53
|
const finished = new Promise( resolve => done = resolve )
|
|
51
|
-
|
|
52
54
|
const receivedmessages = []
|
|
53
55
|
const chan = await prtp.projectrtp.openchannel( ( e ) => {
|
|
54
56
|
receivedmessages.push( e )
|
|
55
57
|
if( "play" == e.action && "end" == e.event ) chan.close()
|
|
56
58
|
if( "close" == e.action ) done()
|
|
57
59
|
} )
|
|
58
|
-
|
|
59
60
|
chan.play( { "interupt":true, "files": [ { "wav": "/tmp/serverconnecttestwav.wav" }, { "wav": "/tmp/otherserverconnecttestwav.wav" } ] } )
|
|
60
|
-
|
|
61
61
|
await finished
|
|
62
62
|
|
|
63
63
|
//console.log(receivedmessages)
|
|
@@ -172,6 +172,101 @@ describe( "channel mix", function() {
|
|
|
172
172
|
|
|
173
173
|
} )
|
|
174
174
|
|
|
175
|
+
|
|
176
|
+
it( "mix 2 channels then unmix then mix again", async function() {
|
|
177
|
+
|
|
178
|
+
this.timeout( 6000 )
|
|
179
|
+
this.slow( 5000 )
|
|
180
|
+
|
|
181
|
+
const endpointa = dgram.createSocket( "udp4" )
|
|
182
|
+
const endpointb = dgram.createSocket( "udp4" )
|
|
183
|
+
|
|
184
|
+
const endpointapkcount = [ 0, 0, 0, 0 ]
|
|
185
|
+
const endpointbpkcount = [ 0, 0, 0, 0 ]
|
|
186
|
+
|
|
187
|
+
endpointa.on( "message", function( msg ) {
|
|
188
|
+
endpointapkcount[ 0x7f & msg[ 50 ] ]++
|
|
189
|
+
expect( msg.length ).to.equal( 172 )
|
|
190
|
+
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
|
|
191
|
+
} )
|
|
192
|
+
|
|
193
|
+
endpointb.on( "message", function( msg ) {
|
|
194
|
+
endpointbpkcount[ 0x7f & msg[ 50 ] ]++
|
|
195
|
+
expect( msg.length ).to.equal( 172 )
|
|
196
|
+
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
|
|
197
|
+
} )
|
|
198
|
+
|
|
199
|
+
endpointa.bind()
|
|
200
|
+
await new Promise( ( resolve ) => { endpointa.on( "listening", function() { resolve() } ) } )
|
|
201
|
+
|
|
202
|
+
endpointb.bind()
|
|
203
|
+
await new Promise( ( resolve ) => { endpointb.on( "listening", function() { resolve() } ) } )
|
|
204
|
+
|
|
205
|
+
let promisearesolve, promisebresolve
|
|
206
|
+
const promisea = new Promise( r => promisearesolve = r )
|
|
207
|
+
const promiseb = new Promise( r => promisebresolve = r )
|
|
208
|
+
|
|
209
|
+
const channela = await projectrtp.openchannel( { "remote": { "address": "localhost", "port": endpointa.address().port, "codec": 0 } }, function( d ) {
|
|
210
|
+
if( "close" === d.action ) {
|
|
211
|
+
promisearesolve()
|
|
212
|
+
}
|
|
213
|
+
} )
|
|
214
|
+
|
|
215
|
+
const channelb = await projectrtp.openchannel( { "remote": { "address": "localhost", "port": endpointb.address().port, "codec": 0 } }, function( d ) {
|
|
216
|
+
if( "close" === d.action ) {
|
|
217
|
+
promisebresolve()
|
|
218
|
+
}
|
|
219
|
+
} )
|
|
220
|
+
|
|
221
|
+
/* mix */
|
|
222
|
+
expect( channela.mix( channelb ) ).to.be.true
|
|
223
|
+
/* Now, when we send UDP on endpointb it passes through our mix then arrives at endpointa */
|
|
224
|
+
let dataa = Buffer.alloc( 172 - 12 ).fill( 0 )
|
|
225
|
+
let datab = Buffer.alloc( 172 - 12 ).fill( 1 )
|
|
226
|
+
|
|
227
|
+
for( let i = 0; 50 > i; i ++ ) {
|
|
228
|
+
sendpk( i, i, channela.local.port, endpointa, dataa )
|
|
229
|
+
sendpk( i, i, channelb.local.port, endpointb, datab )
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* 1S for 50 packets to get through, 0.5 seconds to allow all through jitter buffers */
|
|
233
|
+
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 1700 ) } )
|
|
234
|
+
|
|
235
|
+
channela.direction( { send: true, recv: false } )
|
|
236
|
+
expect( channelb.unmix( channela ) ).to.be.true
|
|
237
|
+
channelb.play( { "loop": true, "files": [
|
|
238
|
+
{ "wav": "/tmp/ukringing.wav" } ] } )
|
|
239
|
+
|
|
240
|
+
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 200 ) } )
|
|
241
|
+
|
|
242
|
+
channela.direction( { send: true, recv: true } )
|
|
243
|
+
expect( channelb.mix( channela ) ).to.be.true
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
dataa = Buffer.alloc( 172 - 12 ).fill( 2 )
|
|
247
|
+
datab = Buffer.alloc( 172 - 12 ).fill( 3 )
|
|
248
|
+
for( let i = 0; 50 > i; i ++ ) {
|
|
249
|
+
sendpk( i, i, channela.local.port, endpointa, dataa )
|
|
250
|
+
sendpk( i, i, channelb.local.port, endpointb, datab )
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 1700 ) } )
|
|
254
|
+
|
|
255
|
+
channelb.close()
|
|
256
|
+
channela.close()
|
|
257
|
+
endpointa.close()
|
|
258
|
+
endpointb.close()
|
|
259
|
+
|
|
260
|
+
/* have we cleaned up? */
|
|
261
|
+
await Promise.all( [ promisea, promiseb ] )
|
|
262
|
+
|
|
263
|
+
expect( endpointapkcount[ 1 ] ).to.be.within( 49, 51 )
|
|
264
|
+
expect( endpointapkcount[ 3 ] ).to.be.within( 49, 51 )
|
|
265
|
+
expect( endpointbpkcount[ 0 ] ).to.be.within( 49, 51 )
|
|
266
|
+
expect( endpointbpkcount[ 2 ] ).to.be.within( 49, 51 )
|
|
267
|
+
|
|
268
|
+
} )
|
|
269
|
+
|
|
175
270
|
it( "mix 2 channels then close b", async function() {
|
|
176
271
|
|
|
177
272
|
this.timeout( 3000 )
|