@babblevoice/projectrtp 2.5.31 → 2.5.34
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/Dockerfile +2 -2
- package/binding.gyp +45 -0
- package/index.js +1 -1
- package/lib/server.js +11 -1
- package/package.json +11 -10
- package/src/boostexception.cpp +24 -0
- package/src/globals.h +14 -3
- package/src/projectrtpchannel.cpp +88 -85
- package/src/projectrtpchannelmux.cpp +59 -41
- package/src/projectrtpnodemain.cpp +24 -28
- package/stress/index.js +15 -0
- package/test/interface/rtpproxyserver.js +0 -1
- package/src/binding.gyp +0 -40
package/Dockerfile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
# docker build . -t <your username>/projectrtp
|
|
3
3
|
# I have tied this to version alpine 3.16 as 3.17 has an exception symbol dynamic linking issue.
|
|
4
|
-
FROM alpine:3.
|
|
4
|
+
FROM alpine:3.20 AS builder
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
WORKDIR /usr/src/
|
|
@@ -20,7 +20,7 @@ COPY . .
|
|
|
20
20
|
RUN npm ci --no-optional --production;\
|
|
21
21
|
rm -fr src/build/Release/obj.target
|
|
22
22
|
|
|
23
|
-
FROM alpine:3.
|
|
23
|
+
FROM alpine:3.20 AS app
|
|
24
24
|
|
|
25
25
|
RUN apk add --no-cache \
|
|
26
26
|
spandsp tiff gnutls libsrtp libc6-compat openssl ca-certificates nodejs npm
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "projectrtp",
|
|
5
|
+
"defines": [ "NODE_MODULE", "BOOST_NO_EXCEPTIONS", "BOOST_EXCEPTION_DISABLE", "NAPI_DISABLE_CPP_EXCEPTIONS" ],
|
|
6
|
+
"cflags_cc!": [ "-fno-rtti" ],
|
|
7
|
+
"cflags_cc": [
|
|
8
|
+
"-O3",
|
|
9
|
+
"-g",
|
|
10
|
+
"-Wall",
|
|
11
|
+
"-fstack-protector-strong",
|
|
12
|
+
"-std=c++20",
|
|
13
|
+
"-Weffc++" ],
|
|
14
|
+
"ldflags": [
|
|
15
|
+
"-Wl,-z,relro",
|
|
16
|
+
"-Wl,-z,now",
|
|
17
|
+
"-Wl,--export-dynamic" ],
|
|
18
|
+
"libraries": [
|
|
19
|
+
"-lrt",
|
|
20
|
+
"-lspandsp",
|
|
21
|
+
"-lilbc",
|
|
22
|
+
"-lgnutls",
|
|
23
|
+
"-lsrtp2" ],
|
|
24
|
+
"sources": [
|
|
25
|
+
"src/boostexception.cpp",
|
|
26
|
+
"src/projectrtpfirfilter.cpp",
|
|
27
|
+
"src/projectrtpnodemain.cpp",
|
|
28
|
+
"src/projectrtpbuffer.cpp",
|
|
29
|
+
"src/projectrtppacket.cpp",
|
|
30
|
+
"src/projectrtprawsound.cpp",
|
|
31
|
+
"src/projectrtpcodecx.cpp",
|
|
32
|
+
"src/projectrtpchannelrecorder.cpp",
|
|
33
|
+
"src/projectrtpsoundfile.cpp",
|
|
34
|
+
"src/projectrtpsoundsoup.cpp",
|
|
35
|
+
"src/projectrtptonegen.cpp",
|
|
36
|
+
"src/projectrtpchannel.cpp",
|
|
37
|
+
"src/projectrtpchannelmux.cpp",
|
|
38
|
+
"src/projectrtpsrtp.cpp",
|
|
39
|
+
"src/projectrtpstun.cpp" ],
|
|
40
|
+
"include_dirs": [
|
|
41
|
+
"src"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
package/index.js
CHANGED
package/lib/server.js
CHANGED
|
@@ -106,6 +106,12 @@ class channel {
|
|
|
106
106
|
*/
|
|
107
107
|
openresolve
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* @private
|
|
111
|
+
* @type { string }
|
|
112
|
+
*/
|
|
113
|
+
ctype
|
|
114
|
+
|
|
109
115
|
/**
|
|
110
116
|
* @private
|
|
111
117
|
* @type { function }
|
|
@@ -218,6 +224,7 @@ class channel {
|
|
|
218
224
|
static _createforlisten( request, remotenode, cb, openresolve, openreject ) {
|
|
219
225
|
|
|
220
226
|
const newchannel = new channel( request.id )
|
|
227
|
+
newchannel.ctype = "l"
|
|
221
228
|
|
|
222
229
|
newchannel.connection = remotenode
|
|
223
230
|
if( cb ) newchannel.em.on( "all", cb )
|
|
@@ -246,6 +253,9 @@ class channel {
|
|
|
246
253
|
static _createforconnect( options, cb, openresolve, openreject ) {
|
|
247
254
|
|
|
248
255
|
const newchannel = new channel( options.id )
|
|
256
|
+
|
|
257
|
+
newchannel.ctype = "c"
|
|
258
|
+
|
|
249
259
|
if( cb ) newchannel.em.on( "all", cb )
|
|
250
260
|
const connecttonode = randomconnectnode()
|
|
251
261
|
return new Promise( connectresolve => {
|
|
@@ -590,7 +600,7 @@ class channel {
|
|
|
590
600
|
// adjust with filter
|
|
591
601
|
const index = this.channels.indexOf( this )
|
|
592
602
|
if( -1 < index ) this.channels.splice( index, 1 )
|
|
593
|
-
if( 0 === this.channels.length && this.connection.sock ) {
|
|
603
|
+
if( this.ctype == "c" && 0 === this.channels.length && this.connection.sock ) {
|
|
594
604
|
this.connection.sock.destroy()
|
|
595
605
|
}
|
|
596
606
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babblevoice/projectrtp",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.34",
|
|
4
4
|
"description": "A scalable Node addon RTP server",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
"check": "tsc --checkJs --noEmit --target es6 --module commonjs --skipLibCheck *.js test/**/*.js; ./node_modules/eslint/bin/eslint.js ./",
|
|
15
15
|
"docs": "jsdoc -c jsdoc.conf.json ./README.md",
|
|
16
16
|
"stress": "node stress/index.js",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"install": "
|
|
17
|
+
"configure:dev": "node-gyp configure --debug",
|
|
18
|
+
"configure": "node-gyp configure",
|
|
19
|
+
"rebuild:dev": "node-gyp configure --debug; node-gyp rebuild --debug",
|
|
20
|
+
"clean": "node-gyp clean",
|
|
21
|
+
"build:dev": "node-gyp configure build --debug",
|
|
22
|
+
"build": "node-gyp configure build",
|
|
23
|
+
"rebuild": "node-gyp rebuild",
|
|
24
|
+
"install": "node-gyp rebuild"
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"homepage": "https://github.com/babblevoice/projectrtp#readme",
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"node-addon-api": "^8.2.2",
|
|
37
38
|
"uuid": "^9.0.0"
|
|
38
39
|
},
|
|
39
40
|
"keywords": [
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"@types/node": "^12.20.55",
|
|
49
50
|
"@types/uuid": "^9.0.0",
|
|
50
51
|
"chai": "^4.3.7",
|
|
51
|
-
"eslint": "^
|
|
52
|
+
"eslint": "^9.15.0",
|
|
52
53
|
"fft-js": "^0.0.12",
|
|
53
54
|
"jsdoc": "^4.0.0",
|
|
54
55
|
"mocha": "^10.2.0",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
#ifdef BOOST_NO_EXCEPTIONS
|
|
3
|
+
|
|
4
|
+
#include <boost/throw_exception.hpp>
|
|
5
|
+
#include <stdexcept>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
Provided exception handlers when BOOST_NO_EXCEPTIONS is defined
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
namespace boost {
|
|
13
|
+
void throw_exception( const std::exception& e ) {
|
|
14
|
+
std::cerr << "Boost exception: " << e.what() << std::endl;
|
|
15
|
+
std::terminate();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void throw_exception( const std::exception& e, const boost::source_location& ) {
|
|
19
|
+
std::cerr << "Boost exception with location: " << e.what() << std::endl;
|
|
20
|
+
std::terminate();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#endif
|
package/src/globals.h
CHANGED
|
@@ -50,8 +50,19 @@ private:
|
|
|
50
50
|
std::shared_ptr< void > d; // Copied from Request
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
/*
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
/* Use spin locks for effiencent protection and ensure unlock */
|
|
54
|
+
struct SpinLockGuard {
|
|
55
|
+
std::atomic_bool& lock;
|
|
56
|
+
|
|
57
|
+
SpinLockGuard( std::atomic_bool& l ) : lock( l ) {
|
|
58
|
+
while( lock.exchange( true, std::memory_order_acquire ) ) {
|
|
59
|
+
// Spin until the lock is acquired
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
~SpinLockGuard() {
|
|
64
|
+
lock.store(false, std::memory_order_release);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
56
67
|
|
|
57
68
|
#endif /* PROJECTRTPGLOBALS_H */
|
|
@@ -26,10 +26,10 @@ std::atomic< std::uint32_t > channelscreated{ 0 };
|
|
|
26
26
|
* Get the next available port.
|
|
27
27
|
*/
|
|
28
28
|
unsigned short getavailableport( void ) {
|
|
29
|
-
|
|
29
|
+
SpinLockGuard guard( availableportslock );
|
|
30
|
+
|
|
30
31
|
auto ourport = availableports.front();
|
|
31
32
|
availableports.pop();
|
|
32
|
-
RELEASESPINLOCK( availableportslock );
|
|
33
33
|
|
|
34
34
|
channelscreated.fetch_add( 1 );
|
|
35
35
|
|
|
@@ -41,11 +41,8 @@ unsigned short getavailableport( void ) {
|
|
|
41
41
|
* @returns { size_t }
|
|
42
42
|
*/
|
|
43
43
|
auto getvailableportsize() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
RELEASESPINLOCK( availableportslock );
|
|
47
|
-
|
|
48
|
-
return availableportssize;
|
|
44
|
+
SpinLockGuard guard( availableportslock );
|
|
45
|
+
return availableports.size();
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
/**
|
|
@@ -55,10 +52,10 @@ auto getvailableportsize() {
|
|
|
55
52
|
void projectrtpchannel::returnavailableport( void ) {
|
|
56
53
|
|
|
57
54
|
if( 0 == this->port ) return;
|
|
58
|
-
|
|
55
|
+
SpinLockGuard guard( availableportslock );
|
|
56
|
+
|
|
59
57
|
availableports.push( this->port );
|
|
60
58
|
this->port = 0;
|
|
61
|
-
RELEASESPINLOCK( availableportslock );
|
|
62
59
|
|
|
63
60
|
channelscreated.fetch_sub( 1 );
|
|
64
61
|
}
|
|
@@ -230,9 +227,10 @@ void projectrtpchannel::remote( std::string address,
|
|
|
230
227
|
}
|
|
231
228
|
} );
|
|
232
229
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
{
|
|
231
|
+
SpinLockGuard guard( this->rtpdtlslock );
|
|
232
|
+
this->rtpdtls = newsession;
|
|
233
|
+
}
|
|
236
234
|
}
|
|
237
235
|
|
|
238
236
|
this->receivedrtp = false;
|
|
@@ -426,15 +424,17 @@ void projectrtpchannel::doclose( void ) {
|
|
|
426
424
|
postdatabacktojsfromthread( shared_from_this(), "play", "end", "channelclosed" );
|
|
427
425
|
}
|
|
428
426
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
427
|
+
{
|
|
428
|
+
SpinLockGuard guard( this->newplaylock );
|
|
429
|
+
this->player = nullptr;
|
|
430
|
+
this->newplaydef = nullptr;
|
|
431
|
+
}
|
|
433
432
|
|
|
434
433
|
/* close our session if we have one */
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
434
|
+
{
|
|
435
|
+
SpinLockGuard dtlsguard( this->rtpdtlslock );
|
|
436
|
+
this->rtpdtls = nullptr;
|
|
437
|
+
}
|
|
438
438
|
|
|
439
439
|
/* close up any remaining recorders */
|
|
440
440
|
for( auto& rec: this->recorders ) {
|
|
@@ -499,7 +499,7 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
499
499
|
if( this->mixing ) {
|
|
500
500
|
this->setnexttick();
|
|
501
501
|
return;
|
|
502
|
-
}
|
|
502
|
+
}
|
|
503
503
|
|
|
504
504
|
this->startticktimer();
|
|
505
505
|
|
|
@@ -517,14 +517,16 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
517
517
|
|
|
518
518
|
rtppacket *src;
|
|
519
519
|
do {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
AQUIRESPINLOCK( this->rtpdtlslock );
|
|
525
|
-
dtlssession::pointer currentdtlssession = this->rtpdtls;
|
|
526
|
-
RELEASESPINLOCK( this->rtpdtlslock );
|
|
520
|
+
{
|
|
521
|
+
SpinLockGuard guard( this->rtpbufferlock );
|
|
522
|
+
src = this->inbuff->pop();
|
|
523
|
+
}
|
|
527
524
|
|
|
525
|
+
dtlssession::pointer currentdtlssession;
|
|
526
|
+
{
|
|
527
|
+
SpinLockGuard guarddtls( this->rtpdtlslock );
|
|
528
|
+
currentdtlssession = this->rtpdtls;
|
|
529
|
+
}
|
|
528
530
|
|
|
529
531
|
if( nullptr != currentdtlssession &&
|
|
530
532
|
!currentdtlssession->rtpdtlshandshakeing ) {
|
|
@@ -545,19 +547,20 @@ void projectrtpchannel::handletick( const boost::system::error_code& error ) {
|
|
|
545
547
|
{
|
|
546
548
|
bool playerreplaced = false;
|
|
547
549
|
bool playernew = false;
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
this->
|
|
550
|
+
{
|
|
551
|
+
SpinLockGuard guard( this->newplaylock );
|
|
552
|
+
if( nullptr != this->newplaydef ) {
|
|
553
|
+
this->doecho = false;
|
|
551
554
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
+
if( nullptr != this->player ) {
|
|
556
|
+
playerreplaced = true;
|
|
557
|
+
}
|
|
555
558
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
+
this->player = this->newplaydef;
|
|
560
|
+
this->newplaydef = nullptr;
|
|
561
|
+
playernew = true;
|
|
562
|
+
}
|
|
559
563
|
}
|
|
560
|
-
RELEASESPINLOCK( this->newplaylock );
|
|
561
564
|
|
|
562
565
|
if( playerreplaced ) {
|
|
563
566
|
postdatabacktojsfromthread( shared_from_this(), "play", "end", "replaced" );
|
|
@@ -625,9 +628,8 @@ void projectrtpchannel::setnexttick( void ) {
|
|
|
625
628
|
}
|
|
626
629
|
|
|
627
630
|
void projectrtpchannel::requestplay( soundsoup::pointer newdef ) {
|
|
628
|
-
|
|
631
|
+
SpinLockGuard guard( this->newplaylock );
|
|
629
632
|
this->newplaydef = newdef;
|
|
630
|
-
RELEASESPINLOCK( this->newplaylock );
|
|
631
633
|
}
|
|
632
634
|
|
|
633
635
|
/*
|
|
@@ -635,9 +637,8 @@ Post a request to record (or modify a param of a record). This function is typic
|
|
|
635
637
|
called from a control thread (i.e. node).
|
|
636
638
|
*/
|
|
637
639
|
void projectrtpchannel::requestrecord( channelrecorder::pointer rec ) {
|
|
638
|
-
|
|
640
|
+
SpinLockGuard guard( this->newrecorderslock );
|
|
639
641
|
this->newrecorders.push_back( rec );
|
|
640
|
-
RELEASESPINLOCK( this->newrecorderslock );
|
|
641
642
|
}
|
|
642
643
|
|
|
643
644
|
/*
|
|
@@ -646,10 +647,9 @@ to requestrecord.
|
|
|
646
647
|
*/
|
|
647
648
|
void projectrtpchannel::checkfornewrecorders( void ) {
|
|
648
649
|
channelrecorder::pointer rec;
|
|
649
|
-
|
|
650
|
+
SpinLockGuard guard( this->newrecorderslock );
|
|
650
651
|
|
|
651
652
|
for ( auto const& newrec : this->newrecorders ) {
|
|
652
|
-
|
|
653
653
|
for( auto& currentrec: this->recorders ) {
|
|
654
654
|
if( currentrec->file == newrec->file ) {
|
|
655
655
|
currentrec->pause = newrec->pause;
|
|
@@ -669,8 +669,6 @@ endofwhileloop:;
|
|
|
669
669
|
}
|
|
670
670
|
|
|
671
671
|
this->newrecorders.clear();
|
|
672
|
-
|
|
673
|
-
RELEASESPINLOCK( this->newrecorderslock );
|
|
674
672
|
}
|
|
675
673
|
|
|
676
674
|
void projectrtpchannel::removeoldrecorders( void ) {
|
|
@@ -832,17 +830,14 @@ void projectrtpchannel::writerecordings( void ) {
|
|
|
832
830
|
}
|
|
833
831
|
|
|
834
832
|
bool projectrtpchannel::dtlsnegotiate( void ) {
|
|
833
|
+
SpinLockGuard guard( this->rtpdtlslock );
|
|
835
834
|
|
|
836
|
-
AQUIRESPINLOCK( this->rtpdtlslock );
|
|
837
835
|
dtlssession::pointer oursession = this->rtpdtls;
|
|
838
|
-
RELEASESPINLOCK( this->rtpdtlslock );
|
|
839
836
|
|
|
840
837
|
if( nullptr == oursession ) return false;
|
|
841
838
|
if( !oursession->rtpdtlshandshakeing ) return false;
|
|
842
839
|
|
|
843
|
-
AQUIRESPINLOCK( this->rtpdtlslock );
|
|
844
840
|
auto dtlsstate = oursession->handshake();
|
|
845
|
-
RELEASESPINLOCK( this->rtpdtlslock );
|
|
846
841
|
|
|
847
842
|
if( GNUTLS_E_SUCCESS != dtlsstate && 0 != gnutls_error_is_fatal( dtlsstate ) ) {
|
|
848
843
|
oursession->bye();
|
|
@@ -929,9 +924,12 @@ void projectrtpchannel::readsomertp( void ) {
|
|
|
929
924
|
if( !this->active || this->_requestclose ) return;
|
|
930
925
|
|
|
931
926
|
/* Grab a buffer */
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
927
|
+
rtppacket* buf;
|
|
928
|
+
{
|
|
929
|
+
SpinLockGuard guard( this->rtpbufferlock );
|
|
930
|
+
buf = this->inbuff->reserve();
|
|
931
|
+
}
|
|
932
|
+
|
|
935
933
|
|
|
936
934
|
if( nullptr == buf ) {
|
|
937
935
|
fprintf( stderr, "Error no buffer\n" );
|
|
@@ -954,15 +952,19 @@ void projectrtpchannel::readsomertp( void ) {
|
|
|
954
952
|
if( this->handlestun( buf->pk, bytesrecvd ) )
|
|
955
953
|
goto readsomemore;
|
|
956
954
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
955
|
+
dtlssession::pointer currentdtlssession;
|
|
956
|
+
{
|
|
957
|
+
SpinLockGuard guard( this->rtpdtlslock );
|
|
958
|
+
currentdtlssession = this->rtpdtls;
|
|
959
|
+
}
|
|
960
960
|
|
|
961
961
|
if( nullptr != currentdtlssession &&
|
|
962
962
|
currentdtlssession->rtpdtlshandshakeing ) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
963
|
+
{
|
|
964
|
+
SpinLockGuard guard( this->rtpdtlslock );
|
|
965
|
+
currentdtlssession->write( buf->pk, bytesrecvd );
|
|
966
|
+
}
|
|
967
|
+
|
|
966
968
|
this->dtlsnegotiate();
|
|
967
969
|
goto readsomemore;
|
|
968
970
|
}
|
|
@@ -1010,9 +1012,10 @@ void projectrtpchannel::readsomertp( void ) {
|
|
|
1010
1012
|
buf->setpayloadtype( RFC2833PAYLOADTYPE );
|
|
1011
1013
|
}
|
|
1012
1014
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1015
|
+
{
|
|
1016
|
+
SpinLockGuard guard( this->rtpbufferlock );
|
|
1017
|
+
this->inbuff->push();
|
|
1018
|
+
}
|
|
1016
1019
|
}
|
|
1017
1020
|
|
|
1018
1021
|
readsomemore:
|
|
@@ -1079,9 +1082,11 @@ void projectrtpchannel::writepacket( rtppacket *pk ) {
|
|
|
1079
1082
|
|
|
1080
1083
|
if( !this->active ) return;
|
|
1081
1084
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
+
dtlssession::pointer currentdtlssession;
|
|
1086
|
+
{
|
|
1087
|
+
SpinLockGuard guard( this->rtpdtlslock );
|
|
1088
|
+
currentdtlssession = this->rtpdtls;
|
|
1089
|
+
}
|
|
1085
1090
|
|
|
1086
1091
|
if( nullptr != currentdtlssession &&
|
|
1087
1092
|
currentdtlssession->rtpdtlshandshakeing ) {
|
|
@@ -1143,7 +1148,7 @@ bool projectrtpchannel::mix( projectrtpchannel::pointer other ) {
|
|
|
1143
1148
|
return true;
|
|
1144
1149
|
}
|
|
1145
1150
|
|
|
1146
|
-
|
|
1151
|
+
SpinLockGuard guard( this->mixerlock );
|
|
1147
1152
|
|
|
1148
1153
|
if( nullptr == this->mixer && nullptr != other->mixer ) {
|
|
1149
1154
|
this->mixer = other->mixer;
|
|
@@ -1162,13 +1167,10 @@ bool projectrtpchannel::mix( projectrtpchannel::pointer other ) {
|
|
|
1162
1167
|
this->mixer->go();
|
|
1163
1168
|
} else {
|
|
1164
1169
|
/* If we get here this and other are already mixing and should be cleaned up first */
|
|
1165
|
-
RELEASESPINLOCK( this->mixerlock );
|
|
1166
1170
|
postdatabacktojsfromthread( shared_from_this(), "mix", "busy" );
|
|
1167
1171
|
return false;
|
|
1168
1172
|
}
|
|
1169
1173
|
|
|
1170
|
-
RELEASESPINLOCK( this->mixerlock );
|
|
1171
|
-
|
|
1172
1174
|
postdatabacktojsfromthread( shared_from_this(), "mix", "start" );
|
|
1173
1175
|
postdatabacktojsfromthread( other, "mix", "start" );
|
|
1174
1176
|
|
|
@@ -1181,11 +1183,9 @@ Add the other to a mixer - both channels have access to the same mixer.
|
|
|
1181
1183
|
n way relationship. Adds to queue for when our main thread calls into us.
|
|
1182
1184
|
*/
|
|
1183
1185
|
bool projectrtpchannel::unmix( void ) {
|
|
1186
|
+
SpinLockGuard guard( this->mixerlock );
|
|
1184
1187
|
|
|
1185
|
-
AQUIRESPINLOCK( this->mixerlock );
|
|
1186
1188
|
if( nullptr != this->mixer ) this->removemixer = true;
|
|
1187
|
-
RELEASESPINLOCK( this->mixerlock );
|
|
1188
|
-
|
|
1189
1189
|
return true;
|
|
1190
1190
|
}
|
|
1191
1191
|
|
|
@@ -1196,9 +1196,10 @@ bool projectrtpchannel::unmix( void ) {
|
|
|
1196
1196
|
void projectrtpchannel::dounmix( void ) {
|
|
1197
1197
|
this->mixing = false;
|
|
1198
1198
|
this->removemixer = false;
|
|
1199
|
-
|
|
1199
|
+
|
|
1200
|
+
SpinLockGuard guard( this->mixerlock );
|
|
1201
|
+
|
|
1200
1202
|
this->mixer = nullptr;
|
|
1201
|
-
RELEASESPINLOCK( this->mixerlock );
|
|
1202
1203
|
|
|
1203
1204
|
postdatabacktojsfromthread( shared_from_this(), "mix", "finished" );
|
|
1204
1205
|
|
|
@@ -1212,9 +1213,8 @@ void projectrtpchannel::dounmix( void ) {
|
|
|
1212
1213
|
Queue digits to send as RFC 2833.
|
|
1213
1214
|
*/
|
|
1214
1215
|
void projectrtpchannel::dtmf( std::string digits ) {
|
|
1215
|
-
|
|
1216
|
+
SpinLockGuard guard( this->queuddigitslock );
|
|
1216
1217
|
this->queueddigits += digits;
|
|
1217
|
-
RELEASESPINLOCK( this->queuddigitslock );
|
|
1218
1218
|
}
|
|
1219
1219
|
|
|
1220
1220
|
/*
|
|
@@ -1227,12 +1227,13 @@ void projectrtpchannel::senddtmf( void ) {
|
|
|
1227
1227
|
}
|
|
1228
1228
|
|
|
1229
1229
|
uint8_t tosend = 0;
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1230
|
+
{
|
|
1231
|
+
SpinLockGuard guard( this->queuddigitslock );
|
|
1232
|
+
if( this->queueddigits.size() > 0 ) {
|
|
1233
|
+
tosend = this->queueddigits[ 0 ];
|
|
1234
|
+
this->queueddigits.erase( this->queueddigits.begin() );
|
|
1235
|
+
}
|
|
1234
1236
|
}
|
|
1235
|
-
RELEASESPINLOCK( this->queuddigitslock );
|
|
1236
1237
|
|
|
1237
1238
|
if( 0 == tosend ) {
|
|
1238
1239
|
return;
|
|
@@ -2368,12 +2369,14 @@ void getchannelstats( napi_env env, napi_value &result ) {
|
|
|
2368
2369
|
void initrtpchannel( napi_env env, napi_value &result, int32_t startport, int32_t endport ) {
|
|
2369
2370
|
napi_value ccreate;
|
|
2370
2371
|
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
availableports.
|
|
2372
|
+
{
|
|
2373
|
+
SpinLockGuard guard( availableportslock );
|
|
2374
|
+
|
|
2375
|
+
while(!availableports.empty()) availableports.pop();
|
|
2376
|
+
for( int i = (int) startport; i < (int) endport; i = i + 2 ) {
|
|
2377
|
+
availableports.push( i );
|
|
2378
|
+
}
|
|
2375
2379
|
}
|
|
2376
|
-
RELEASESPINLOCK( availableportslock );
|
|
2377
2380
|
|
|
2378
2381
|
if( napi_ok != napi_create_function( env, "exports", NAPI_AUTO_LENGTH, channelcreate, nullptr, &ccreate ) ) return;
|
|
2379
2382
|
if( napi_ok != napi_set_named_property( env, result, "openchannel", ccreate ) ) return;
|
|
@@ -56,24 +56,30 @@ void projectchannelmux::mixall( void ) {
|
|
|
56
56
|
|
|
57
57
|
rtppacket *src;
|
|
58
58
|
while( true ) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
{
|
|
60
|
+
SpinLockGuard guard( chan->rtpbufferlock );
|
|
61
|
+
src = chan->inbuff->peek();
|
|
62
|
+
}
|
|
62
63
|
|
|
63
64
|
if( nullptr == src ) break;
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
dtlssession::pointer currentdtlssession;
|
|
67
|
+
{
|
|
68
|
+
SpinLockGuard guard( chan->rtpdtlslock );
|
|
69
|
+
currentdtlssession = chan->rtpdtls;
|
|
70
|
+
}
|
|
71
|
+
|
|
68
72
|
if( nullptr != currentdtlssession &&
|
|
69
73
|
!currentdtlssession->rtpdtlshandshakeing ) {
|
|
70
74
|
if( !currentdtlssession->unprotect( src ) ) {
|
|
71
75
|
chan->receivedpkskip++;
|
|
72
76
|
src = nullptr;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
|
|
78
|
+
{
|
|
79
|
+
SpinLockGuard guard( chan->rtpbufferlock );
|
|
80
|
+
chan->inbuff->poppeeked();
|
|
81
|
+
}
|
|
82
|
+
|
|
77
83
|
break;
|
|
78
84
|
}
|
|
79
85
|
}
|
|
@@ -86,9 +92,10 @@ void projectchannelmux::mixall( void ) {
|
|
|
86
92
|
}
|
|
87
93
|
}
|
|
88
94
|
/* remove the DTMF packet */
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
{
|
|
96
|
+
SpinLockGuard guard( chan->rtpbufferlock );
|
|
97
|
+
chan->inbuff->poppeeked();
|
|
98
|
+
}
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
if( nullptr != src ) {
|
|
@@ -101,9 +108,8 @@ void projectchannelmux::mixall( void ) {
|
|
|
101
108
|
/* Now we subtract this channel to send to this channel. */
|
|
102
109
|
for( auto& chan: this->channels ) {
|
|
103
110
|
if( !chan->send ) {
|
|
104
|
-
|
|
111
|
+
SpinLockGuard guard( chan->rtpbufferlock );
|
|
105
112
|
chan->inbuff->poppeeked();
|
|
106
|
-
RELEASESPINLOCK( chan->rtpbufferlock );
|
|
107
113
|
continue;
|
|
108
114
|
}
|
|
109
115
|
|
|
@@ -113,15 +119,20 @@ void projectchannelmux::mixall( void ) {
|
|
|
113
119
|
this->subtracted.copy( this->added );
|
|
114
120
|
|
|
115
121
|
if( chan->recv ) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
rtppacket *src;
|
|
123
|
+
{
|
|
124
|
+
SpinLockGuard guard( chan->rtpbufferlock );
|
|
125
|
+
src = chan->inbuff->peeked();
|
|
126
|
+
}
|
|
127
|
+
|
|
119
128
|
if( nullptr != src ) {
|
|
120
129
|
this->subtracted -= chan->incodec;
|
|
121
130
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
|
|
132
|
+
{
|
|
133
|
+
SpinLockGuard guard( chan->rtpbufferlock );
|
|
134
|
+
chan->inbuff->poppeeked();
|
|
135
|
+
}
|
|
125
136
|
}
|
|
126
137
|
|
|
127
138
|
chan->outcodec << codecx::next;
|
|
@@ -144,15 +155,20 @@ void projectchannelmux::mix2( void ) {
|
|
|
144
155
|
rtppacket *src;
|
|
145
156
|
|
|
146
157
|
while( true ) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
158
|
+
{
|
|
159
|
+
SpinLockGuard guard( chan1->rtpbufferlock );
|
|
160
|
+
src = chan1->inbuff->pop();
|
|
161
|
+
}
|
|
150
162
|
|
|
151
163
|
if( nullptr == src ) break;
|
|
152
164
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
dtlssession::pointer currentdtlssession;
|
|
166
|
+
{
|
|
167
|
+
SpinLockGuard guard( chan1->rtpdtlslock );
|
|
168
|
+
currentdtlssession = chan1->rtpdtls;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
156
172
|
if( nullptr != currentdtlssession &&
|
|
157
173
|
!currentdtlssession->rtpdtlshandshakeing ) {
|
|
158
174
|
if( !currentdtlssession->unprotect( src ) ) {
|
|
@@ -168,15 +184,20 @@ void projectchannelmux::mix2( void ) {
|
|
|
168
184
|
this->postrtpdata( chan1, chan2, src );
|
|
169
185
|
|
|
170
186
|
while( true ) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
187
|
+
{
|
|
188
|
+
SpinLockGuard guard( chan2->rtpbufferlock );
|
|
189
|
+
src = chan2->inbuff->pop();
|
|
190
|
+
}
|
|
174
191
|
|
|
175
192
|
if( nullptr == src ) break;
|
|
176
193
|
|
|
177
|
-
|
|
178
|
-
dtlssession::pointer currentdtlssession
|
|
179
|
-
|
|
194
|
+
|
|
195
|
+
dtlssession::pointer currentdtlssession;
|
|
196
|
+
{
|
|
197
|
+
SpinLockGuard guard( chan2->rtpdtlslock );
|
|
198
|
+
currentdtlssession = chan2->rtpdtls;
|
|
199
|
+
}
|
|
200
|
+
|
|
180
201
|
if( nullptr != currentdtlssession &&
|
|
181
202
|
!currentdtlssession->rtpdtlshandshakeing ) {
|
|
182
203
|
if( !currentdtlssession->unprotect( src ) ) {
|
|
@@ -299,8 +320,7 @@ static bool underlyingpointercmp( projectrtpchannelptr l, projectrtpchannelptr r
|
|
|
299
320
|
Check for new channels to add to the mix in our own thread.
|
|
300
321
|
*/
|
|
301
322
|
void projectchannelmux::checkfornewmixes( void ) {
|
|
302
|
-
|
|
303
|
-
AQUIRESPINLOCK( this->newchannelslock );
|
|
323
|
+
SpinLockGuard guard( this->newchannelslock );
|
|
304
324
|
|
|
305
325
|
for ( auto const& newchan : this->newchannels ) {
|
|
306
326
|
this->channels.push_back( newchan );
|
|
@@ -309,24 +329,22 @@ void projectchannelmux::checkfornewmixes( void ) {
|
|
|
309
329
|
|
|
310
330
|
this->channels.sort( underlyingpointercmp );
|
|
311
331
|
this->channels.unique( underlyingpointerequal );
|
|
312
|
-
|
|
313
|
-
RELEASESPINLOCK( this->newchannelslock );
|
|
314
332
|
}
|
|
315
333
|
|
|
316
334
|
void projectchannelmux::addchannel( projectrtpchannelptr chan ) {
|
|
317
|
-
|
|
335
|
+
SpinLockGuard guard( this->newchannelslock );
|
|
336
|
+
|
|
318
337
|
chan->mixing = true;
|
|
319
338
|
this->newchannels.push_back( chan );
|
|
320
|
-
RELEASESPINLOCK( this->newchannelslock );
|
|
321
339
|
}
|
|
322
340
|
|
|
323
341
|
void projectchannelmux::addchannels( projectrtpchannelptr chana, projectrtpchannelptr chanb ) {
|
|
324
|
-
|
|
342
|
+
SpinLockGuard guard( this->newchannelslock );
|
|
343
|
+
|
|
325
344
|
chana->mixing = true;
|
|
326
345
|
chanb->mixing = true;
|
|
327
346
|
this->newchannels.push_back( chana );
|
|
328
347
|
this->newchannels.push_back( chanb );
|
|
329
|
-
RELEASESPINLOCK( this->newchannelslock );
|
|
330
348
|
}
|
|
331
349
|
|
|
332
350
|
/*
|
|
@@ -28,12 +28,6 @@ static std::atomic_bool warningissued( false );
|
|
|
28
28
|
int32_t startport = 10000;
|
|
29
29
|
int32_t endport = 20000;
|
|
30
30
|
|
|
31
|
-
void boost::throw_exception( std::exception const & e ) {
|
|
32
|
-
std::string err = boost::diagnostic_information( e );
|
|
33
|
-
fprintf( stderr, "%s", err.c_str() );
|
|
34
|
-
exit( EXIT_FAILURE );
|
|
35
|
-
}
|
|
36
|
-
|
|
37
31
|
/* our work queue requires some work to not exit */
|
|
38
32
|
static ourhighrestimer periodictimer( workercontext );
|
|
39
33
|
|
|
@@ -203,33 +197,35 @@ void initserver( napi_env env, napi_value &result ) {
|
|
|
203
197
|
if( napi_ok != napi_set_named_property( env, result, "stats", cstats ) ) return;
|
|
204
198
|
}
|
|
205
199
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
srand( time( NULL ) );
|
|
200
|
+
/* Initialize the module */
|
|
201
|
+
napi_value initprtp(napi_env env, napi_value exports) {
|
|
202
|
+
std::atomic_bool test;
|
|
203
|
+
if (!test.is_lock_free()) {
|
|
204
|
+
fprintf(stderr, "Warning - performance will be poor as atomic variables are not available\n");
|
|
205
|
+
}
|
|
215
206
|
|
|
216
|
-
|
|
207
|
+
srand(time(NULL));
|
|
217
208
|
|
|
218
|
-
|
|
209
|
+
/* Initialize DTLS or other dependencies */
|
|
210
|
+
dtlsinit();
|
|
219
211
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
212
|
+
/* Initialize the exported module object */
|
|
213
|
+
initserver(env, exports);
|
|
214
|
+
initrtpbuffer(env, exports);
|
|
215
|
+
initrtpchannel(env, exports, startport, endport);
|
|
216
|
+
initrtpsoundfile(env, exports);
|
|
217
|
+
initrtpcodecx(env, exports);
|
|
218
|
+
initfilter(env, exports);
|
|
219
|
+
inittonegen(env, exports);
|
|
220
|
+
initsrtp(env, exports);
|
|
229
221
|
|
|
230
|
-
|
|
222
|
+
/* Generate G.711 conversion data */
|
|
223
|
+
gen711convertdata();
|
|
231
224
|
|
|
232
|
-
|
|
225
|
+
return exports;
|
|
233
226
|
}
|
|
234
227
|
|
|
228
|
+
/* Register the module */
|
|
229
|
+
NAPI_MODULE(NODE_GYP_MODULE_NAME, initprtp)
|
|
230
|
+
|
|
235
231
|
#endif /* NODE_MODULE */
|
package/stress/index.js
CHANGED
|
@@ -46,6 +46,18 @@ const run = async () => {
|
|
|
46
46
|
await node.listen( projectrtp, "127.0.0.1", 9002 )
|
|
47
47
|
} else console.log( "Mode: server as listener" )
|
|
48
48
|
|
|
49
|
+
let currentstatsquery = 0
|
|
50
|
+
const intervaletimers = [
|
|
51
|
+
setInterval( () => {
|
|
52
|
+
currentstatsquery++
|
|
53
|
+
const prtpstats = projectrtp.stats()
|
|
54
|
+
currentstatsquery--
|
|
55
|
+
}, 100 ),
|
|
56
|
+
setInterval( () => {
|
|
57
|
+
if( currentstatsquery > 3 ) utils.log( "Problem with stats not completing" )
|
|
58
|
+
}, 100 )
|
|
59
|
+
]
|
|
60
|
+
|
|
49
61
|
while ( rununtil > Math.floor( Date.now() / 1000 ) ) {
|
|
50
62
|
if( utils.currentchannelcount() < maxnumberofsessions ) {
|
|
51
63
|
scenarios[ utils.between( 0, scenarios.length ) ]( utils.between( minmscalllength, maxmscalllength ) )
|
|
@@ -56,6 +68,9 @@ const run = async () => {
|
|
|
56
68
|
|
|
57
69
|
/* It is safe to call shutdown before we are complete - it will just shutdown after all the work is done */
|
|
58
70
|
projectrtp.shutdown()
|
|
71
|
+
|
|
72
|
+
clearInterval( intervaletimers[ 0 ] )
|
|
73
|
+
clearInterval( intervaletimers[ 1 ] )
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
run()
|
|
@@ -680,7 +680,6 @@ describe( "rtpproxy server", function() {
|
|
|
680
680
|
const p = await prtp.proxy.listen( undefined, "127.0.0.1", ourport )
|
|
681
681
|
const ournode = await prtp.node.connect( ourport, "127.0.0.1" )
|
|
682
682
|
|
|
683
|
-
|
|
684
683
|
const chnl = await prtp.openchannel()
|
|
685
684
|
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 100 ) } )
|
|
686
685
|
await chnl.close()
|
package/src/binding.gyp
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"targets": [
|
|
3
|
-
{
|
|
4
|
-
"target_name": "projectrtp",
|
|
5
|
-
"defines": [ "NODE_MODULE", "BOOST_NO_EXCEPTIONS", "BOOST_EXCEPTION_DISABLE" ],
|
|
6
|
-
"cflags_cc!": [ "-fno-rtti" ],
|
|
7
|
-
"cflags_cc": [
|
|
8
|
-
"-O3",
|
|
9
|
-
"-g",
|
|
10
|
-
"-Wall",
|
|
11
|
-
"-fstack-protector-all",
|
|
12
|
-
"-std=c++17",
|
|
13
|
-
"-fconcepts-ts",
|
|
14
|
-
"-Weffc++" ],
|
|
15
|
-
"libraries": [
|
|
16
|
-
"-lrt",
|
|
17
|
-
"-lspandsp",
|
|
18
|
-
"-lilbc",
|
|
19
|
-
"-lgnutls",
|
|
20
|
-
"-lsrtp2",
|
|
21
|
-
"-fstack-protector-all"
|
|
22
|
-
],
|
|
23
|
-
"sources": [
|
|
24
|
-
"projectrtpfirfilter.cpp",
|
|
25
|
-
"projectrtpnodemain.cpp",
|
|
26
|
-
"projectrtpbuffer.cpp",
|
|
27
|
-
"projectrtppacket.cpp",
|
|
28
|
-
"projectrtprawsound.cpp",
|
|
29
|
-
"projectrtpcodecx.cpp",
|
|
30
|
-
"projectrtpchannelrecorder.cpp",
|
|
31
|
-
"projectrtpsoundfile.cpp",
|
|
32
|
-
"projectrtpsoundsoup.cpp",
|
|
33
|
-
"projectrtptonegen.cpp",
|
|
34
|
-
"projectrtpchannel.cpp",
|
|
35
|
-
"projectrtpchannelmux.cpp",
|
|
36
|
-
"projectrtpsrtp.cpp",
|
|
37
|
-
"projectrtpstun.cpp" ]
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|