@@ -55,13 +55,15 @@ class Connection extends EventEmitter {
5555
5656 this . player = {
5757 sequence : 0 ,
58- timestamp : 0
58+ timestamp : 0 ,
59+ nextPacket : 0
5960 }
6061
6162 this . nonce = 0
6263 this . nonceBuffer = Buffer . alloc ( 24 )
64+ this . packetBuffer = Buffer . allocUnsafe ( 12 )
6365
64- this . playInterval = null
66+ this . playTimeout = null
6567 this . audioStream = null
6668 }
6769
@@ -306,15 +308,15 @@ class Connection extends EventEmitter {
306308 this . ws . on ( 'error' , ( error ) => this . emit ( 'error' , error ) )
307309 }
308310
309- sendAudioChunk ( packetBuffer , chunk ) {
310- packetBuffer . writeUInt8 ( 0x80 , 0 )
311- packetBuffer . writeUInt8 ( 0x78 , 1 )
311+ sendAudioChunk ( chunk ) {
312+ this . packetBuffer . writeUInt8 ( 0x80 , 0 )
313+ this . packetBuffer . writeUInt8 ( 0x78 , 1 )
312314
313- packetBuffer . writeUInt16BE ( this . player . sequence , 2 , 2 )
314- packetBuffer . writeUInt32BE ( this . player . timestamp , 4 , 4 )
315- packetBuffer . writeUInt32BE ( this . udpInfo . ssrc , 8 , 4 )
315+ this . packetBuffer . writeUInt16BE ( this . player . sequence , 2 , 2 )
316+ this . packetBuffer . writeUInt32BE ( this . player . timestamp , 4 , 4 )
317+ this . packetBuffer . writeUInt32BE ( this . udpInfo . ssrc , 8 , 4 )
316318
317- packetBuffer . copy ( nonce , 0 , 0 , 12 )
319+ this . packetBuffer . copy ( nonce , 0 , 0 , 12 )
318320
319321 this . player . timestamp += TIMESTAMP_INCREMENT
320322 if ( this . player . timestamp >= MAX_TIMESTAMP ) this . player . timestamp = 0
@@ -327,15 +329,15 @@ class Connection extends EventEmitter {
327329 case 'xsalsa20_poly1305' : {
328330 const output = Sodium . close ( chunk , nonce , this . udpInfo . secretKey )
329331
330- packet = Buffer . concat ( [ packetBuffer , output ] )
332+ packet = Buffer . concat ( [ this . packetBuffer , output ] )
331333
332334 break
333335 }
334336 case 'xsalsa20_poly1305_suffix' : {
335337 const random = Sodium . random ( 24 , this . nonceBuffer )
336338 const output = Sodium . close ( chunk , random , this . udpInfo . secretKey )
337339
338- packet = Buffer . concat ( [ packetBuffer , output , random ] )
340+ packet = Buffer . concat ( [ this . packetBuffer , output , random ] )
339341
340342 break
341343 }
@@ -346,7 +348,7 @@ class Connection extends EventEmitter {
346348
347349 const output = Sodium . close ( chunk , this . nonceBuffer , this . udpInfo . secretKey )
348350
349- packet = Buffer . concat ( [ packetBuffer , output , this . nonceBuffer . subarray ( 0 , 4 ) ] )
351+ packet = Buffer . concat ( [ this . packetBuffer , output , this . nonceBuffer . subarray ( 0 , 4 ) ] )
350352
351353 break
352354 }
@@ -368,7 +370,7 @@ class Connection extends EventEmitter {
368370 }
369371
370372 audioStream . once ( 'readable' , ( ) => {
371- if ( this . audioStream && this . playInterval ) {
373+ if ( this . audioStream && this . playTimeout ) {
372374 this . statistics = {
373375 packetsSent : 0 ,
374376 packetsLost : 0 ,
@@ -390,8 +392,8 @@ class Connection extends EventEmitter {
390392 }
391393
392394 stop ( reason ) {
393- clearInterval ( this . playInterval )
394- this . playInterval = null
395+ clearTimeout ( this . playTimeout )
396+ this . playTimeout = null
395397
396398 this . audioStream . destroy ( )
397399 this . audioStream . removeListener ( 'finishBuffering' , this . _markAsStoppable )
@@ -414,28 +416,34 @@ class Connection extends EventEmitter {
414416 this . _updatePlayerState ( { status : 'idle' , reason : reason ?? 'paused' } )
415417
416418 this . _setSpeaking ( 0 )
417- clearInterval ( this . playInterval )
419+ clearTimeout ( this . playTimeout )
418420 }
419421
420422 _markAsStoppable ( ) {
421423 this . audioStream . canStop = true
422424 }
423425
424- unpause ( reason ) {
425- this . _updatePlayerState ( { status : 'playing' , reason : reason ?? 'unpaused' } )
426+ _packetInterval ( ) {
427+ this . playTimeout = setTimeout ( ( ) => {
428+ const chunk = this . audioStream . read ( OPUS_FRAME_SIZE )
426429
427- this . _setSpeaking ( 1 << 0 )
430+ if ( ! chunk && this . audioStream . canStop ) return this . stop ( 'finished' )
428431
429- const packetBuffer = Buffer . allocUnsafe ( 12 )
432+ if ( chunk ) this . sendAudioChunk ( chunk )
433+
434+ this . player . nextPacket += OPUS_FRAME_DURATION
435+ this . _packetInterval ( )
436+ } , this . player . nextPacket - Date . now ( ) )
437+ }
430438
431- this . playInterval = setInterval ( ( ) => {
432- const chunk = this . audioStream . read ( OPUS_FRAME_SIZE )
439+ unpause ( reason ) {
440+ this . _updatePlayerState ( { status : 'playing' , reason : reason ?? 'unpaused' } )
433441
434- if ( ! chunk && this . audioStream . canStop ) return this . stop ( 'finished' )
435-
436- if ( chunk ) this . sendAudioChunk ( packetBuffer , chunk )
437- } , OPUS_FRAME_DURATION )
442+ this . _setSpeaking ( 1 << 0 )
438443
444+ this . player . nextPacket = Date . now ( ) + OPUS_FRAME_DURATION
445+ this . _packetInterval ( )
446+
439447 this . audioStream . once ( 'finishBuffering' , ( ) => this . _markAsStoppable ( ) )
440448 }
441449
@@ -445,14 +453,15 @@ class Connection extends EventEmitter {
445453 this . hbInterval = null
446454 }
447455
448- if ( this . playInterval ) {
449- clearInterval ( this . playInterval )
450- this . playInterval = null
456+ if ( this . playTimeout ) {
457+ clearTimeout ( this . playTimeout )
458+ this . playTimeout = null
451459 }
452460
453461 this . player = {
454462 sequence : 0 ,
455- timestamp : 0
463+ timestamp : 0 ,
464+ nextPacket : 0
456465 }
457466
458467 if ( this . ws && ! this . ws . closing ) {
0 commit comments