@babblevoice/projectrtp 2.5.20 → 2.5.25
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/README.md +1 -1
- package/lib/server.js +9 -1
- package/package.json +1 -1
- package/src/globals.h +3 -0
- package/src/projectrtpchannel.cpp +16 -2
- package/src/projectrtpchannelmux.cpp +17 -7
- package/src/projectrtpchannelmux.h +4 -2
- package/src/projectrtpcodecx.cpp +76 -93
- package/src/projectrtpcodecx.h +1 -3
- package/src/projectrtprawsound.cpp +34 -70
- package/src/projectrtpsoundfile.cpp +62 -52
- package/src/projectrtpsoundfile.h +1 -0
- package/test/interface/pcap.js +2 -2
- package/test/interface/pcaps/440hzinbackgroundg722.pcap +0 -0
- package/test/interface/projectrtpchannel.js +4 -9
- package/test/interface/projectrtpdtmf.js +147 -6
- package/test/interface/projectrtpmix.js +77 -6
- package/test/interface/projectrtpsound.js +145 -91
- package/test/interface/transcode.js +164 -0
- package/test/util/rtp.js +17 -0
|
@@ -147,24 +147,17 @@ rawsound::~rawsound()
|
|
|
147
147
|
## zero
|
|
148
148
|
Reset buffer with zero
|
|
149
149
|
*/
|
|
150
|
-
void rawsound::zero( void )
|
|
151
|
-
|
|
152
|
-
if( nullptr != this->data )
|
|
153
|
-
{
|
|
154
|
-
size_t zeroamount = this->samples * this->bytespersample;
|
|
155
|
-
if( L1616KPAYLOADTYPE == format )
|
|
156
|
-
{
|
|
157
|
-
zeroamount = zeroamount * 2;
|
|
158
|
-
}
|
|
150
|
+
void rawsound::zero( void ) {
|
|
151
|
+
if( nullptr == this->data ) return;
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
{
|
|
162
|
-
std::cerr << "Trying to zero memory but capped by allocated amount" << std::endl;
|
|
163
|
-
zeroamount = this->allocatedlength;
|
|
164
|
-
}
|
|
153
|
+
size_t zeroamount = this->samples * this->bytespersample;
|
|
165
154
|
|
|
166
|
-
|
|
155
|
+
if( 0 != this->allocatedlength && zeroamount > this->allocatedlength ) {
|
|
156
|
+
std::cerr << "Trying to zero memory but capped by allocated amount" << std::endl;
|
|
157
|
+
zeroamount = this->allocatedlength;
|
|
167
158
|
}
|
|
159
|
+
|
|
160
|
+
memset( this->data, 0, zeroamount );
|
|
168
161
|
}
|
|
169
162
|
|
|
170
163
|
/*
|
|
@@ -172,49 +165,31 @@ void rawsound::zero( void )
|
|
|
172
165
|
* Target (this) MUST have memory available.
|
|
173
166
|
* format must be set appropriatly before the call
|
|
174
167
|
*/
|
|
175
|
-
void rawsound::copy( uint8_t *src, size_t len )
|
|
176
|
-
|
|
177
|
-
if( nullptr != this->data )
|
|
178
|
-
{
|
|
179
|
-
memcpy( this->data,
|
|
180
|
-
src,
|
|
181
|
-
len );
|
|
168
|
+
void rawsound::copy( uint8_t *src, size_t len ) {
|
|
169
|
+
if( nullptr == this->data ) return;
|
|
182
170
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
case L1616KPAYLOADTYPE:
|
|
187
|
-
{
|
|
188
|
-
this->samples = len / 2;
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
default:
|
|
192
|
-
{
|
|
193
|
-
this->samples = len;
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
171
|
+
memcpy( this->data,
|
|
172
|
+
src,
|
|
173
|
+
len );
|
|
198
174
|
}
|
|
199
175
|
|
|
200
176
|
/*
|
|
201
177
|
## copy (from other)
|
|
202
178
|
* Target (this) MUST have data allocated.
|
|
203
179
|
*/
|
|
204
|
-
void rawsound::copy( rawsound &other )
|
|
205
|
-
{
|
|
206
|
-
if( nullptr != this->data && this->samples >= other.samples )
|
|
207
|
-
{
|
|
208
|
-
this->bytespersample = other.bytespersample;
|
|
209
|
-
this->samplerate = other.samplerate;
|
|
210
|
-
this->format = other.format;
|
|
211
|
-
this->samples = other.samples;
|
|
180
|
+
void rawsound::copy( rawsound &other ) {
|
|
212
181
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
182
|
+
if( nullptr == this->data || this->samples < other.samples ) return;
|
|
183
|
+
|
|
184
|
+
this->bytespersample = other.bytespersample;
|
|
185
|
+
this->samplerate = other.samplerate;
|
|
186
|
+
this->format = other.format;
|
|
187
|
+
this->samples = other.samples;
|
|
188
|
+
|
|
189
|
+
memcpy( this->data,
|
|
190
|
+
other.data,
|
|
191
|
+
other.samples * other.bytespersample );
|
|
216
192
|
|
|
217
|
-
}
|
|
218
193
|
}
|
|
219
194
|
|
|
220
195
|
/*
|
|
@@ -237,15 +212,11 @@ void rawsound::subtract( void )
|
|
|
237
212
|
## malloc
|
|
238
213
|
Allocate our own memory.
|
|
239
214
|
*/
|
|
240
|
-
void rawsound::malloc( size_t samplecount, size_t bytespersample, int format )
|
|
241
|
-
{
|
|
215
|
+
void rawsound::malloc( size_t samplecount, size_t bytespersample, int format ) {
|
|
242
216
|
this->samples = samplecount;
|
|
243
217
|
this->bytespersample = bytespersample;
|
|
244
218
|
this->format = format;
|
|
245
219
|
size_t requiredsize = samplecount * bytespersample;
|
|
246
|
-
if( L1616KPAYLOADTYPE == format ) {
|
|
247
|
-
requiredsize = requiredsize * 2;
|
|
248
|
-
}
|
|
249
220
|
|
|
250
221
|
if( this->allocatedlength > 0 ) {
|
|
251
222
|
if( this->allocatedlength >= requiredsize ) {
|
|
@@ -262,46 +233,39 @@ void rawsound::malloc( size_t samplecount, size_t bytespersample, int format )
|
|
|
262
233
|
## operator +=
|
|
263
234
|
Used for mixing audio
|
|
264
235
|
*/
|
|
265
|
-
rawsound& rawsound::operator+=( codecx& rhs )
|
|
266
|
-
{
|
|
236
|
+
rawsound& rawsound::operator+=( codecx& rhs ) {
|
|
267
237
|
size_t length;
|
|
268
238
|
|
|
269
239
|
int16_t *in;
|
|
270
240
|
int16_t *out = ( int16_t * ) this->data;
|
|
271
241
|
|
|
272
|
-
switch( this->format )
|
|
273
|
-
|
|
274
|
-
case L168KPAYLOADTYPE:
|
|
275
|
-
{
|
|
242
|
+
switch( this->format ) {
|
|
243
|
+
case L168KPAYLOADTYPE: {
|
|
276
244
|
rhs.requirenarrowband();
|
|
277
|
-
|
|
245
|
+
if( rhs.l168kref.isdirty() ) return *this;
|
|
278
246
|
length = rhs.l168kref.size();
|
|
279
247
|
in = ( int16_t * ) rhs.l168kref.c_str();
|
|
280
248
|
break;
|
|
281
249
|
}
|
|
282
|
-
case L1616KPAYLOADTYPE:
|
|
283
|
-
{
|
|
250
|
+
case L1616KPAYLOADTYPE: {
|
|
284
251
|
rhs.requirewideband();
|
|
285
|
-
|
|
252
|
+
if( rhs.l1616kref.isdirty() ) return *this;
|
|
286
253
|
length = rhs.l1616kref.size();
|
|
287
254
|
in = ( int16_t * ) rhs.l1616kref.c_str();
|
|
288
255
|
break;
|
|
289
256
|
}
|
|
290
|
-
default:
|
|
291
|
-
{
|
|
257
|
+
default: {
|
|
292
258
|
std::cerr << "Attemping to perform an addition on a none linear format" << std::endl;
|
|
293
259
|
return *this;
|
|
294
260
|
}
|
|
295
261
|
}
|
|
296
262
|
|
|
297
|
-
if( length > this->samples )
|
|
298
|
-
{
|
|
263
|
+
if( length > this->samples ) {
|
|
299
264
|
std::cerr << "We have been asked to add samples but we don't have enough space" << std::endl;
|
|
300
265
|
length = this->samples;
|
|
301
266
|
}
|
|
302
267
|
|
|
303
|
-
for( size_t i = 0; i < length; i++ )
|
|
304
|
-
{
|
|
268
|
+
for( size_t i = 0; i < length; i++ ) {
|
|
305
269
|
*out++ += *in++;
|
|
306
270
|
}
|
|
307
271
|
|
|
@@ -101,6 +101,7 @@ soundfilereader::soundfilereader( std::string &url ) :
|
|
|
101
101
|
blocksize( L16NARROWBANDBYTES ),
|
|
102
102
|
badheader( false ),
|
|
103
103
|
headerread( false ),
|
|
104
|
+
bodyread( false ),
|
|
104
105
|
initseekmseconds( 0 ),
|
|
105
106
|
ploadtype( L168KPAYLOADTYPE ) {
|
|
106
107
|
|
|
@@ -127,15 +128,13 @@ soundfilereader::soundfilereader( std::string &url ) :
|
|
|
127
128
|
/* read */
|
|
128
129
|
if ( aio_read( &this->cbwavheader ) == -1 ) {
|
|
129
130
|
fprintf( stderr, "aio_read read of header failed in soundfile\n" );
|
|
130
|
-
|
|
131
|
-
this->file = -1;
|
|
131
|
+
this->badheader = true;
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
if ( aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
|
|
136
136
|
fprintf( stderr, "aio_read read of block failed in soundfile" );
|
|
137
|
-
|
|
138
|
-
this->file = -1;
|
|
137
|
+
this->bodyread = true;
|
|
139
138
|
return;
|
|
140
139
|
}
|
|
141
140
|
|
|
@@ -153,8 +152,7 @@ soundfilereader::~soundfilereader() {
|
|
|
153
152
|
# create
|
|
154
153
|
Shared pointer version of us.
|
|
155
154
|
*/
|
|
156
|
-
soundfilereader::pointer soundfilereader::create( std::string url )
|
|
157
|
-
{
|
|
155
|
+
soundfilereader::pointer soundfilereader::create( std::string url ) {
|
|
158
156
|
return pointer( new soundfilereader( url ) );
|
|
159
157
|
}
|
|
160
158
|
|
|
@@ -177,16 +175,17 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
177
175
|
|
|
178
176
|
if( this->badheader ) {
|
|
179
177
|
fprintf( stderr, "Bad wav file\n" );
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if( !this->headerread &&
|
|
184
|
-
aio_error( &this->cbwavheader ) == EINPROGRESS ) {
|
|
185
|
-
fprintf( stderr, "Read of soundfile wav header has not completed\n" );
|
|
186
|
-
return false;
|
|
178
|
+
out.zero();
|
|
179
|
+
return true;
|
|
187
180
|
}
|
|
188
181
|
|
|
189
182
|
if( !this->headerread ) {
|
|
183
|
+
if( aio_error( &this->cbwavheader ) == EINPROGRESS ) {
|
|
184
|
+
fprintf( stderr, "Read of soundfile wav header has not completed\n" );
|
|
185
|
+
out.zero();
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
190
189
|
if( 'W' != this->ourwavheader.wave_header[ 0 ] ) {
|
|
191
190
|
this->badheader = true;
|
|
192
191
|
}
|
|
@@ -197,7 +196,9 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
197
196
|
break;
|
|
198
197
|
default:
|
|
199
198
|
fprintf( stderr, "Bad sample rate in wav\n" );
|
|
200
|
-
|
|
199
|
+
this->badheader = true;
|
|
200
|
+
out.zero();
|
|
201
|
+
return true;
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
this->ploadtype = L168KPAYLOADTYPE;
|
|
@@ -211,7 +212,9 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
211
212
|
this->ploadtype = L1616KPAYLOADTYPE;
|
|
212
213
|
this->blocksize = L16WIDEBANDBYTES;
|
|
213
214
|
} else {
|
|
214
|
-
|
|
215
|
+
this->badheader = true;
|
|
216
|
+
out.zero();
|
|
217
|
+
return true;
|
|
215
218
|
}
|
|
216
219
|
break;
|
|
217
220
|
}
|
|
@@ -236,8 +239,10 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
236
239
|
break;
|
|
237
240
|
}
|
|
238
241
|
default: {
|
|
242
|
+
this->badheader = true;
|
|
243
|
+
out.zero();
|
|
239
244
|
fprintf( stderr, "Bad audio format in wav\n" );
|
|
240
|
-
return
|
|
245
|
+
return true;
|
|
241
246
|
}
|
|
242
247
|
}
|
|
243
248
|
this->headerread = true;
|
|
@@ -245,12 +250,15 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
245
250
|
|
|
246
251
|
if( this->initseekmseconds > 0 ) {
|
|
247
252
|
this->setposition( this->initseekmseconds );
|
|
253
|
+
out.zero();
|
|
248
254
|
return true;
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
if( aio_error( &this->cbwavblock[ this->currentcbindex ] ) == EINPROGRESS ) {
|
|
252
258
|
fprintf( stderr, "Read of soundfile wav block has not completed\n" );
|
|
253
|
-
return
|
|
259
|
+
/* return some silence */
|
|
260
|
+
out.zero();
|
|
261
|
+
return true;
|
|
254
262
|
}
|
|
255
263
|
|
|
256
264
|
/* success? */
|
|
@@ -258,12 +266,20 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
258
266
|
|
|
259
267
|
if( -1 == numbytes ) {
|
|
260
268
|
fprintf( stderr, "Bad call to aio_return\n" );
|
|
261
|
-
|
|
269
|
+
this->bodyread = true;
|
|
270
|
+
out.zero();
|
|
271
|
+
return true;
|
|
262
272
|
}
|
|
263
273
|
|
|
264
274
|
uint8_t *current = ( uint8_t * ) this->cbwavblock[ this->currentcbindex ].aio_buf;
|
|
265
275
|
out = rawsound( current, this->blocksize, this->ploadtype, this->ourwavheader.sample_rate );
|
|
266
276
|
|
|
277
|
+
if( numbytes < this->blocksize ) {
|
|
278
|
+
this->bodyread = true;
|
|
279
|
+
/* TODO if we get a partial read we probably should not zero that part */
|
|
280
|
+
out.zero();
|
|
281
|
+
}
|
|
282
|
+
|
|
267
283
|
/* Get the next block reading */
|
|
268
284
|
auto lastreadoffset = this->cbwavblock[ this->currentcbindex ].aio_offset;
|
|
269
285
|
this->currentcbindex = ( this->currentcbindex + 1 ) % SOUNDFILENUMBUFFERS;
|
|
@@ -277,10 +293,10 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
277
293
|
this->cbwavblock[ this->currentcbindex ].aio_nbytes = this->blocksize;
|
|
278
294
|
|
|
279
295
|
/* read next block */
|
|
280
|
-
if ( aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return
|
|
296
|
+
if ( !this->bodyread && aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
|
|
297
|
+
this->bodyread = true;
|
|
298
|
+
out.zero();
|
|
299
|
+
return true;
|
|
284
300
|
}
|
|
285
301
|
|
|
286
302
|
return true;
|
|
@@ -291,11 +307,10 @@ bool soundfilereader::read( rawsound &out ) {
|
|
|
291
307
|
Have we completed reading the file.
|
|
292
308
|
*/
|
|
293
309
|
bool soundfilereader::complete( void ) {
|
|
294
|
-
if( this->badheader
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return ( this->cbwavblock[ this->currentcbindex ].aio_offset + this->blocksize ) > this->ourwavheader.chunksize;
|
|
310
|
+
if( this->badheader ) return true;
|
|
311
|
+
if( !this->headerread ) return false;
|
|
312
|
+
if( -1 == this->file ) return true;
|
|
313
|
+
return this->bodyread;
|
|
299
314
|
}
|
|
300
315
|
|
|
301
316
|
/*!md
|
|
@@ -315,35 +330,31 @@ void soundfilereader::setposition( long mseconds ) {
|
|
|
315
330
|
this->headerread = true;
|
|
316
331
|
}
|
|
317
332
|
|
|
333
|
+
if( !this->headerread ) {
|
|
334
|
+
this->initseekmseconds = mseconds;
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
318
337
|
|
|
319
|
-
|
|
320
|
-
|
|
338
|
+
this->bodyread = false;
|
|
339
|
+
while( AIO_NOTCANCELED == aio_cancel( this->file, NULL ) );
|
|
321
340
|
|
|
322
|
-
|
|
341
|
+
this->currentcbindex = ( this->currentcbindex + 1 ) % SOUNDFILENUMBUFFERS;
|
|
323
342
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
343
|
+
off_t our_aio_offset = ( this->ourwavheader.bit_depth /*16*/ / 8 ) * ( this->ourwavheader.sample_rate / 1000 ) * mseconds; /* bytes per sample */
|
|
344
|
+
our_aio_offset = ( our_aio_offset / this->blocksize ) * this->blocksize; /* realign to the nearest block */
|
|
345
|
+
our_aio_offset += sizeof( wavheader );
|
|
327
346
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
this->cbwavblock[ i ].aio_fildes = this->file;
|
|
332
|
-
this->cbwavblock[ i ].aio_offset = sizeof( wavheader ) + our_aio_offset + ( i * L16WIDEBANDBYTES );
|
|
333
|
-
this->cbwavblock[ i ].aio_buf = this->buffer + ( i * L16WIDEBANDBYTES );
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/* read ahead */
|
|
337
|
-
this->currentcbindex = 0;
|
|
338
|
-
if ( aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
|
|
339
|
-
close( this->file );
|
|
340
|
-
this->file = -1;
|
|
341
|
-
}
|
|
347
|
+
for( auto i = 0; i < SOUNDFILENUMBUFFERS; i++ ) {
|
|
348
|
+
this->cbwavblock[ ( this->currentcbindex + i ) % SOUNDFILENUMBUFFERS ].aio_offset = our_aio_offset + ( i * L16WIDEBANDBYTES );
|
|
349
|
+
}
|
|
342
350
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
this->
|
|
351
|
+
/* read ahead */
|
|
352
|
+
if ( aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
|
|
353
|
+
this->bodyread = true;
|
|
346
354
|
}
|
|
355
|
+
|
|
356
|
+
this->initseekmseconds = 0;
|
|
357
|
+
|
|
347
358
|
}
|
|
348
359
|
|
|
349
360
|
long soundfilereader::offtomsecs( void ) {
|
|
@@ -423,8 +434,7 @@ soundfilewriter::~soundfilewriter() {
|
|
|
423
434
|
# create
|
|
424
435
|
Shared pointer for writing.
|
|
425
436
|
*/
|
|
426
|
-
soundfilewriter::pointer soundfilewriter::create( std::string &url, int16_t numchannels, int32_t samplerate )
|
|
427
|
-
{
|
|
437
|
+
soundfilewriter::pointer soundfilewriter::create( std::string &url, int16_t numchannels, int32_t samplerate ) {
|
|
428
438
|
return pointer( new soundfilewriter( url, numchannels, samplerate ) );
|
|
429
439
|
}
|
|
430
440
|
|
package/test/interface/pcap.js
CHANGED
|
@@ -132,9 +132,9 @@ module.exports.readpcap = async ( file, maxnumberofpackets = 5000 ) => {
|
|
|
132
132
|
etherpacket.ipv4.udp = {}
|
|
133
133
|
etherpacket.ipv4.udp.srcport = parseInt( toHex( etherpacket.ipv4.data[ 20 ] ) + toHex( etherpacket.ipv4.data[ 21 ] ), 16 )
|
|
134
134
|
etherpacket.ipv4.udp.dstport = parseInt( toHex( etherpacket.ipv4.data[ 22 ] ) + toHex( etherpacket.ipv4.data[ 23 ] ), 16 )
|
|
135
|
-
etherpacket.ipv4.udp.length = parseInt( toHex( etherpacket.ipv4.data[ 24 ] ) + toHex( etherpacket.ipv4.data[ 25 ] ), 16 )
|
|
135
|
+
etherpacket.ipv4.udp.length = parseInt( toHex( etherpacket.ipv4.data[ 24 ] ) + toHex( etherpacket.ipv4.data[ 25 ] ), 16 ) - /* udp header */ 8
|
|
136
136
|
etherpacket.ipv4.udp.checksum = parseInt( toHex( etherpacket.ipv4.data[ 26 ] ) + toHex( etherpacket.ipv4.data[ 27 ] ), 16 )
|
|
137
|
-
etherpacket.ipv4.udp.data = etherpacket.ipv4.data.subarray( 28, 28 + etherpacket.ipv4.
|
|
137
|
+
etherpacket.ipv4.udp.data = etherpacket.ipv4.data.subarray( 28, 28 + etherpacket.ipv4.udp.length )
|
|
138
138
|
break
|
|
139
139
|
case 6:
|
|
140
140
|
/* TCP */
|
|
Binary file
|
|
@@ -5,6 +5,7 @@ const dgram = require( "dgram" )
|
|
|
5
5
|
const projectrtp = require( "../../index" ).projectrtp
|
|
6
6
|
const node = require( "../../lib/node" ).interface
|
|
7
7
|
const server = require( "../../lib/server" ).interface
|
|
8
|
+
const rtputil = require( "../util/rtp" )
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Common channel tester
|
|
@@ -360,15 +361,9 @@ describe( "rtpchannel", function() {
|
|
|
360
361
|
let totalsndiff = 0
|
|
361
362
|
let totaltsdiff = 0
|
|
362
363
|
server.on( "message", function( msg ) {
|
|
363
|
-
|
|
364
|
-
sn =
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
let ts = 0
|
|
368
|
-
ts = msg[ 4 ] << 24
|
|
369
|
-
ts = ts | ( msg[ 5 ] << 16 )
|
|
370
|
-
ts = ts | ( msg[ 6 ] << 8 )
|
|
371
|
-
ts = ts | msg[ 7 ]
|
|
364
|
+
const pk = rtputil.parsepk( msg )
|
|
365
|
+
const sn = pk.sn
|
|
366
|
+
const ts = pk.ts
|
|
372
367
|
|
|
373
368
|
if( -1 !== lastsn ) {
|
|
374
369
|
totalsndiff += sn - lastsn - 1
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
const expect = require( "chai" ).expect
|
|
3
|
-
const projectrtp = require( "../../index
|
|
3
|
+
const projectrtp = require( "../../index" ).projectrtp
|
|
4
4
|
const dgram = require( "dgram" )
|
|
5
5
|
|
|
6
|
-
const pcap = require( "./pcap
|
|
6
|
+
const pcap = require( "./pcap" )
|
|
7
7
|
|
|
8
8
|
/*
|
|
9
9
|
i.e. the RTP payload
|
|
@@ -66,16 +66,14 @@ function sendpk( sn, ts, sendtime, dstport, server, pt = 0, ssrc ) {
|
|
|
66
66
|
/*
|
|
67
67
|
|
|
68
68
|
*/
|
|
69
|
-
function senddtmf( sn, ts, sendtime, dstport, server, endofevent, ev ) {
|
|
69
|
+
function senddtmf( sn, ts, sendtime, dstport, server, endofevent, ev, pt = 101 ) {
|
|
70
70
|
|
|
71
71
|
return setTimeout( () => {
|
|
72
72
|
const ssrc = 25
|
|
73
|
-
const pklength =
|
|
73
|
+
const pklength = 16
|
|
74
74
|
|
|
75
75
|
const header = Buffer.alloc( pklength )
|
|
76
76
|
|
|
77
|
-
const pt = 101
|
|
78
|
-
|
|
79
77
|
header.writeUInt8( 0x80 )
|
|
80
78
|
header.writeUInt8( pt, 1 ) // payload type
|
|
81
79
|
header.writeUInt16BE( ( sn ) % ( 2**16 ), 2 )
|
|
@@ -715,6 +713,149 @@ describe( "dtmf", function() {
|
|
|
715
713
|
} )
|
|
716
714
|
|
|
717
715
|
|
|
716
|
+
it( "mix 2 channels - pcmu <-> pcma and send DTMF different 2833 pt", async function() {
|
|
717
|
+
|
|
718
|
+
/*
|
|
719
|
+
When mixing 2 channels, we expect the second leg to receive the 2833 packets
|
|
720
|
+
and our server to emit events indicating the DTMF on the first channel.
|
|
721
|
+
*/
|
|
722
|
+
this.timeout( 3000 )
|
|
723
|
+
this.slow( 2000 )
|
|
724
|
+
|
|
725
|
+
const endpointa = dgram.createSocket( "udp4" )
|
|
726
|
+
const endpointb = dgram.createSocket( "udp4" )
|
|
727
|
+
|
|
728
|
+
const receivedmessages = []
|
|
729
|
+
|
|
730
|
+
let endpointapkcount = 0
|
|
731
|
+
let endpointbpkcount = 0
|
|
732
|
+
let dtmfpkcount = 0
|
|
733
|
+
|
|
734
|
+
endpointa.on( "message", function( msg ) {
|
|
735
|
+
endpointapkcount++
|
|
736
|
+
expect( msg.length ).to.equal( 172 )
|
|
737
|
+
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
|
|
738
|
+
} )
|
|
739
|
+
|
|
740
|
+
endpointb.on( "message", function( msg ) {
|
|
741
|
+
endpointbpkcount++
|
|
742
|
+
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
|
|
743
|
+
dtmfpkcount++
|
|
744
|
+
} else {
|
|
745
|
+
expect( msg.length ).to.equal( 172 )
|
|
746
|
+
expect( 0x7f & msg [ 1 ] ).to.equal( 8 )
|
|
747
|
+
endpointb.send( msg, channelb.local.port, "localhost" )
|
|
748
|
+
}
|
|
749
|
+
} )
|
|
750
|
+
|
|
751
|
+
endpointa.bind()
|
|
752
|
+
await new Promise( ( resolve ) => { endpointa.on( "listening", function() { resolve() } ) } )
|
|
753
|
+
|
|
754
|
+
endpointb.bind()
|
|
755
|
+
await new Promise( ( resolve ) => { endpointb.on( "listening", function() { resolve() } ) } )
|
|
756
|
+
|
|
757
|
+
let done
|
|
758
|
+
const finished = new Promise( ( r ) => { done = r } )
|
|
759
|
+
|
|
760
|
+
const channela = await projectrtp.openchannel( { "remote": { "address": "localhost", "port": endpointa.address().port, "codec": 0, "rfc2833pt": 127 } }, function( d ) {
|
|
761
|
+
receivedmessages.push( d )
|
|
762
|
+
|
|
763
|
+
if( "close" === d.action ) channelb.close()
|
|
764
|
+
} )
|
|
765
|
+
|
|
766
|
+
const channelb = await projectrtp.openchannel( { "remote": { "address": "localhost", "port": endpointb.address().port, "codec": 8, "rfc2833pt": 101 } }, function( d ) {
|
|
767
|
+
if( "close" === d.action ) done()
|
|
768
|
+
} )
|
|
769
|
+
|
|
770
|
+
/* mix */
|
|
771
|
+
expect( channela.mix( channelb ) ).to.be.true
|
|
772
|
+
|
|
773
|
+
/* send a packet every 20mS x 50 */
|
|
774
|
+
sendpk( 0, 0, 0, channela.local.port, endpointa )
|
|
775
|
+
sendpk( 1, 1*160, 1*20, channela.local.port, endpointa )
|
|
776
|
+
sendpk( 2, 2*160, 2*20, channela.local.port, endpointa )
|
|
777
|
+
sendpk( 3, 3*160, 3*20, channela.local.port, endpointa )
|
|
778
|
+
sendpk( 4, 4*160, 4*20, channela.local.port, endpointa )
|
|
779
|
+
sendpk( 5, 5*160, 5*20, channela.local.port, endpointa )
|
|
780
|
+
sendpk( 6, 6*160, 6*20, channela.local.port, endpointa )
|
|
781
|
+
sendpk( 7, 7*160, 7*20, channela.local.port, endpointa )
|
|
782
|
+
sendpk( 8, 8*160, 8*20, channela.local.port, endpointa )
|
|
783
|
+
sendpk( 9, 9*160, 9*20, channela.local.port, endpointa )
|
|
784
|
+
sendpk( 10, 10*160, 10*20, channela.local.port, endpointa )
|
|
785
|
+
sendpk( 11, 11*160, 11*20, channela.local.port, endpointa )
|
|
786
|
+
sendpk( 12, 12*160, 12*20, channela.local.port, endpointa )
|
|
787
|
+
|
|
788
|
+
senddtmf( 13, 13*160, 13*20, channela.local.port, endpointa, false, "4", 127 )
|
|
789
|
+
sendpk( 14, 13*160, 13*20, channela.local.port, endpointa, 0 )
|
|
790
|
+
sendpk( 15, 14*160, 14*20, channela.local.port, endpointa, 0 )
|
|
791
|
+
senddtmf( 16, (15*160)+10, (15*20)+10, channela.local.port, endpointa, false, "4", 127 )
|
|
792
|
+
sendpk( 17, 15*160, 15*20, channela.local.port, endpointa, 0 )
|
|
793
|
+
sendpk( 18, 16*160, 16*20, channela.local.port, endpointa, 0 )
|
|
794
|
+
senddtmf( 19, (17*160)+20, (17*20)+20, channela.local.port, endpointa, true, "4", 127 )
|
|
795
|
+
sendpk( 20, 17*160, 17*20, channela.local.port, endpointa, 0 )
|
|
796
|
+
sendpk( 21, 18*160, 18*20, channela.local.port, endpointa, 0 )
|
|
797
|
+
senddtmf( 22, (18*160)+30, (18*20)+30, channela.local.port, endpointa, true, "4", 127 )
|
|
798
|
+
sendpk( 23, 19*160, 19*20, channela.local.port, endpointa, 0 )
|
|
799
|
+
sendpk( 24, 20*160, 20*20, channela.local.port, endpointa, 0 )
|
|
800
|
+
sendpk( 25, 21*160, 21*20, channela.local.port, endpointa, 0 )
|
|
801
|
+
sendpk( 26, 22*160, 22*20, channela.local.port, endpointa, 0 )
|
|
802
|
+
sendpk( 27, 23*160, 23*20, channela.local.port, endpointa, 0 )
|
|
803
|
+
sendpk( 28, 24*160, 24*20, channela.local.port, endpointa, 0 )
|
|
804
|
+
sendpk( 29, 25*160, 25*20, channela.local.port, endpointa, 0 )
|
|
805
|
+
|
|
806
|
+
senddtmf( 30, 26*160, 26*20, channela.local.port, endpointa, false, "5", 127 )
|
|
807
|
+
sendpk( 31, 26*160, 26*20, channela.local.port, endpointa, 0 )
|
|
808
|
+
sendpk( 32, 27*160, 27*20, channela.local.port, endpointa, 0 )
|
|
809
|
+
senddtmf( 33, (27*160)+10, (27*20)+10, channela.local.port, endpointa, false, "5", 127 )
|
|
810
|
+
sendpk( 34, 28*160, 28*20, channela.local.port, endpointa, 0 )
|
|
811
|
+
sendpk( 35, 29*160, 28*20, channela.local.port, endpointa, 0 )
|
|
812
|
+
senddtmf( 36, (28*160)+20, (28*20)+20, channela.local.port, endpointa, true, "5", 127 )
|
|
813
|
+
sendpk( 37, 30*160, 29*20, channela.local.port, endpointa, 0 )
|
|
814
|
+
sendpk( 38, 31*160, 30*20, channela.local.port, endpointa, 0 )
|
|
815
|
+
|
|
816
|
+
senddtmf( 39, (38*160)+30, (30*20)+30, channela.local.port, endpointa, true, "5", 127 )
|
|
817
|
+
sendpk( 40, 32*160, 31*20, channela.local.port, endpointa, 0 )
|
|
818
|
+
sendpk( 41, 33*160, 32*20, channela.local.port, endpointa, 0 )
|
|
819
|
+
|
|
820
|
+
sendpk( 42, 34*160, 33*20, channela.local.port, endpointa, 0 )
|
|
821
|
+
sendpk( 43, 35*160, 34*20, channela.local.port, endpointa, 0 )
|
|
822
|
+
sendpk( 44, 36*160, 35*20, channela.local.port, endpointa, 0 )
|
|
823
|
+
sendpk( 45, 37*160, 36*20, channela.local.port, endpointa, 0 )
|
|
824
|
+
sendpk( 46, 38*160, 37*20, channela.local.port, endpointa, 0 )
|
|
825
|
+
sendpk( 47, 39*160, 38*20, channela.local.port, endpointa, 0 )
|
|
826
|
+
sendpk( 48, 40*160, 39*20, channela.local.port, endpointa, 0 )
|
|
827
|
+
sendpk( 49, 51*160, 40*20, channela.local.port, endpointa, 0 )
|
|
828
|
+
|
|
829
|
+
await new Promise( ( r ) => { setTimeout( () => r(), 1400 ) } )
|
|
830
|
+
|
|
831
|
+
channela.close()
|
|
832
|
+
endpointa.close()
|
|
833
|
+
endpointb.close()
|
|
834
|
+
|
|
835
|
+
await finished
|
|
836
|
+
|
|
837
|
+
expect( endpointapkcount ).to.be.within( 30, 51 )
|
|
838
|
+
expect( endpointbpkcount ).to.be.within( 30, 51 )
|
|
839
|
+
|
|
840
|
+
expect( receivedmessages.length ).to.equal( 5 )
|
|
841
|
+
|
|
842
|
+
expect( dtmfpkcount ).to.be.within( 4, 8 )
|
|
843
|
+
|
|
844
|
+
expect( receivedmessages[ 0 ].action ).to.equal( "mix" )
|
|
845
|
+
expect( receivedmessages[ 1 ].action ).to.equal( "telephone-event" )
|
|
846
|
+
expect( receivedmessages[ 2 ].action ).to.equal( "telephone-event" )
|
|
847
|
+
expect( receivedmessages[ 3 ].action ).to.equal( "mix" )
|
|
848
|
+
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
|
|
849
|
+
expect( receivedmessages[ 4 ].action ).to.equal( "close" )
|
|
850
|
+
|
|
851
|
+
expect( receivedmessages[ 0 ].event ).to.equal( "start" )
|
|
852
|
+
expect( receivedmessages[ 1 ].event ).to.equal( "4" )
|
|
853
|
+
expect( receivedmessages[ 2 ].event ).to.equal( "5" )
|
|
854
|
+
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
|
|
855
|
+
|
|
856
|
+
} )
|
|
857
|
+
|
|
858
|
+
|
|
718
859
|
it( "mix 3 channels - pcmu <-> pcma and ilbc and send DTMF", async function() {
|
|
719
860
|
|
|
720
861
|
this.timeout( 3000 )
|