@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.
@@ -5,9 +5,8 @@ const expect = require( "chai" ).expect
5
5
  const dgram = require( "dgram" )
6
6
  const projectrtp = require( "../../index.js" ).projectrtp
7
7
 
8
- function sendpk( sn, sendtime, dstport, server, data = undefined ) {
8
+ function sendpk( sn, sendtime, dstport, server, data = undefined, pt = 0, ssrc = 25 ) {
9
9
 
10
- const ssrc = 25
11
10
  const pklength = 172
12
11
 
13
12
  return setTimeout( () => {
@@ -27,8 +26,11 @@ function sendpk( sn, sendtime, dstport, server, data = undefined ) {
27
26
  subheader.writeUInt32BE( ts, 2 )
28
27
  subheader.writeUInt32BE( ssrc, 6 )
29
28
 
29
+ const header = Buffer.from( [ 0x80, 0x00 ] )
30
+ header.writeUInt8( pt, 1 ) // payload type
31
+
30
32
  const rtppacket = Buffer.concat( [
31
- Buffer.from( [ 0x80, 0x00 ] ),
33
+ header,
32
34
  subheader,
33
35
  payload ] )
34
36
 
@@ -101,6 +103,75 @@ describe( "channel mix", function() {
101
103
 
102
104
  } )
103
105
 
106
+ it( "basic mix 2 channels with start 2 packets wrong payload type", async function() {
107
+
108
+ this.timeout( 3000 )
109
+ this.slow( 2000 )
110
+
111
+ const endpointa = dgram.createSocket( "udp4" )
112
+ const endpointb = dgram.createSocket( "udp4" )
113
+
114
+ let endpointapkcount = 0
115
+ let endpointbpkcount = 0
116
+
117
+ endpointa.on( "message", function( msg ) {
118
+ endpointapkcount++
119
+ expect( msg.length ).to.equal( 172 )
120
+ expect( 0x7f & msg [ 1 ] ).to.equal( 8 )
121
+ } )
122
+
123
+ endpointb.on( "message", function( msg ) {
124
+ endpointbpkcount++
125
+
126
+ expect( msg.length ).to.equal( 172 )
127
+ expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
128
+ endpointb.send( msg, channelb.local.port, "localhost" )
129
+ } )
130
+
131
+ endpointa.bind()
132
+ await new Promise( ( r ) => { endpointa.on( "listening", function() { r() } ) } )
133
+
134
+ endpointb.bind()
135
+ await new Promise( ( r ) => { endpointb.on( "listening", function() { r() } ) } )
136
+
137
+ let done
138
+ const finished = new Promise( ( r ) => { done = r } )
139
+
140
+ const channela = await projectrtp.openchannel( {}, function( d ) {
141
+ if( "close" === d.action ) channelb.close()
142
+ } )
143
+
144
+ const channelb = await projectrtp.openchannel( { "remote": { "address": "localhost", "port": endpointb.address().port, "codec": 0 } }, function( d ) {
145
+ if( "close" === d.action ) done()
146
+ } )
147
+
148
+ /* mix */
149
+ expect( channela.mix( channelb ) ).to.be.true
150
+
151
+ /* a problem was highlighted that would remote would be called before rtp stream was updated */
152
+ channela.remote( { "address": "localhost", "port": endpointa.address().port, "codec": 8 } )
153
+
154
+ sendpk( 0, 0, channela.local.port, endpointa )
155
+ sendpk( 1, 1, channela.local.port, endpointa )
156
+
157
+ /* Now, when we send UDP on endpointb it passes through our mix then arrives at endpointa */
158
+ for( let i = 2; 50 > i; i ++ ) {
159
+ sendpk( i, i, channela.local.port, endpointa, undefined, 8, 27 )
160
+ }
161
+
162
+ await new Promise( ( resolve ) => { setTimeout( () => resolve(), 1300 ) } )
163
+
164
+ channela.close()
165
+ endpointa.close()
166
+ endpointb.close()
167
+
168
+ expect( endpointapkcount ).to.be.within( 30, 51 )
169
+ expect( endpointbpkcount ).to.be.within( 30, 51 )
170
+
171
+ await finished
172
+
173
+ } )
174
+
104
175
 
105
176
  it( "mix 2 channels then unmix", async function() {
106
177
 
@@ -900,9 +971,9 @@ describe( "channel mix", function() {
900
971
  endpointb.close()
901
972
  endpointc.close()
902
973
 
903
- expect( endpointapkcountzero ).to.be.within( 65, 75 )
904
- expect( endpointbpkcountzero ).to.be.within( 65, 75 )
905
- expect( endpointcpkcountzero ).to.be.within( 65, 75 )
974
+ expect( endpointapkcountzero ).to.be.within( 60, 75 )
975
+ expect( endpointbpkcountzero ).to.be.within( 60, 75 )
976
+ expect( endpointcpkcountzero ).to.be.within( 60, 75 )
906
977
  expect( endpointapkcountnotzero ).to.be.within( 4, 12 )
907
978
  expect( endpointbpkcountnotzero ).to.be.within( 4, 12 )
908
979
  expect( endpointcpkcountnotzero ).to.be.below( 2 )
@@ -1,4 +1,9 @@
1
1
 
2
+
3
+ //const npl = require( "nodeplotlib" )
4
+ // eslint-disable-next-line no-unused-vars
5
+ const npl = { plot: ( /** @type {any} */ a ) => {} }
6
+
2
7
  /*
3
8
  Note, timing in Node doesn't appear that accurate. This requires more work if
4
9
  we can measure jitter. The pcap traces show 0.01 mS jitter but we are getting 4mS
@@ -8,7 +13,48 @@ when playing in node. For now, leave checking of timing.
8
13
  const expect = require( "chai" ).expect
9
14
  const fs = require( "fs" )
10
15
  const dgram = require( "dgram" )
11
- const prtp = require( "../../index.js" )
16
+ const prtp = require( "../../index" )
17
+ const rtputils = require( "../util/rtp" )
18
+
19
+ function gensignal( hz, datalength, magnitude ) {
20
+
21
+ const y = Buffer.alloc( datalength * 2 )
22
+
23
+ for( let i = 0; i < datalength; i ++ ) {
24
+ y.writeInt16LE( Math.sin( i * ( Math.PI * 2 * ( 1 / 8000 ) ) * hz ) * magnitude, i * 2 )
25
+ }
26
+
27
+ return y
28
+ }
29
+
30
+ /**
31
+ *
32
+ * @param { Array< number > } inarray
33
+ * @returns { Int16Array }
34
+ */
35
+ function pcmutolinear( inarray ) {
36
+ const out = new Int16Array( inarray.length )
37
+ for( let i = 0; i < inarray.length; i++ ) {
38
+ out[ i ] = prtp.projectrtp.codecx.pcmu2linear16( inarray[ i ] )
39
+ }
40
+
41
+ return out
42
+ }
43
+
44
+ /**
45
+ * Limitation of not parsing ccrc.
46
+ * @param { Buffer } packet
47
+ * @return { object }
48
+ */
49
+ function parsertppk( packet ) {
50
+ return {
51
+ sn: packet.readUInt16BE( 2 ),
52
+ ts: packet.readUInt32BE( 4 ),
53
+ pt: packet.readUInt8( 1 ) & 0x7f,
54
+ ssrc: packet.readUInt32BE( 8 ),
55
+ payload: new Uint8Array( packet.slice( 12 ) )
56
+ }
57
+ }
12
58
 
13
59
  /**
14
60
  * @param { number } samples
@@ -75,13 +121,16 @@ describe( "rtpsound", function() {
75
121
  /* create our RTP/UDP endpoint */
76
122
  const server = dgram.createSocket( "udp4" )
77
123
  let receviedpkcount = 0
124
+ let receivedcorrectvalue = 0
78
125
 
79
126
  /** @type { prtp.channel } */
80
127
  let channel
81
128
 
82
129
  server.on( "message", function( msg ) {
83
130
  /* This is PCMA encoded data from our flat file */
84
- expect( msg[ 16 ] ).to.equal( 0x99 )
131
+ const pk = parsertppk( msg )
132
+ /* we can also receive silence */
133
+ if( 228 == pk.payload[ 10 ] ) receivedcorrectvalue++
85
134
  receviedpkcount++
86
135
  } )
87
136
 
@@ -114,10 +163,11 @@ describe( "rtpsound", function() {
114
163
 
115
164
  await finished
116
165
 
117
- expect( receviedpkcount ).to.be.within( 48, 50 )
166
+ expect( receviedpkcount ).to.be.within( 48, 60 )
167
+ expect( receivedcorrectvalue ).to.be.within( 48, 60 )
118
168
  } )
119
169
 
120
- it( "loop in soundsoup and check udp data", function( done ) {
170
+ it( "loop in soundsoup and check udp data", async function() {
121
171
 
122
172
  this.timeout( 6000 )
123
173
  this.slow( 5000 )
@@ -125,45 +175,52 @@ describe( "rtpsound", function() {
125
175
  /* create our RTP/UDP endpoint */
126
176
  const server = dgram.createSocket( "udp4" )
127
177
  let receviedpkcount = 0
128
- let channel
178
+ let correctvalcount = 0
179
+ let done, cleanedup
180
+ const completpromise = new Promise( resolve => done = resolve )
181
+ const cleanedpromise = new Promise( resolve => cleanedup = resolve )
129
182
 
130
183
  server.on( "message", function( msg ) {
131
184
 
132
185
  /* This is PCMA encoded data from our flat file */
133
- expect( msg[ 16 ] ).to.equal( 0x99 )
186
+ if( 228 == msg[ 16 ] ) correctvalcount++
134
187
  receviedpkcount++
135
188
  /*
136
189
  flat.wav has 1 S of audio (8000 samples). 160 per packet compressed = 320 PCM.
137
190
  200 packets is 64000 samples so this must have looped to work.
138
191
  */
139
192
  if( 220 < receviedpkcount ) {
140
- channel.close()
193
+ done()
141
194
  }
142
195
  } )
143
196
 
144
197
  server.bind()
145
- server.on( "listening", async function() {
198
+ await new Promise( resolve => server.on( "listening", resolve ) )
146
199
 
147
- const ourport = server.address().port
200
+ const ourport = server.address().port
148
201
 
149
- channel = await prtp.projectrtp.openchannel( { "remote": { "address": "localhost", "port": ourport, "codec": 0 } }, function( d ) {
202
+ const channel = await prtp.projectrtp.openchannel( { "remote": { "address": "localhost", "port": ourport, "codec": 0 } }, function( d ) {
203
+ if( "close" == d.action ) cleanedup()
204
+ } )
150
205
 
151
- if( "close" === d.action ) {
152
- server.close()
153
- done()
154
- }
155
- } )
206
+ expect( channel.play( {
207
+ "loop": true,
208
+ "files": [
209
+ { "wav": "/tmp/flat.wav" }
210
+ ]
211
+ } ) ).to.be.true
156
212
 
157
- expect( channel.play( {
158
- "loop": true,
159
- "files": [
160
- { "wav": "/tmp/flat.wav" }
161
- ]
162
- } ) ).to.be.true
213
+ await completpromise
163
214
 
164
- } )
215
+ channel.close()
216
+ server.close()
217
+
218
+ await cleanedpromise
219
+ expect( correctvalcount ).to.be.above( 210 )
165
220
  } )
166
221
 
222
+ /* I have also used this test to play with file codec conversion to check it is working properly */
223
+
167
224
  it( "loop in soundsoup file and check udp data", function( done ) {
168
225
 
169
226
  this.timeout( 6000 )
@@ -174,10 +231,12 @@ describe( "rtpsound", function() {
174
231
  let receviedpkcount = 0
175
232
  let channel
176
233
 
234
+ let receivedpcmu = []
177
235
  server.on( "message", function( msg ) {
236
+ receivedpcmu = [ ...receivedpcmu, ...Array.from( pcmutolinear( rtputils.parsepk( msg ).payload ) ) ]
178
237
 
179
238
  /* This is PCMA encoded data from our flat file */
180
- expect( msg[ 16 ] ).to.equal( 0x99 )
239
+ //expect( msg[ 16 ] ).to.equal( 0x99 )
181
240
 
182
241
  receviedpkcount++
183
242
  /*
@@ -199,13 +258,20 @@ describe( "rtpsound", function() {
199
258
 
200
259
  if( "close" === d.action ) {
201
260
  server.close()
261
+
262
+ npl.plot( [ {
263
+ y: receivedpcmu,
264
+ type: "scatter"
265
+ } ] )
266
+
267
+
202
268
  done()
203
269
  }
204
270
  } )
205
271
 
206
272
  expect( channel.play( {
207
273
  "files": [
208
- { "loop": true, "wav": "/tmp/flat.wav" }
274
+ { "loop": true, "wav": "/tmp/440sine.wav" }
209
275
  ]
210
276
  } ) ).to.be.true
211
277
 
@@ -220,6 +286,7 @@ describe( "rtpsound", function() {
220
286
  /* create our RTP/UDP endpoint */
221
287
  const server = dgram.createSocket( "udp4" )
222
288
  let receviedpkcount = 0
289
+ let receviedgoodcount = 0
223
290
 
224
291
  /** @type { prtp.channel } */
225
292
  let channel
@@ -232,8 +299,7 @@ describe( "rtpsound", function() {
232
299
  receviedpkcount++
233
300
 
234
301
  /* This is PCMA encoded data from our flat file */
235
- expect( msg[ 17 ] ).to.equal( 153 /* 0x99 */ )
236
- expect( msg[ 150 ] ).to.equal( 153 /* 0x99 */ )
302
+ if( 228 == msg[ 17 ] ) receviedgoodcount++
237
303
  } )
238
304
 
239
305
  server.bind()
@@ -258,7 +324,8 @@ describe( "rtpsound", function() {
258
324
  8000 samples looped twice. 100 packets (50 packets/S).
259
325
  */
260
326
 
261
- expect( receviedpkcount ).to.be.within( 97, 100 )
327
+ expect( receviedpkcount ).to.above( 90 )
328
+ expect( receviedgoodcount ).to.be.above( 90 )
262
329
  } )
263
330
 
264
331
  it( "slightly more complex soundsoup file and check udp data", async function() {
@@ -270,73 +337,61 @@ describe( "rtpsound", function() {
270
337
  const server = dgram.createSocket( "udp4" )
271
338
  let receviedpkcount = 0
272
339
 
273
- /** @type { prtp.channel } */
274
- let channel
340
+ let enoughpackets
341
+ const enoughpacketspromise = new Promise( resolve => enoughpackets = resolve )
275
342
 
276
343
  let done
277
344
  const finished = new Promise( ( r ) => { done = r } )
278
345
 
346
+ // eslint-disable-next-line complexity
279
347
  server.on( "message", function( msg ) {
280
348
 
281
349
  receviedpkcount++
282
-
283
- /* This is PCMA encoded data from our soundsoup:
284
- { "loop": 2, "files": [
285
- { "wav": "/tmp/flat.wav", "loop": 2 },
286
- { "wav": "/tmp/flat2.wav" },
287
- { "wav": "/tmp/flat.wav" },
288
- { "wav": "/tmp/flat3.wav", "start": 40, "stop": 60 }, should be 2 packets
289
- ] }
290
- */
291
- if( 75 == receviedpkcount ) {
292
- /* flat.wav */
293
- expect( msg[ 17 ] ).to.equal( 153 /* 0x99 */ )
294
- expect( msg[ 150 ] ).to.equal( 153 /* 0x99 */ )
295
- } else if( 125 == receviedpkcount ) {
296
- /* flat2.wav */
297
- expect( msg[ 17 ] ).to.equal( 3 )
298
- expect( msg[ 150 ] ).to.equal( 3 )
299
- } else if( 175 == receviedpkcount ) {
300
- /* flat.wav */
301
- expect( msg[ 17 ] ).to.equal( 153 /* 0x99 */ )
302
- expect( msg[ 150 ] ).to.equal( 153 /* 0x99 */ )
303
- } else if( 250 == receviedpkcount ) {
304
- /* flat.wav */
305
- expect( msg[ 17 ] ).to.equal( 153 )
306
- expect( msg[ 150 ] ).to.equal( 153 )
307
- } else if( 325 == receviedpkcount ) {
350
+ const secondouterloopoffset = 205
351
+
352
+ /* This is PCMA encoded data from our soundsoup */
353
+ if( 25 == receviedpkcount || ( 25 + secondouterloopoffset ) == receviedpkcount ) {
354
+ /* flat.wav first loop */
355
+ expect( msg[ 17 ] ).to.equal( 228 )
356
+ expect( msg[ 150 ] ).to.equal( 228 )
357
+ } else if( 75 == receviedpkcount || ( 75 + secondouterloopoffset ) == receviedpkcount ) {
358
+ /* flat.wav second loop */
359
+ expect( msg[ 17 ] ).to.equal( 228 )
360
+ expect( msg[ 150 ] ).to.equal( 228 )
361
+ } else if( 125 == receviedpkcount || ( 125 + secondouterloopoffset ) == receviedpkcount ) {
308
362
  /* flat2.wav */
309
- expect( msg[ 17 ] ).to.equal( 3 )
310
- expect( msg[ 150 ] ).to.equal( 3 )
311
- } else if( 375 == receviedpkcount ) {
363
+ expect( msg[ 17 ] ).to.equal( 223 )
364
+ expect( msg[ 150 ] ).to.equal( 223 )
365
+ } else if( 175 == receviedpkcount || ( 175 + secondouterloopoffset ) == receviedpkcount ) {
312
366
  /* flat.wav */
313
- expect( msg[ 17 ] ).to.equal( 153 )
314
- expect( msg[ 150 ] ).to.equal( 153 )
315
- } else if( 403 == receviedpkcount ) {
367
+ expect( msg[ 17 ] ).to.equal( 228 )
368
+ expect( msg[ 150 ] ).to.equal( 228 )
369
+ } else if( 206 == receviedpkcount || 413 == receviedpkcount ) {
316
370
  /* flat3.wav */
317
- expect( msg[ 17 ] ).to.equal( 54 )
318
- expect( msg[ 150 ] ).to.equal( 54 )
371
+ expect( msg[ 17 ] ).to.equal( 220 )
372
+ expect( msg[ 150 ] ).to.equal( 220 )
373
+ } else if( ( 207 * 2 ) == receviedpkcount ) {
374
+ enoughpackets()
319
375
  }
320
376
  } )
321
377
 
322
378
  server.bind()
323
- server.on( "listening", async function() {
324
-
325
- const ourport = server.address().port
379
+ await new Promise( resolve => server.on( "listening", resolve ) )
326
380
 
327
- channel = await prtp.projectrtp.openchannel( { "remote": { "address": "localhost", "port": ourport, "codec": 0 } }, function( d ) {
328
- if( "close" === d.action ) done()
329
- } )
381
+ const ourport = server.address().port
330
382
 
331
- expect( channel.play( { "loop": 2, "files": [
332
- { "wav": "/tmp/flat.wav", "loop": 2 },
333
- { "wav": "/tmp/flat2.wav" },
334
- { "wav": "/tmp/flat.wav" },
335
- { "wav": "/tmp/flat3.wav", "start": 40, "stop": 60 }, /* should be 2 packets */
336
- ] } ) ).to.be.true
383
+ const channel = await prtp.projectrtp.openchannel( { "remote": { "address": "localhost", "port": ourport, "codec": 0 } }, function( d ) {
384
+ if( "close" === d.action ) done()
337
385
  } )
338
386
 
339
- await new Promise( ( resolve ) => { setTimeout( () => resolve(), 9000 ) } )
387
+ expect( channel.play( { "loop": 2, "files": [
388
+ { "wav": "/tmp/flat.wav", "loop": 2 },
389
+ { "wav": "/tmp/flat2.wav" },
390
+ { "wav": "/tmp/flat.wav" },
391
+ { "wav": "/tmp/flat3.wav", "start": 40, "stop": 100 }, /* should be 4 packets */
392
+ ] } ) ).to.be.true
393
+
394
+ await enoughpacketspromise
340
395
  channel.close()
341
396
  server.close()
342
397
 
@@ -345,7 +400,7 @@ describe( "rtpsound", function() {
345
400
  /*
346
401
  8000 samples looped twice with 3 sections to play. 400 packets (50 packets/S).
347
402
  */
348
- expect( receviedpkcount ).to.be.within( 390, 405 )
403
+ expect( receviedpkcount ).to.be.above( 400 )
349
404
  } )
350
405
 
351
406
  before( async () => {
@@ -355,35 +410,34 @@ describe( "rtpsound", function() {
355
410
  const wavheader = createwavheader( samples )
356
411
  const values = Buffer.alloc( samples * bytespersample )
357
412
  for( let i = 0; i < samples; i++ ) {
358
- values.writeUInt16BE( 300, i * 2 )
413
+ values.writeUInt16LE( 300, i * 2 )
359
414
  }
360
415
  /* Put a marker at the start of the file */
361
- values.writeUInt16BE( 1000, 50 )
416
+ values.writeUInt16LE( 1000, 50 )
362
417
 
363
- await fs.writeFile( "/tmp/flat.wav", Buffer.concat( [ wavheader, values ] ), function() {} )
418
+ await fs.promises.writeFile( "/tmp/flat.wav", Buffer.concat( [ wavheader, values ] ) )
364
419
 
365
420
  for( let i = 0; i < samples; i++ ) {
366
- values.writeUInt16BE( 400, i * 2 )
421
+ values.writeUInt16LE( 400, i * 2 )
367
422
  }
368
423
 
369
- await fs.writeFile( "/tmp/flat2.wav", Buffer.concat( [ wavheader, values ] ), function() {} )
424
+ await fs.promises.writeFile( "/tmp/flat2.wav", Buffer.concat( [ wavheader, values ] ) )
370
425
 
371
426
  for( let i = 0; i < samples; i++ ) {
372
- values.writeUInt16BE( 0, i * 2 )
427
+ values.writeUInt16LE( 500, i * 2 )
373
428
  }
374
429
 
430
+ await fs.promises.writeFile( "/tmp/flat3.wav", Buffer.concat( [ wavheader, values ] ) )
375
431
 
376
- for( let i = 0; 320 > i; i++ ) {
377
- values.writeUInt16BE( 500, 640 + ( i * 2 ) )
378
- }
379
-
380
- await fs.writeFile( "/tmp/flat3.wav", Buffer.concat( [ wavheader, values ] ), function() {} )
432
+ const sig = gensignal( 440, 8000, 1000 )
433
+ await fs.promises.writeFile( "/tmp/440sine.wav", Buffer.concat( [ wavheader, sig ] ) )
381
434
 
382
435
  } )
383
436
 
384
437
  after( async () => {
385
- await new Promise( ( resolve ) => { fs.unlink( "/tmp/flat.wav", () => { resolve() } ) } )
386
- await new Promise( ( resolve ) => { fs.unlink( "/tmp/flat2.wav", () => { resolve() } ) } )
387
- await new Promise( ( resolve ) => { fs.unlink( "/tmp/flat3.wav", () => { resolve() } ) } )
438
+ await fs.promises.unlink( "/tmp/flat.wav" )
439
+ await fs.promises.unlink( "/tmp/flat2.wav" )
440
+ await fs.promises.unlink( "/tmp/flat3.wav" )
441
+ await fs.promises.unlink( "/tmp/440sine.wav" )
388
442
  } )
389
443
  } )
@@ -9,6 +9,7 @@ const projectrtp = require( "../../index" ).projectrtp
9
9
  const expect = require( "chai" ).expect
10
10
  const dgram = require( "dgram" )
11
11
  const fs = require( "fs" )
12
+ const pcap = require( "./pcap" )
12
13
 
13
14
 
14
15
  /*
@@ -167,6 +168,20 @@ function pcmutolinear( inarray ) {
167
168
  return out
168
169
  }
169
170
 
171
+ /**
172
+ * Send Buffer to server at required time
173
+ * @param { number } sendtime
174
+ * @param { Buffer } pk
175
+ * @param { number } dstport
176
+ * @param { dgram.Socket } server
177
+ * @returns
178
+ */
179
+ function sendpayload( sendtime, pk, dstport, server ) {
180
+ return setTimeout( () => {
181
+ server.send( pk, dstport, "localhost" )
182
+ }, sendtime )
183
+ }
184
+
170
185
  /**
171
186
  *
172
187
  * @param { number } sn - should start from 0 which we use to index into the supplied data buffer
@@ -653,5 +668,154 @@ describe( "Transcode", function() {
653
668
 
654
669
  await fs.promises.unlink( "/tmp/ukringing.wav" ).catch( () => {} )
655
670
  } )
671
+
672
+ it( "replay captured g722 from poly", async () => {
673
+
674
+ const g722endpoint = dgram.createSocket( "udp4" )
675
+ g722endpoint.on( "message", function() {} )
676
+
677
+ const pcmuendpoint = dgram.createSocket( "udp4" )
678
+ let receivedpcmu = []
679
+ pcmuendpoint.on( "message", function( msg ) {
680
+ pcmuendpoint.send( msg, pcmuchannel.local.port, "localhost" )
681
+
682
+ receivedpcmu = [ ...receivedpcmu, ...Array.from( pcmutolinear( parsepk( msg ).payload ) ) ]
683
+ } )
684
+
685
+ g722endpoint.bind()
686
+ await new Promise( resolve => g722endpoint.on( "listening", resolve ) )
687
+ pcmuendpoint.bind()
688
+ await new Promise( resolve => pcmuendpoint.on( "listening", resolve ) )
689
+
690
+ const allstats = {}
691
+
692
+ const g722channel = await projectrtp.openchannel( { "id": "4", "remote": { "address": "localhost", "port": g722endpoint.address().port, "codec": 9 } }, function( d ) {
693
+ if( "close" === d.action ) {
694
+ g722endpoint.close()
695
+ pcmuendpoint.close()
696
+ pcmuchannel.close()
697
+ allstats.achannel = { stats: d.stats }
698
+ }
699
+ } )
700
+
701
+ let done
702
+ const allclose = new Promise( resolve => done = resolve )
703
+ const pcmuchannel = await projectrtp.openchannel( { "id": "4", "remote": { "address": "localhost", "port": pcmuendpoint.address().port, "codec": 0 } }, function( d ) {
704
+ if( "close" === d.action ) {
705
+ allstats.bchannel = { stats: d.stats }
706
+ done()
707
+ }
708
+ } )
709
+
710
+ const ourpcap = ( await pcap.readpcap( "test/interface/pcaps/440hzinbackgroundg722.pcap" ) ).slice( 0, 50 )
711
+
712
+ g722channel.mix( pcmuchannel )
713
+
714
+ const offset = 0
715
+ ourpcap.forEach( ( packet ) => {
716
+ if( packet.ipv4 && packet.ipv4.udp && 10018 == packet.ipv4.udp.dstport ) {
717
+ sendpayload( ( 1000 * packet.ts_sec_offset ) - offset, packet.ipv4.udp.data, g722channel.local.port, g722endpoint )
718
+ }
719
+ } )
720
+
721
+ await new Promise( resolve => setTimeout( resolve, 1400 ) )
722
+ g722channel.close()
723
+ await allclose
724
+
725
+ npl.plot( [ {
726
+ y: Array.from( receivedpcmu ),
727
+ type: "scatter"
728
+ } ] )
729
+
730
+ const amps = ampbyfrequency( Int16Array.from( receivedpcmu ) )
731
+ const bin = 225
732
+ expect( 20000 < amps[ bin ] ).to.be.true
733
+
734
+ npl.plot( [ {
735
+ y: Array.from( amps ),
736
+ type: "scatter"
737
+ } ] )
738
+
739
+ } )
740
+
741
+ it( "replay captured g722 no transcode from poly 3 way mix", async () => {
742
+
743
+ const g722endpoint = dgram.createSocket( "udp4" )
744
+ g722endpoint.on( "message", function() {} )
745
+
746
+ const pcmuendpoint = dgram.createSocket( "udp4" )
747
+ let receivedpcmu = []
748
+
749
+ pcmuendpoint.on( "message", function( msg ) {
750
+ pcmuendpoint.send( msg, pcmuchannel.local.port, "localhost" )
751
+
752
+ receivedpcmu = [ ...receivedpcmu, ...Array.from( pcmutolinear( parsepk( msg ).payload ) ) ]
753
+ } )
754
+
755
+ g722endpoint.bind()
756
+ await new Promise( resolve => g722endpoint.on( "listening", resolve ) )
757
+ pcmuendpoint.bind()
758
+ await new Promise( resolve => pcmuendpoint.on( "listening", resolve ) )
759
+
760
+ const allstats = {}
761
+
762
+ const g722channel = await projectrtp.openchannel( { "id": "4", "remote": { "address": "localhost", "port": g722endpoint.address().port, "codec": 9 } }, function( d ) {
763
+ if( "close" === d.action ) {
764
+ g722endpoint.close()
765
+ pcmuendpoint.close()
766
+ pcmuchannel.close()
767
+ secondg722.close()
768
+ allstats.achannel = { stats: d.stats }
769
+ }
770
+ } )
771
+
772
+ let done
773
+ const allclose = new Promise( resolve => done = resolve )
774
+ const pcmuchannel = await projectrtp.openchannel( { "id": "4", "remote": { "address": "localhost", "port": pcmuendpoint.address().port, "codec": 0 } }, function( d ) {
775
+ if( "close" === d.action ) {
776
+ allstats.bchannel = { stats: d.stats }
777
+ done()
778
+ }
779
+ } )
780
+
781
+ const secondg722 = await projectrtp.openchannel( { "id": "4", "remote": { "address": "localhost", "port": 9990, "codec": 9 } }, function( d ) {
782
+ if( "close" === d.action ) {
783
+ allstats.bchannel = { stats: d.stats }
784
+ done()
785
+ }
786
+ } )
787
+
788
+ const ourpcap = ( await pcap.readpcap( "test/interface/pcaps/440hzinbackgroundg722.pcap" ) ).slice( 0, 50 )
789
+
790
+ g722channel.mix( pcmuchannel )
791
+ g722channel.mix( secondg722 )
792
+
793
+ const offset = 0
794
+ ourpcap.forEach( ( packet ) => {
795
+ if( packet.ipv4 && packet.ipv4.udp && 10018 == packet.ipv4.udp.dstport ) {
796
+ sendpayload( ( 1000 * packet.ts_sec_offset ) - offset, packet.ipv4.udp.data, g722channel.local.port, g722endpoint )
797
+ }
798
+ } )
799
+
800
+ await new Promise( resolve => setTimeout( resolve, 1400 ) )
801
+ g722channel.close()
802
+ await allclose
803
+
804
+ npl.plot( [ {
805
+ y: Array.from( receivedpcmu ),
806
+ type: "scatter"
807
+ } ] )
808
+
809
+ const amps = ampbyfrequency( Int16Array.from( receivedpcmu ) )
810
+
811
+ npl.plot( [ {
812
+ y: Array.from( amps ),
813
+ type: "scatter"
814
+ } ] )
815
+
816
+ const bin = 430
817
+ expect( 20000 < amps[ bin ] ).to.be.true
818
+
819
+ } )
656
820
  } )
657
821