@babblevoice/projectrtp
Version:
A scalable Node addon RTP server
1,309 lines (1,030 loc) • 56 kB
JavaScript
const expect = require( "chai" ).expect
const projectrtp = require( "../../index" ).projectrtp
const dgram = require( "dgram" )
const pcap = require( "./pcap" )
const pkcountperdtmfdigit = 14 /* defined in projectrtpchannel::senddtmf */
const pausebetweendtmfdigits = 200 /* mS 10 pks ref projectrtpchannel::senddtmf */
const timeperdtmfdigit = ( pkcountperdtmfdigit * 20 /* mS */ ) + pausebetweendtmfdigits
const dtmfeventduration = ( ( pkcountperdtmfdigit - 2) * 160 )
/*
i.e. the RTP payload
str = "80 e5 03 b5 00 02 44 a0 1e e3 61 fb 03 0a 00 a0 4c d1"
returns
Buffer.from( [ 0x80, ... ] )
*/
function fromstr( str ) {
const retval = []
str.split( " " ).forEach( v => retval.push ( parseInt( v, 16 ) ) )
return Buffer.from( retval )
}
function sendpayload( sendtime, pk, dstport, server ) {
return setTimeout( () => {
/* Pcap replays schedule the full capture up front and then close
the channel at a fixed deadline. Any packet whose sendtime lands
after that deadline fires on a closed socket; without a guard
the synchronous ERR_SOCKET_DGRAM_NOT_RUNNING bleeds into the
NEXT test as an uncaught error. Silently drop. */
try {
server.send( pk, dstport, "localhost" )
} catch ( e ) {
if( "ERR_SOCKET_DGRAM_NOT_RUNNING" !== e.code ) throw e
}
}, sendtime )
}
/**
* Limitation of not parsing ccrc.
* @param { Buffer } packet
* @return { object }
*/
function parsepk( packet ) {
return {
sn: packet.readUInt16BE( 2 ),
ts: packet.readUInt32BE( 4 ),
pt: packet.readUInt8( 1 ) & 0x7f,
ssrc: packet.readUInt32BE( 8 ),
payload: new Uint8Array( packet.slice( 12 ) )
}
}
/**
* Limitation of not parsing ccrc.
* @param { Buffer } packet
* @return { object }
*/
function parse2833pk( packet ) {
return {
sn: packet.readUInt16BE( 2 ),
ts: packet.readUInt32BE( 4 ),
pt: packet.readUInt8( 1 ) & 0x7f,
ssrc: packet.readUInt32BE( 8 ),
event: {
id: packet.readUInt8( 12 ),
eoe: ( packet.readUInt8( 13 ) & 0x80 ) == 0x80,
volume: packet.readUInt8( 13 ) & 0x7f,
duration: packet.readUInt16BE( 14 ),
}
}
}
/* helper functions */
function sendpk( sn, ts, sendtime, dstport, server, pt = 0, ssrc ) {
if( !ssrc ) ssrc = 25
const pklength = 172
return setTimeout( () => {
const payload = Buffer.alloc( pklength - 12 ).fill( projectrtp.codecx.linear162pcmu( sn ) & 0xff )
const subheader = Buffer.alloc( 10 )
subheader.writeUInt8( pt, 1 ) // payload type
subheader.writeUInt16BE( ( sn ) % ( 2**16 ) )
subheader.writeUInt32BE( ts, 2 )
subheader.writeUInt32BE( ssrc, 6 )
const rtppacket = Buffer.concat( [
Buffer.from( [ 0x80, 0x00 ] ),
subheader,
payload ] )
server.send( rtppacket, dstport, "localhost" )
}, sendtime )
}
/*
*/
function senddtmf( sn, ts, sendtime, dstport, server, endofevent, ev, pt = 101 ) {
return setTimeout( () => {
const ssrc = 25
const pklength = 16
const header = Buffer.alloc( pklength )
header.writeUInt8( 0x80 )
header.writeUInt8( pt, 1 ) // payload type
header.writeUInt16BE( ( sn ) % ( 2**16 ), 2 )
header.writeUInt32BE( ts, 4 )
header.writeUInt32BE( ssrc, 8 )
/* DTMF data */
header.writeUInt8( ev, 12 )
let eoerv = 10
if( endofevent ) {
eoerv = eoerv | 0x80
}
header.writeUInt8( eoerv, 13 ) /* End of Event, Reserved, Volume */
header.writeUInt16BE( 160, 14 ) /* Duration */
server.send( header, dstport, "localhost" )
}, sendtime )
}
/* Tests */
describe( "dtmf", function() {
it( "Send 2833 DTMF and check event", function( done ) {
/* create our RTP/UDP endpoint */
const server = dgram.createSocket( "udp4" )
server.on( "message", function() {} )
this.timeout( 3000 )
this.slow( 2500 )
server.bind()
server.on( "listening", async function() {
const ourport = server.address().port
let expectedmessagecount = 0
const expectedmessages = [
{ action: "telephone-event", event: "4" },
{ action: "close" }
]
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
expect( d ).to.deep.include( expectedmessages[ expectedmessagecount ] )
expectedmessagecount++
if( "close" === d.action ) {
server.close()
done()
}
} )
expect( channel.echo() ).to.be.true
/* send a packet every 20mS x 50 */
for( let i = 0; 23 > i; i ++ ) {
sendpk( i, i*160, i*20, channel.local.port, server )
}
senddtmf( 23, 22*160, 23*20, channel.local.port, server, false, "4" )
senddtmf( 24, 22*160, 24*20, channel.local.port, server, false, "4" )
senddtmf( 25, 22*160, 25*20, channel.local.port, server, true, "4" )
for( let i = 26; 40 > i; i ++ ) {
sendpk( i, i*160, (i-3)*20, channel.local.port, server )
}
setTimeout( () => channel.close(), 1000 )
} )
} )
it( "single channel and request rtp server to send 2833", async function() {
/* TODO - check tre fuller structure of an RTP event (duration, volume, etc) */
/* create our RTP/UDP endpoint */
let done
const finished = new Promise( resolve => done = resolve )
const server = dgram.createSocket( "udp4" )
let dtmfpkcount = 0
server.on( "message", function( msg ) {
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfpkcount++
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
}
} )
this.timeout( 5000 )
this.slow( 4000 )
server.bind()
await new Promise( resolve => server.on( "listening", resolve ) )
const ourport = server.address().port
let expectedmessagecount = 0
const expectedmessages = [
{ action: "close" }
]
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
expect( d ).to.deep.include( expectedmessages[ expectedmessagecount ] )
expectedmessagecount++
if( "close" === d.action ) {
server.close()
done()
}
} )
expect( channel.echo() ).to.be.true
/* send a packet every 20mS x 50 */
for( let i = 0; 50 > i; i ++ ) {
sendpk( i, i*160, i*20, channel.local.port, server )
}
await new Promise( resolve => setTimeout( resolve, 400 ) )
channel.dtmf( "#1" )
await new Promise( resolve => setTimeout( resolve, 1000 ) )
channel.close()
await finished
expect( dtmfpkcount ).to.equal( 2*pkcountperdtmfdigit )
} )
it( "2 channels mixing and request rtp server to send 2833 to one", async function() {
/* create our RTP/UDP endpoint */
const clienta = dgram.createSocket( "udp4" )
const clientb = dgram.createSocket( "udp4" )
const dtmfpks = []
clienta.on( "message", function( msg ) {
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfpks.push( parse2833pk( msg ) )
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
}
} )
clientb.on( "message", function( msg ) {
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
expect( true ).to.equal( false ) //here = bad
}
clientb.send( msg, channelb.local.port, "localhost" )
} )
this.timeout( 3000 )
this.slow( 2500 )
clienta.bind()
await new Promise( ( resolve ) => { clienta.on( "listening", () => resolve() ) } )
clientb.bind()
await new Promise( ( resolve ) => { clientb.on( "listening", () => resolve() ) } )
const ouraport = clienta.address().port
const ourbport = clientb.address().port
let done
const finished = new Promise( ( r ) => { done = r } )
const channela = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ouraport, "codec": 0 } }, function( d ) {
if( "close" === d.action ) channelb.close()
} )
const channelb = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourbport, "codec": 0 } }, function( d ) {
if( "close" === d.action ) done()
} )
expect( channela.mix( channelb ) ).to.be.true
/* send a packet every 20mS x 70 */
for( let i = 0; 50 > i; i ++ ) {
sendpk( i, i*160, i*20, channela.local.port, clienta )
}
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 400 ) } )
channela.dtmf( "*9F" )
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 3 * timeperdtmfdigit ) } )
channela.close()
await finished
clienta.close()
clientb.close()
expect( dtmfpks.length ).to.equal( 3*pkcountperdtmfdigit )
expect( dtmfpks[ 0 ].event.id ).to.equal( 10 )
expect( dtmfpks[ 0 ].event.duration ).to.equal( 160 )
expect( dtmfpks[ 0 ].event.eoe ).to.be.false
expect( dtmfpks[ pkcountperdtmfdigit - 3 ].event.id ).to.equal( 10 )
expect( dtmfpks[ pkcountperdtmfdigit - 3 ].event.duration ).to.equal( dtmfeventduration )
expect( dtmfpks[ pkcountperdtmfdigit - 3 ].event.eoe ).to.be.true
} )
it( "2 channels mixing and request rtp server to send 2833 to one with dynamic payloadtype", async function() {
/* create our RTP/UDP endpoint */
const clienta = dgram.createSocket( "udp4" )
const clientb = dgram.createSocket( "udp4" )
const rfc2833pt = 44
let dtmfpkcount = 0
clienta.on( "message", function( msg ) {
if( rfc2833pt == ( 0x7f & msg [ 1 ] ) ) {
dtmfpkcount++
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
}
} )
clientb.on( "message", function( msg ) {
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
expect( true ).to.equal( false ) //here = bad
dtmfpkcount++
}
clientb.send( msg, channelb.local.port, "localhost" )
} )
this.timeout( 3000 )
this.slow( 2500 )
clienta.bind()
await new Promise( ( resolve ) => { clienta.on( "listening", () => resolve() ) } )
clientb.bind()
await new Promise( ( resolve ) => { clientb.on( "listening", () => resolve() ) } )
const ouraport = clienta.address().port
const ourbport = clientb.address().port
let done
const finished = new Promise( ( r ) => { done = r } )
const channela = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ouraport, "codec": 0, rfc2833pt } }, function( d ) {
if( "close" === d.action ) channelb.close()
} )
const channelb = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourbport, "codec": 0 } }, function( d ) {
if( "close" === d.action ) done()
} )
expect( channela.mix( channelb ) ).to.be.true
/* send a packet every 20mS x 70 */
for( let i = 0; 50 > i; i ++ ) {
sendpk( i, i*160, i*20, channela.local.port, clienta )
}
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 400 ) } )
channela.dtmf( "*9F" )
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 3 * timeperdtmfdigit ) } )
channela.close()
await finished
clienta.close()
clientb.close()
expect( dtmfpkcount ).to.equal( 3*pkcountperdtmfdigit )
} )
it( "3 channels mixing and request rtp server to send 2833 to one", async function() {
/* create our RTP/UDP endpoint */
const clienta = dgram.createSocket( "udp4" )
const clientb = dgram.createSocket( "udp4" )
const clientc = dgram.createSocket( "udp4" )
let dtmfpks = []
clienta.on( "message", function( msg ) {
const pk = parsepk( msg )
if( 101 == pk.pt ) {
dtmfpks.push( parse2833pk( msg ) )
} else {
expect( msg.length ).to.equal( 172 )
expect( pk.pt ).to.equal( 0 )
}
} )
clientb.on( "message", function( msg ) {
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
expect( true ).to.equal( false ) //here = bad
}
clientb.send( msg, channelb.local.port, "localhost" )
} )
clientc.on( "message", function( msg ) {
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
expect( true ).to.equal( false ) //here = bad
}
clientb.send( msg, channelb.local.port, "localhost" )
} )
this.timeout( 3000 )
this.slow( 2500 )
clienta.bind()
await new Promise( ( resolve ) => { clienta.on( "listening", () => resolve() ) } )
clientb.bind()
await new Promise( ( resolve ) => { clientb.on( "listening", () => resolve() ) } )
clientc.bind()
await new Promise( ( resolve ) => { clientc.on( "listening", () => resolve() ) } )
const ouraport = clienta.address().port
const ourbport = clientb.address().port
const ourcport = clientc.address().port
let done
const finished = new Promise( ( r ) => { done = r } )
const channela = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ouraport, "codec": 0 } }, function( d ) {
if( "close" === d.action ) channelb.close()
} )
const channelb = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourbport, "codec": 0 } }, function( d ) {
if( "close" === d.action ) channelc.close()
} )
const channelc = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourcport, "codec": 0 } }, function( d ) {
if( "close" === d.action ) done()
} )
expect( channela.mix( channelb ) ).to.be.true
expect( channela.mix( channelc ) ).to.be.true
/* send a packet every 20mS x 50 */
for( let i = 0; 50 > i; i ++ ) {
sendpk( i, i*160, i*20, channela.local.port, clienta )
}
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 100 ) } )
channela.dtmf( "*9ABD" )
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 5 * timeperdtmfdigit ) } )
channela.close()
clienta.close()
clientb.close()
clientc.close()
expect( dtmfpks.length ).to.equal( 5*pkcountperdtmfdigit )
await finished
} )
it( "Send multiple 2833 DTMF and check event", async function() {
/* create our RTP/UDP endpoint */
const server = dgram.createSocket( "udp4" )
server.on( "message", function() {} )
this.timeout( 3000 )
this.slow( 2500 )
server.bind()
await new Promise( ( resolve ) => { server.on( "listening", () => resolve() ) } )
const ourport = server.address().port
const receivedmessages = []
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
receivedmessages.push( d )
if( "close" === d.action ) {
server.close()
}
} )
expect( channel.echo() ).to.be.true
/* send a packet every 20mS x 50 */
for( let i = 0; 13 > i; i ++ ) {
sendpk( i, i*160, i*20, channel.local.port, server )
}
/* DTMF every 50mS */
senddtmf( 13, 12*160, 13*20, channel.local.port, server, false, "4" )
sendpk( 14, 13*160, 13*20, channel.local.port, server )
sendpk( 15, 14*160, 14*20, channel.local.port, server )
senddtmf( 16, 14*160, (13*20)+50, channel.local.port, server, false, "4" )
// Packet loss
// senddtmf( 15, 12 * 160, 15*20, channel.port, server, true, "4" )
for( let i = 17; 30 > i; i ++ ) {
sendpk( i, (i-2)*160, (i-2)*20, channel.local.port, server )
}
senddtmf( 31, 29*160, 29*20, channel.local.port, server, false, "5" )
sendpk( 32, 29*160, 29*20, channel.local.port, server )
sendpk( 33, 30*160, 30*20, channel.local.port, server )
senddtmf( 34, 30*160, (29*20)+50, channel.local.port, server, false, "5" )
sendpk( 35, 31*160, 31*20, channel.local.port, server )
sendpk( 36, 32*160, 32*20, channel.local.port, server )
senddtmf( 37, 32*160, (29*20)+100, channel.local.port, server, true, "5" )
for( let i = 37; 45 > i; i ++ ) {
sendpk( i, i*160, (i-6)*20, channel.local.port, server )
}
setTimeout( () => channel.close(), 1100 )
await new Promise( resolve => { server.on( "close", resolve ) } )
expect( receivedmessages[ 0 ].action ).to.equal( "telephone-event" )
expect( receivedmessages[ 0 ].event ).to.equal( "4" )
expect( receivedmessages[ 1 ].action ).to.equal( "telephone-event" )
expect( receivedmessages[ 1 ].event ).to.equal( "5" )
expect( receivedmessages[ 2 ].action ).to.equal( "close" )
} )
it( "Lose end packet", async function() {
/* create our RTP/UDP endpoint */
const server = dgram.createSocket( "udp4" )
const receivedmessages = []
let receviedpkcount = 0
server.on( "message", function() {
receviedpkcount++
} )
let done
const finished = new Promise( r => done = r )
this.timeout( 3000 )
this.slow( 2500 )
server.bind()
server.on( "listening", async function() {
const ourport = server.address().port
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
receivedmessages.push( d )
if( "close" === d.action ) {
server.close()
done()
}
} )
expect( channel.echo() ).to.be.true
/* send a packet every 20mS x 50 */
sendpk( 0, 160, 0, channel.local.port, server )
sendpk( 1, 1*160, 1*20, channel.local.port, server )
sendpk( 2, 2*160, 2*20, channel.local.port, server )
sendpk( 3, 3*160, 3*20, channel.local.port, server )
sendpk( 4, 4*160, 4*20, channel.local.port, server )
sendpk( 5, 5*160, 5*20, channel.local.port, server )
sendpk( 6, 6*160, 6*20, channel.local.port, server )
sendpk( 7, 7*160, 7*20, channel.local.port, server )
sendpk( 8, 8*160, 8*20, channel.local.port, server )
sendpk( 9, 9*160, 9*20, channel.local.port, server )
sendpk( 10, 10*160, 10*20, channel.local.port, server )
sendpk( 11, 11*160, 11*20, channel.local.port, server )
sendpk( 12, 12*160, 12*20, channel.local.port, server )
senddtmf( 13, 13*160, 13*20, channel.local.port, server, false, "4" )
sendpk( 14, 13*160, 13*20, channel.local.port, server, 0 )
sendpk( 15, 14*160, 14*20, channel.local.port, server, 0 )
senddtmf( 16, (15*160)+10, (15*20)+10, channel.local.port, server, false, "4" )
sendpk( 17, 15*160, 15*20, channel.local.port, server, 0 )
sendpk( 18, 16*160, 16*20, channel.local.port, server, 0 )
// Packet loss
// senddtmf( 19, (16*160)+20, (16*20)+20, channel.local.port, server, true, "4" )
sendpk( 20, 17*160, 17*20, channel.local.port, server, 0 )
sendpk( 21, 18*160, 18*20, channel.local.port, server, 0 )
sendpk( 22, 19*160, 19*20, channel.local.port, server, 0 )
sendpk( 23, 20*160, 20*20, channel.local.port, server, 0 )
sendpk( 24, 21*160, 21*20, channel.local.port, server, 0 )
sendpk( 25, 22*160, 22*20, channel.local.port, server, 0 )
sendpk( 26, 23*160, 23*20, channel.local.port, server, 0 )
sendpk( 27, 24*160, 24*20, channel.local.port, server, 0 )
sendpk( 28, 25*160, 25*20, channel.local.port, server, 0 )
sendpk( 29, 26*160, 26*20, channel.local.port, server, 0 )
sendpk( 30, 27*160, 27*20, channel.local.port, server, 0 )
setTimeout( () => channel.close(), 1000 )
} )
await finished
const expectedmessages = [
{ action: "telephone-event", event: "4" },
{ action: "close" }
]
expect( receviedpkcount ).to.be.above( 15 )
expect( receivedmessages.length ).to.equal( 2 )
expect( receivedmessages[ 0 ] ).to.deep.include( expectedmessages[ 0 ] )
expect( receivedmessages[ 1 ] ).to.deep.include( expectedmessages[ 1 ] )
} )
it( "mix 2 channels - pcmu <-> pcma and send DTMF", async function() {
/*
When mixing 2 channels, we expect the second leg to receive the 2833 packets
and our server to emit events indicating the DTMF on the first channel.
The timing was tight against the original C++ addon: 50 packets
emitted over 1 second, 1400 ms settle after the last send, total
~2450 ms. The Rust jitter buffer primes ~200 ms/hop and the mix is
a 2-hop round trip (endpointa → channela → mix → endpointb echo →
channelb → mix → endpointa), so the last couple of packets can
miss the close window. Widening the settle gives every packet
time to complete the round trip without changing what's asserted.
*/
this.timeout( 5000 )
this.slow( 3500 )
const endpointa = dgram.createSocket( "udp4" )
const endpointb = dgram.createSocket( "udp4" )
const receivedmessages = []
let endpointapkcount = 0
let endpointbpkcount = 0
let dtmfpkcount = 0
endpointa.on( "message", function( msg ) {
endpointapkcount++
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
} )
endpointb.on( "message", function( msg ) {
endpointbpkcount++
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfpkcount++
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 8 )
endpointb.send( msg, channelb.local.port, "localhost" )
}
} )
endpointa.bind()
await new Promise( ( resolve ) => { endpointa.on( "listening", function() { resolve() } ) } )
endpointb.bind()
await new Promise( ( resolve ) => { endpointb.on( "listening", function() { resolve() } ) } )
let done
const finished = new Promise( ( r ) => { done = r } )
const channela = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointa.address().port, "codec": 0 } }, function( d ) {
receivedmessages.push( d )
if( "close" === d.action ) channelb.close()
} )
const channelb = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointb.address().port, "codec": 8 } }, function( d ) {
if( "close" === d.action ) done()
} )
/* mix */
expect( channela.mix( channelb ) ).to.be.true
/* send a packet every 20mS x 50 */
sendpk( 0, 0, 0, channela.local.port, endpointa )
sendpk( 1, 1*160, 1*20, channela.local.port, endpointa )
sendpk( 2, 2*160, 2*20, channela.local.port, endpointa )
sendpk( 3, 3*160, 3*20, channela.local.port, endpointa )
sendpk( 4, 4*160, 4*20, channela.local.port, endpointa )
sendpk( 5, 5*160, 5*20, channela.local.port, endpointa )
sendpk( 6, 6*160, 6*20, channela.local.port, endpointa )
sendpk( 7, 7*160, 7*20, channela.local.port, endpointa )
sendpk( 8, 8*160, 8*20, channela.local.port, endpointa )
sendpk( 9, 9*160, 9*20, channela.local.port, endpointa )
sendpk( 10, 10*160, 10*20, channela.local.port, endpointa )
sendpk( 11, 11*160, 11*20, channela.local.port, endpointa )
sendpk( 12, 12*160, 12*20, channela.local.port, endpointa )
senddtmf( 13, 13*160, 13*20, channela.local.port, endpointa, false, "4" )
sendpk( 14, 13*160, 13*20, channela.local.port, endpointa, 0 )
sendpk( 15, 14*160, 14*20, channela.local.port, endpointa, 0 )
senddtmf( 16, (15*160)+10, (15*20)+10, channela.local.port, endpointa, false, "4" )
sendpk( 17, 15*160, 15*20, channela.local.port, endpointa, 0 )
sendpk( 18, 16*160, 16*20, channela.local.port, endpointa, 0 )
senddtmf( 19, (17*160)+20, (17*20)+20, channela.local.port, endpointa, true, "4" )
sendpk( 20, 17*160, 17*20, channela.local.port, endpointa, 0 )
sendpk( 21, 18*160, 18*20, channela.local.port, endpointa, 0 )
senddtmf( 22, (18*160)+30, (18*20)+30, channela.local.port, endpointa, true, "4" )
sendpk( 23, 19*160, 19*20, channela.local.port, endpointa, 0 )
sendpk( 24, 20*160, 20*20, channela.local.port, endpointa, 0 )
sendpk( 25, 21*160, 21*20, channela.local.port, endpointa, 0 )
sendpk( 26, 22*160, 22*20, channela.local.port, endpointa, 0 )
sendpk( 27, 23*160, 23*20, channela.local.port, endpointa, 0 )
sendpk( 28, 24*160, 24*20, channela.local.port, endpointa, 0 )
sendpk( 29, 25*160, 25*20, channela.local.port, endpointa, 0 )
senddtmf( 30, 26*160, 26*20, channela.local.port, endpointa, false, "5" )
sendpk( 31, 26*160, 26*20, channela.local.port, endpointa, 0 )
sendpk( 32, 27*160, 27*20, channela.local.port, endpointa, 0 )
senddtmf( 33, (27*160)+10, (27*20)+10, channela.local.port, endpointa, false, "5" )
sendpk( 34, 28*160, 28*20, channela.local.port, endpointa, 0 )
sendpk( 35, 29*160, 28*20, channela.local.port, endpointa, 0 )
senddtmf( 36, (28*160)+20, (28*20)+20, channela.local.port, endpointa, true, "5" )
sendpk( 37, 30*160, 29*20, channela.local.port, endpointa, 0 )
sendpk( 38, 31*160, 30*20, channela.local.port, endpointa, 0 )
senddtmf( 39, (38*160)+30, (30*20)+30, channela.local.port, endpointa, true, "5" )
sendpk( 40, 32*160, 31*20, channela.local.port, endpointa, 0 )
sendpk( 41, 33*160, 32*20, channela.local.port, endpointa, 0 )
sendpk( 42, 34*160, 33*20, channela.local.port, endpointa, 0 )
sendpk( 43, 35*160, 34*20, channela.local.port, endpointa, 0 )
sendpk( 44, 36*160, 35*20, channela.local.port, endpointa, 0 )
sendpk( 45, 37*160, 36*20, channela.local.port, endpointa, 0 )
sendpk( 46, 38*160, 37*20, channela.local.port, endpointa, 0 )
sendpk( 47, 39*160, 38*20, channela.local.port, endpointa, 0 )
sendpk( 48, 40*160, 39*20, channela.local.port, endpointa, 0 )
sendpk( 49, 51*160, 40*20, channela.local.port, endpointa, 0 )
await new Promise( ( r ) => { setTimeout( () => r(), 2500 ) } )
channela.close()
endpointa.close()
endpointb.close()
await finished
expect( dtmfpkcount ).to.be.within( ( pkcountperdtmfdigit * 2 ) - 4 , pkcountperdtmfdigit * 2 ) /* allow loss */
expect( endpointapkcount ).to.be.within( 30, 51 )
expect( endpointbpkcount - dtmfpkcount ).to.be.within( 30, 51 )
expect( receivedmessages.length ).to.equal( 5 )
expect( receivedmessages[ 0 ].action ).to.equal( "mix" )
expect( receivedmessages[ 1 ].action ).to.equal( "telephone-event" )
expect( receivedmessages[ 2 ].action ).to.equal( "telephone-event" )
expect( receivedmessages[ 3 ].action ).to.equal( "mix" )
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
expect( receivedmessages[ 4 ].action ).to.equal( "close" )
expect( receivedmessages[ 0 ].event ).to.equal( "start" )
expect( receivedmessages[ 1 ].event ).to.equal( "4" )
expect( receivedmessages[ 2 ].event ).to.equal( "5" )
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
} )
it( "wefwef mix 2 channels - pcmu <-> pcma and send DTMF different 2833 pt", async function() {
/*
When mixing 2 channels, we expect the second leg to receive the 2833 packets
and our server to emit events indicating the DTMF on the first channel.
Timing rationale: identical to the sibling test above — widened to
accommodate the ~400 ms two-hop jitter-prime latency so the last
packets complete the round trip before close.
*/
this.timeout( 5000 )
this.slow( 3500 )
const endpointa = dgram.createSocket( "udp4" )
const endpointb = dgram.createSocket( "udp4" )
const receivedmessages = []
let endpointapkcount = 0
let endpointbpkcount = 0
let dtmfpkcount = 0
endpointa.on( "message", function( msg ) {
endpointapkcount++
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
} )
endpointb.on( "message", function( msg ) {
endpointbpkcount++
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfpkcount++
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 8 )
endpointb.send( msg, channelb.local.port, "localhost" )
}
} )
endpointa.bind()
await new Promise( ( resolve ) => { endpointa.on( "listening", function() { resolve() } ) } )
endpointb.bind()
await new Promise( ( resolve ) => { endpointb.on( "listening", function() { resolve() } ) } )
let done
const finished = new Promise( ( r ) => { done = r } )
const channela = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointa.address().port, "codec": 0, "rfc2833pt": 127 } }, function( d ) {
receivedmessages.push( d )
if( "close" === d.action ) channelb.close()
} )
const channelb = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointb.address().port, "codec": 8, "rfc2833pt": 101 } }, function( d ) {
if( "close" === d.action ) done()
} )
/* mix */
expect( channela.mix( channelb ) ).to.be.true
/* send a packet every 20mS x 50 */
sendpk( 0, 0, 0, channela.local.port, endpointa )
sendpk( 1, 1*160, 1*20, channela.local.port, endpointa )
sendpk( 2, 2*160, 2*20, channela.local.port, endpointa )
sendpk( 3, 3*160, 3*20, channela.local.port, endpointa )
sendpk( 4, 4*160, 4*20, channela.local.port, endpointa )
sendpk( 5, 5*160, 5*20, channela.local.port, endpointa )
sendpk( 6, 6*160, 6*20, channela.local.port, endpointa )
sendpk( 7, 7*160, 7*20, channela.local.port, endpointa )
sendpk( 8, 8*160, 8*20, channela.local.port, endpointa )
sendpk( 9, 9*160, 9*20, channela.local.port, endpointa )
sendpk( 10, 10*160, 10*20, channela.local.port, endpointa )
sendpk( 11, 11*160, 11*20, channela.local.port, endpointa )
sendpk( 12, 12*160, 12*20, channela.local.port, endpointa )
senddtmf( 13, 13*160, 13*20, channela.local.port, endpointa, false, "4", 127 )
sendpk( 14, 13*160, 13*20, channela.local.port, endpointa, 0 )
sendpk( 15, 14*160, 14*20, channela.local.port, endpointa, 0 )
senddtmf( 16, (15*160)+10, (15*20)+10, channela.local.port, endpointa, false, "4", 127 )
sendpk( 17, 15*160, 15*20, channela.local.port, endpointa, 0 )
sendpk( 18, 16*160, 16*20, channela.local.port, endpointa, 0 )
senddtmf( 19, (17*160)+20, (17*20)+20, channela.local.port, endpointa, true, "4", 127 )
sendpk( 20, 17*160, 17*20, channela.local.port, endpointa, 0 )
sendpk( 21, 18*160, 18*20, channela.local.port, endpointa, 0 )
senddtmf( 22, (18*160)+30, (18*20)+30, channela.local.port, endpointa, true, "4", 127 )
sendpk( 23, 19*160, 19*20, channela.local.port, endpointa, 0 )
sendpk( 24, 20*160, 20*20, channela.local.port, endpointa, 0 )
sendpk( 25, 21*160, 21*20, channela.local.port, endpointa, 0 )
sendpk( 26, 22*160, 22*20, channela.local.port, endpointa, 0 )
sendpk( 27, 23*160, 23*20, channela.local.port, endpointa, 0 )
sendpk( 28, 24*160, 24*20, channela.local.port, endpointa, 0 )
sendpk( 29, 25*160, 25*20, channela.local.port, endpointa, 0 )
senddtmf( 30, 26*160, 26*20, channela.local.port, endpointa, false, "5", 127 )
sendpk( 31, 26*160, 26*20, channela.local.port, endpointa, 0 )
sendpk( 32, 27*160, 27*20, channela.local.port, endpointa, 0 )
senddtmf( 33, (27*160)+10, (27*20)+10, channela.local.port, endpointa, false, "5", 127 )
sendpk( 34, 28*160, 28*20, channela.local.port, endpointa, 0 )
sendpk( 35, 29*160, 28*20, channela.local.port, endpointa, 0 )
senddtmf( 36, (28*160)+20, (28*20)+20, channela.local.port, endpointa, true, "5", 127 )
sendpk( 37, 30*160, 29*20, channela.local.port, endpointa, 0 )
sendpk( 38, 31*160, 30*20, channela.local.port, endpointa, 0 )
senddtmf( 39, (38*160)+30, (30*20)+30, channela.local.port, endpointa, true, "5", 127 )
sendpk( 40, 32*160, 31*20, channela.local.port, endpointa, 0 )
sendpk( 41, 33*160, 32*20, channela.local.port, endpointa, 0 )
sendpk( 42, 34*160, 33*20, channela.local.port, endpointa, 0 )
sendpk( 43, 35*160, 34*20, channela.local.port, endpointa, 0 )
sendpk( 44, 36*160, 35*20, channela.local.port, endpointa, 0 )
sendpk( 45, 37*160, 36*20, channela.local.port, endpointa, 0 )
sendpk( 46, 38*160, 37*20, channela.local.port, endpointa, 0 )
sendpk( 47, 39*160, 38*20, channela.local.port, endpointa, 0 )
sendpk( 48, 40*160, 39*20, channela.local.port, endpointa, 0 )
sendpk( 49, 51*160, 40*20, channela.local.port, endpointa, 0 )
await new Promise( ( r ) => { setTimeout( () => r(), 2500 ) } )
channela.close()
endpointa.close()
endpointb.close()
await finished
expect( endpointapkcount ).to.be.within( 30, 51 )
expect( endpointbpkcount - dtmfpkcount ).to.be.within( 30, 51 )
expect( receivedmessages.length ).to.equal( 5 )
expect( dtmfpkcount ).to.be.within( ( pkcountperdtmfdigit * 2 ) - 4 , pkcountperdtmfdigit * 2 ) /* allow loss */
expect( receivedmessages[ 0 ].action ).to.equal( "mix" )
expect( receivedmessages[ 1 ].action ).to.equal( "telephone-event" )
expect( receivedmessages[ 2 ].action ).to.equal( "telephone-event" )
expect( receivedmessages[ 3 ].action ).to.equal( "mix" )
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
expect( receivedmessages[ 4 ].action ).to.equal( "close" )
expect( receivedmessages[ 0 ].event ).to.equal( "start" )
expect( receivedmessages[ 1 ].event ).to.equal( "4" )
expect( receivedmessages[ 2 ].event ).to.equal( "5" )
expect( receivedmessages[ 3 ].event ).to.equal( "finished" )
} )
it( "mix 3 channels - pcmu <-> pcma and ilbc and send DTMF", async function() {
this.timeout( 3000 )
this.slow( 2000 )
const endpointa = dgram.createSocket( "udp4" )
const endpointb = dgram.createSocket( "udp4" )
const endpointc = dgram.createSocket( "udp4" )
let endpointapkcount = 0
let endpointbpkcount = 0
let endpointcpkcount = 0
let dtmfapkcount = 0
let dtmfbpkcount = 0
let dtmfcpkcount = 0
endpointa.on( "message", function( msg ) {
endpointapkcount++
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfapkcount++
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 0 )
endpointb.send( msg, channelb.local.port, "localhost" )
}
} )
endpointb.on( "message", function( msg ) {
endpointbpkcount++
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfbpkcount++
} else {
expect( msg.length ).to.equal( 172 )
expect( 0x7f & msg [ 1 ] ).to.equal( 8 )
endpointb.send( msg, channelb.local.port, "localhost" )
}
} )
endpointc.on( "message", function( msg ) {
endpointcpkcount++
if( 101 == ( 0x7f & msg [ 1 ] ) ) {
dtmfcpkcount++
} else {
expect( msg.length ).to.equal( 50 )
expect( 0x7f & msg [ 1 ] ).to.equal( 97 )
endpointb.send( msg, channelb.local.port, "localhost" )
}
} )
endpointa.bind()
await new Promise( ( resolve ) => { endpointa.on( "listening", function() { resolve() } ) } )
endpointb.bind()
await new Promise( ( resolve ) => { endpointb.on( "listening", function() { resolve() } ) } )
endpointc.bind()
await new Promise( ( resolve ) => { endpointc.on( "listening", function() { resolve() } ) } )
const receveiedmessages = []
const channela = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointa.address().port, "codec": 0 } }, function( d ) {
receveiedmessages.push( d )
if( "close" === d.action ) channelb.close()
} )
const channelb = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointb.address().port, "codec": 8 } }, function( d ) {
expect( d.action).to.not.equal( "telephone-event" )
if( "close" === d.action ) channelc.close()
} )
const channelc = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": endpointc.address().port, "codec": 97 } }, function( d ) {
expect( d.action).to.not.equal( "telephone-event" )
if( "close" === d.action ) {
endpointa.close()
endpointb.close()
endpointc.close()
}
} )
/* mix */
expect( channela.mix( channelb ) ).to.be.true
expect( channela.mix( channelc ) ).to.be.true
/* send a packet every 20mS x 50 */
/* NO FOR LOOPS for explicit readablity of the test */
sendpk( 0, 0, 0, channela.local.port, endpointa )
sendpk( 1, 1*160, 20, channela.local.port, endpointa )
sendpk( 2, 2*160, 2*20, channela.local.port, endpointa )
sendpk( 3, 3*160, 3*20, channela.local.port, endpointa )
sendpk( 4, 4*160, 4*20, channela.local.port, endpointa )
sendpk( 5, 5*160, 5*20, channela.local.port, endpointa )
sendpk( 6, 6*160, 6*20, channela.local.port, endpointa )
sendpk( 7, 7*160, 7*20, channela.local.port, endpointa )
sendpk( 8, 8*160, 8*20, channela.local.port, endpointa )
sendpk( 9, 9*160, 9*20, channela.local.port, endpointa )
sendpk( 10, 10*160, 10*20, channela.local.port, endpointa )
sendpk( 11, 11*160, 11*20, channela.local.port, endpointa )
sendpk( 12, 12*160, 12*20, channela.local.port, endpointa )
/* rfc2833 - 3.6: An audio source SHOULD start transmitting event packets as soon as it
recognizes an event and every 50 ms thereafter or the packet interval
for the audio codec used for this session, if known.
This means our ts will not stay in sync with our sequence number - which increments
with every packet.
senddtmf( sn, ts, sendtime, port, socket, endofevent, event )
sendpk( sn, sendtime, port, socket, pt, ts, ssrc ) */
senddtmf( 13, 13*160, 13*20, channela.local.port, endpointa, false, "4" )
sendpk( 14, 13*160, 13*20, channela.local.port, endpointa, 0 )
sendpk( 15, 14*160, 14*20, channela.local.port, endpointa, 0 )
sendpk( 16, 15*160, 15*20, channela.local.port, endpointa, 0 )
senddtmf( 17, (15*160), (13*20)+50, channela.local.port, endpointa, false, "4" )
sendpk( 18, 16*160, 16*20, channela.local.port, endpointa, 0 )
sendpk( 19, 17*160, 17*20, channela.local.port, endpointa, 0 )
senddtmf( 20, (17*160), (13*20)+100, channela.local.port, endpointa, true, "4" )
sendpk( 21, 18*160, 18*20, channela.local.port, endpointa, 0 )
sendpk( 22, 19*160, 19*20, channela.local.port, endpointa, 0 )
sendpk( 23, 20*160, 20*20, channela.local.port, endpointa, 0 )
senddtmf( 24, (20*160), (13*20)+150, channela.local.port, endpointa, true, "4" )
sendpk( 25, 21*160, 21*20, channela.local.port, endpointa, 0 )
sendpk( 26, 22*160, 22*20, channela.local.port, endpointa, 0 )
sendpk( 27, 23*160, 23*20, channela.local.port, endpointa, 0 )
sendpk( 28, 24*160, 24*20, channela.local.port, endpointa, 0 )
sendpk( 29, 25*160, 25*20, channela.local.port, endpointa, 0 )
senddtmf( 30, 25*160, 25*20, channela.local.port, endpointa, false, "5" )
sendpk( 31, 26*160, 26*20, channela.local.port, endpointa, 0 )
sendpk( 32, 27*160, 27*20, channela.local.port, endpointa, 0 )
senddtmf( 33, (27*160), (25*20)+50, channela.local.port, endpointa, false, "5" )
sendpk( 34, 28*160, 28*20, channela.local.port, endpointa, 0 )
sendpk( 35, 29*160, 29*20, channela.local.port, endpointa, 0 )
senddtmf( 36, (29*160), (25*20)+100, channela.local.port, endpointa, true, "5" )
sendpk( 37, 30*160, 30*20, channela.local.port, endpointa, 0 )
sendpk( 38, 31*160, 31*20, channela.local.port, endpointa, 0 )
sendpk( 39, 32*160, 32*20, channela.local.port, endpointa, 0 )
senddtmf( 40, (32*160), (25*20)+150, channela.local.port, endpointa, true, "5" )
sendpk( 41, 33*160, 33*20, channela.local.port, endpointa, 0 )
sendpk( 42, 34*160, 34*20, channela.local.port, endpointa, 0 )
sendpk( 43, 35*160, 35*20, channela.local.port, endpointa, 0 )
sendpk( 44, 36*160, 36*20, channela.local.port, endpointa, 0 )
sendpk( 45, 37*160, 37*20, channela.local.port, endpointa, 0 )
sendpk( 46, 38*160, 38*20, channela.local.port, endpointa, 0 )
sendpk( 47, 39*160, 39*20, channela.local.port, endpointa, 0 )
sendpk( 48, 40*160, 40*20, channela.local.port, endpointa, 0 )
sendpk( 49, 41*160, 41*20, channela.local.port, endpointa, 0 )
sendpk( 50, 42*160, 42*20, channela.local.port, endpointa, 0 )
sendpk( 51, 43*160, 43*20, channela.local.port, endpointa, 0 )
sendpk( 52, 44*160, 44*20, channela.local.port, endpointa, 0 )
sendpk( 53, 45*160, 45*20, channela.local.port, endpointa, 0 )
sendpk( 54, 46*160, 46*20, channela.local.port, endpointa, 0 )
sendpk( 55, 47*160, 47*20, channela.local.port, endpointa, 0 )
sendpk( 56, 48*160, 48*20, channela.local.port, endpointa, 0 )
sendpk( 57, 49*160, 49*20, channela.local.port, endpointa, 0 )
sendpk( 58, 50*160, 50*20, channela.local.port, endpointa, 0 )
sendpk( 59, 52*160, 51*20, channela.local.port, endpointa, 0 )
await new Promise( ( resolve ) => { setTimeout( () => resolve(), 1200 ) } )
channela.close()
await Promise.all( [
new Promise( resolve => { endpointa.on( "close", resolve ) } ),
new Promise( resolve => { endpointb.on( "close", resolve ) } ),
new Promise( resolve => { endpointc.on( "close", resolve ) } )
] )
expect( endpointapkcount ).to.be.within( 59, 70 )
expect( endpointbpkcount - dtmfbpkcount ).to.be.within( 59, 70 )
expect( endpointcpkcount - dtmfcpkcount ).to.be.within( 59, 70 )
// 3 after we return to the event loop and enter the callback with close event.
expect( dtmfapkcount ).to.equal( 0 )
expect( dtmfbpkcount ).to.be.within( ( pkcountperdtmfdigit * 2 ) - 4, pkcountperdtmfdigit * 2 )
expect( dtmfcpkcount ).to.be.within( ( pkcountperdtmfdigit * 2 ) - 4, pkcountperdtmfdigit * 2 )
expect( receveiedmessages[ 0 ].action ).to.equal( "mix" )
expect( receveiedmessages[ 1 ].action ).to.equal( "mix" )
expect( receveiedmessages[ 2 ].action ).to.equal( "telephone-event" )
expect( receveiedmessages[ 3 ].action ).to.equal( "telephone-event" )
expect( receveiedmessages[ 4 ].action ).to.equal( "mix" )
expect( receveiedmessages[ 5 ].action ).to.equal( "close" )
expect( receveiedmessages[ 0 ].event ).to.equal( "start" )
expect( receveiedmessages[ 1 ].event ).to.equal( "start" )
expect( receveiedmessages[ 2 ].event ).to.equal( "4" )
expect( receveiedmessages[ 3 ].event ).to.equal( "5" )
expect( receveiedmessages[ 4 ].event ).to.equal( "finished" )
} )
it( "DTMF captured not working", async function() {
/* create our RTP/UDP endpoint */
const server = dgram.createSocket( "udp4" )
server.on( "message", function() {} )
this.timeout( 3000 )
this.slow( 2500 )
let done
const finished = new Promise( ( r ) => { done = r } )
server.bind()
server.on( "listening", async function() {
const ourport = server.address().port
let expectedmessagecount = 0
const expectedmessages = [
{ action: "telephone-event", event: "3" },
{ action: "close" }
]
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
expect( d ).to.deep.include( expectedmessages[ expectedmessagecount ] )
expectedmessagecount++
if( "close" === d.action ) {
server.close()
done()
}
} )
expect( channel.echo() ).to.be.true
// Event "3"
const dstport = channel.local.port
sendpk( 948, 148480, 0, dstport, server, 0, 518218235 )
sendpayload( 20, fromstr( "80 e5 03 b5 00 02 44 a0 1e e3 61 fb 03 0a 00 a0 4c d1" ), dstport, server )
sendpk( 950, 148800, 40, dstport, server, 0, 518218235 )
sendpayload( 60, fromstr( "80 65 03 b7 00 02 44 a0 1e e3 61 fb 03 0a 01 40 25 b8" ), dstport, server )
sendpk( 952, 149120, 80, dstport, server, 0, 518218235 )
sendpayload( 100, fromstr( "80 65 03 b9 00 02 44 a0 1e e3 61 fb 03 0a 01 e0 e8 81" ), dstport, server )
sendpk( 954, 149440,120, dstport, server, 0, 518218235 )
sendpayload( 140, fromstr( "80 65 03 bb 00 02 44 a0 1e e3 61 fb 03 0a 02 80 e2 74" ), dstport, server )
sendpk( 956, 149760, 160, dstport, server, 0, 518218235 )
sendpayload( 180, fromstr( "80 65 03 bd 00 02 44 a0 1e e3 61 fb 03 0a 03 20 1f bb" ), dstport, server )
sendpk( 958, 150080, 200, dstport, server, 0, 518218235 )
sendpayload( 220, fromstr( "80 65 03 bf 00 02 44 a0 1e e3 61 fb 03 0a 03 c0 13 0c" ), dstport, server )
sendpk( 960, 150400,240, dstport, server, 0, 518218235 )
sendpayload( 260, fromstr( "80 65 03 c1 00 02 44 a0 1e e3 61 fb 03 0a 04 60 2e bf" ), dstport, server )
sendpk( 962, 150720, 280, dstport, server, 0, 518218235 )
sendpayload( 300, fromstr( "80 65 03 c3 00 02 44 a0 1e e3 61 fb 03 8a 04 60 05 c1" ), dstport, server )
sendpayload( 320 ,fromstr( "80 65 03 c4 00 02 44 a0 1e e3 61 fb 03 8a 04 60 bb 69" ), dstport, server )
sendpk( 965, 151200, 340, dstport, server, 0, 518218235 )
sendpayload( 360, fromstr( "80 65 03 c6 00 02 44 a0 1e e3 61 fb 03 8a 04 60 1e 27" ), dstport, server )
sendpk( 967, 151520, 380, dstport, server, 0, 518218235 )
sendpk( 968, 151680, 400, dstport, server, 0, 518218235 )
sendpk( 969, 151840, 420, dstport, server, 0, 518218235 )
sendpk( 970, 152000, 440, dstport, server, 0, 518218235 )
setTimeout( () => channel.close(), 25*20 )
} )
await finished
} )
it( "DTMF PCAP playback test 1", async function() {
this.timeout( 21000 )
this.slow( 20000 )
let done
const finished = new Promise( ( r ) => { done = r } )
const receivedmessages = []
/* create our RTP/UDP endpoint */
const server = dgram.createSocket( "udp4" )
server.on( "message", function() {} )
server.bind()
server.on( "listening", async function() {
const ourport = server.address().port
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
receivedmessages.push( d )
if( "close" === d.action ) {
server.close()
done()
}
} )
setTimeout( () => channel.close(), 1000 * 17 )
const dstport = channel.local.port
channel.play( { "interupt":true, "files": [ { "wav": "test/interface/pcaps/180fa1ac-08e5-11ed-bd4d-02dba5b5aad6.wav" } ] } )
const ourpcap = await pcap.readpcap( "test/interface/pcaps/dtmfcapture1.pcap" )
const offset = 4700
ourpcap.forEach( ( packet ) => {
if( packet.ipv4 && packet.ipv4.udp && 10230 == packet.ipv4.udp.dstport ) {
//console.dir( packet, { depth: null } )
//console.log(packet.ipv4.udp.data.readUInt16BE( 2 ) )
//const sn = packet.ipv4.udp.data.readUInt16BE( 2 )
sendpayload( ( 1000 * packet.ts_sec_offset ) - offset, packet.ipv4.udp.data, dstport, server )
}
} )
} )
await finished
const expectedmessages = [
{ action: "play", event: "start", reason: "new" },
{ action: "play", event: "end", reason: "telephone-event" },
{ action: "telephone-event", event: "2" },
{ action: "close" }
]
expect( receivedmessages.length ).to.equal( 4 )
expect( receivedmessages[ 0 ] ).to.deep.include( expectedmessages[ 0 ] )
expect( receivedmessages[ 1 ] ).to.deep.include( expectedmessages[ 1 ] )
expect( receivedmessages[ 2 ] ).to.deep.include( expectedmessages[ 2 ] )
expect( receivedmessages[ 3 ] ).to.deep.include( expectedmessages[ 3 ] )
} )
it( "DTMF PCAP playback test 2", async function() {
this.timeout( 21000 )
this.slow( 20000 )
let done
const finished = new Promise( ( r ) => { done = r } )
const receivedmessages = []
/* create our RTP/UDP endpoint */
const server = dgram.createSocket( "udp4" )
server.on( "message", function() {} )
server.bind()
server.on( "listening", async function() {
const ourport = server.address().port
const channel = await projectrtp.openchannel( { "remote": { "address": "127.0.0.1", "port": ourport, "codec": 0 } }, function( d ) {
receivedmessages.push( d )
if( "close" === d.action ) {
server.close()
done()
}
} )
setTimeout( () => channel.close(), 1000 * 17 )
const dstport = channel.local.port
channel.play( { "interupt":true, "files": [ { "wav": "test/interface/pcaps/180fa1ac-08e5-11ed-bd4d-02dba5b5aad6.wav" } ] } )
const ourpcap = await pcap.readpcap( "test/interface/pcaps/dtmf3presses.pcap" )
const offset = 17 * 1000
ourpcap.forEach( ( packet ) => {
if( packet.ipv4 && packet.ipv4.udp && 10298 == packet.ipv4.udp.dstport ) {
//console.dir( packet, { depth: null } )
//console.log(packet.ipv4.udp.data.readUInt16BE( 2 ) )
//const sn = packet.ipv4.udp.data.readUInt16BE( 2 )
const sendat = ( 1000 * packet.ts_sec_offset ) - offset
if ( 0 < sendat ) {
//console.log(sn, sendat)
sendpayload( sendat, packet.ipv4.udp.data, dstport, server )
}
}
} )
} )
await finished
const expectedmessages = [
{ action: "play", event: "start", reason: "new" },
{ action: "play", event: "end", reason: "telephone-event" },
{ action: "telephone-event", event: "1" },
{ action: "telephone-event", event: "1" },
{ action: "telephone-event", event: "1" },
{ action: "close" }
]
expect( receivedmessages.length ).to.equal( 6 )
expect( receivedmessages[ 0 ] ).to.deep.include( expectedmessages[ 0 ] )
expect( receivedmessages[ 1 ] ).to.deep.include( expectedmessages[ 1 ] )
expect( receivedmessages[ 2 ] ).to.deep.include( expectedmessages[ 2 ] )
expect( receivedmessages[ 3 ] ).to.deep.include( expectedmessages[ 3 ] )
expect( receivedmessages[ 4 ]