Player
Plays audio sources on one voice connection, one at a time. playAsync sends Speaking, then each packet of the
source paced by its own duration, then five silence frames and Speaking 0, and resolves "finished", or
"stopped" after stop. One player per connection plays at a time; a second playAsync, on this player or on
another player of the same connection, fails at once and leaves the running playback alone.
pause holds the running playback: at its next step it sends the silence tail and Speaking 0, stops reading the
source and waits. resume sends Speaking again and plays on from the next packet on a fresh schedule.
While the connection resumes or rejoins, the playback waits, woken by the connection's onReady, onResumed and
onClosed. On each new session it waits up to mediaWaitSeconds for DAVE media readiness, then sends Speaking
again; until media is ready, voice sends Opus silence in place of every packet, so nothing leaves unencrypted.
A player is bound to one Connection. After that connection closes, a new join makes a new Connection, which
needs a new player. Sources must return quickly: a read that takes longer than a frame leaves a gap in the audio,
and a read that never returns holds the playback, which stop cannot end.
A stream source from audio.fromStream never blocks a read. While it is starved, before it has buffered enough
and whenever it stalls, the playback sends its silence tail and Speaking 0 if Speaking went out, then polls the
source every 20 ms, and speaks again on a fresh schedule once the source has audio.
Summary
Properties
Player.connection :: voice.ConnectionPlayer.speakingFlags :: numberPlayer.silenceFrames :: numberPlayer.mediaWaitSeconds :: numberPlayer.clock :: PlayerClockPlayer.logger :: logger.LoggerPlayer.playing :: booleanPlayer.ending :: booleanPlayer.stopRequested :: booleanPlayer.paused :: booleanPlayer.readyCount :: numberPlayer.spokenReadyCount :: number?Player.startMillis :: number?Player.elapsedSamples :: numberPlayer.packetsSent :: numberPlayer.silenceFramesSent :: numberPlayer.onWake :: emitter.Emitter<()>Player.listenerDisconnects :: { () -> () }Properties
Section titled “Properties”connection
Section titled “connection”The voice connection the player sends on.
speakingFlags
Section titled “speakingFlags”The Speaking flags sent before audio: 1 (Microphone) by default, never 0.
silenceFrames
Section titled “silenceFrames”How many Opus silence frames end a playback, 5 by default.
mediaWaitSeconds
Section titled “mediaWaitSeconds”How long a playback waits for DAVE media readiness before Speaking on each new session, 5 seconds by default.
Where the pace reads the time and waits. The default reads std_polyfills' datetime.now and task.wait on
every call, so a clock swapped in later, such as discord_stub's virtual clock, is the one it uses.
logger
Section titled “logger”The player's logger, named AudioPlayer, at Info unless logLevel says otherwise.
playing
Section titled “playing”Whether a playback runs, from its start checks until its silence tail and cleanup end.
ending
Section titled “ending”Whether the running playback has reached its end and is sending its silence tail; stop does nothing then.
stopRequested
Section titled “stopRequested”Whether stop asked the running playback to end. A playback clears it when it starts.
paused
Section titled “paused”Whether pause holds the running playback. A playback clears it when it starts and when it ends.
readyCount
Section titled “readyCount”How many times the connection became ready since the running playback started.
spokenReadyCount
Section titled “spokenReadyCount”The readyCount that Speaking last went out on, nil while Speaking is off.
startMillis
Section titled “startMillis”The clock time the schedule starts from: set just before the first paced send of a playback, and moved by each schedule reset.
elapsedSamples
Section titled “elapsedSamples”The samples sent since startMillis; the next deadline is startMillis + elapsedSamples / 48 milliseconds.
packetsSent
Section titled “packetsSent”How many of the source's packets the running or last playback sent.
silenceFramesSent
Section titled “silenceFramesSent”How many silence frames the running or last playback sent.
onWake
Section titled “onWake”Wakes the playback's thread on the next scheduler step after the connection becomes ready, resumes or closes, or
after stop.
listenerDisconnects
Section titled “listenerDisconnects”Disconnects the running playback's listeners on the connection's onReady, onResumed and onClosed; empty
while nothing plays.
Methods
Section titled “Methods”playAsync
Section titled “playAsync”Player : playAsync ( source ) -> ()
Plays source and resolves Ok with "finished" once the source ran out and the silence tail and Speaking 0 went
out (or could not be sent because the session went away), or with "stopped" after stop and the same tail. The
future is lazy: playback starts when it is polled or awaited.
Fails at once, without claiming the source, when this player is playing, another player plays on the connection,
the connection was never joined or has closed, or the source was played before. Fails with
voice connection closed: <closeDetail> when the connection closes before the end, with the send's own error when
a send fails on a session that stayed ready (a send lost to a reconnect is logged at debug and not sent again),
with audio source failed: <error> when the source raises and with
invalid Opus packet from the audio source: <error> for a packet that is not Opus. Every exit after the start
destroys the source.
Parameters
| source: Source |
Player : stop ( ) -> ()
Asks the running playback to end. It ends at its next step with the silence tail and Speaking 0 when Speaking went
out on a ready session, and resolves "stopped": at once from the readiness wait or a pause (whose tail already
went out), within about one 20 ms poll from a starved stream's wait (whose tail already went out), within one
packet from a pace, when a send or a source read returns, and when the media wait ends, which in a DAVE channel
can take up to mediaWaitSeconds. A stream source's own read never blocks, and killing a fromProcess program
never waits for it to exit, so a stream whose producer waits for bytes, or is blocked writing them, still stops
this quickly. Does nothing, logged at debug, when nothing plays or the playback is already sending its tail.
Player : pause ( ) -> boolean
Pauses the running playback and returns whether it did. At its next step the playback sends the silence tail and
Speaking 0 when Speaking went out on a ready session, stops reading the source and waits. resume plays it on,
stop ends it at once with "stopped", and a close fails it with the close, as while playing; a voice resume or
rejoin keeps the pause. A stream that is buffering keeps buffering until it has audio, then holds. Returns false,
logged at debug, when nothing plays, the playback is already paused, or it is ending.
Returns
| boolean |
resume
Section titled “resume”Player : resume ( ) -> boolean
Resumes a paused playback and returns whether it did. The playback sends Speaking again and plays on from the source's next packet on a fresh schedule, as after a stall, so a long pause never makes it catch up. Returns false, logged at debug, when nothing plays, the playback is not paused, or it is stopping.
Returns
| boolean |
Functions
Section titled “Functions”Player . new ( connection , options ) -> Player
Builds a player for connection. Raises for a missing connection, speakingFlags of 0, and a negative
silenceFrames or mediaWaitSeconds.
Parameters
| connection: Connection | |
| options: PlayerOptions? |
Returns
| Player |