Document audio player
Add some high-level documentation on the audio player implementation.
This commit is contained in:
@@ -6,6 +6,53 @@
|
|||||||
|
|
||||||
#define SC_AUDIO_PLAYER_NDEBUG // comment to debug
|
#define SC_AUDIO_PLAYER_NDEBUG // comment to debug
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Real-time audio player with configurable latency
|
||||||
|
*
|
||||||
|
* As input, the player regularly receives AVFrames of decoded audio samples.
|
||||||
|
* As output, an SDL callback regularly requests audio samples to be played.
|
||||||
|
* In the middle, an audio buffer stores the samples produced but not consumed
|
||||||
|
* yet.
|
||||||
|
*
|
||||||
|
* The goal of the player is to feed the audio output with a latency as low as
|
||||||
|
* possible while avoiding buffer underrun (i.e. not being able to provide
|
||||||
|
* samples when requested).
|
||||||
|
*
|
||||||
|
* For that purpose, it attempts to keep the average buffering (the number of
|
||||||
|
* samples present in the buffer) around a target value. If this target
|
||||||
|
* buffering is too low, then buffer underrun will occur often. If it is too
|
||||||
|
* high, then latency will be increased (this can be used on purpose to delay
|
||||||
|
* the audio playback). This value can be configured (in milliseconds) via the
|
||||||
|
* scrcpy option --audio-buffer.
|
||||||
|
*
|
||||||
|
* The player could not adjust the sample input rate (it receives samples
|
||||||
|
* produced in real-time) nor the sample output rate (it must provide samples
|
||||||
|
* as requested by the audio output callback). Therefore, it may only apply
|
||||||
|
* compensation by resampling (convert m input samples to n output samples).
|
||||||
|
*
|
||||||
|
* The compensation itself is applied by swresample (FFmpeg). It is configured
|
||||||
|
* by swr_set_compensation(). An important work for the player is thus to
|
||||||
|
* estimate regularly the compensation value to configure.
|
||||||
|
*
|
||||||
|
* Basically, the player wants to estimate the current buffering level: it is
|
||||||
|
* the result of an average of the "natural" buffering (samples are produced
|
||||||
|
* and consumed by blocks, so it must be smoothed), and by instant adjustments
|
||||||
|
* resulting of its own actions (explicit compensation and silence insertion on
|
||||||
|
* underflow), which are not smoothed.
|
||||||
|
*
|
||||||
|
* Buffer underflow events may occur when packets arrive too late. In that
|
||||||
|
* case, the player is inserting silence. Once the packets finally arrive
|
||||||
|
* (late), one strategy could be to drop the samples that were replaced by
|
||||||
|
* silence, in order to keep a minimal latency. However, dropping samples in
|
||||||
|
* case of buffer underflow is not a good strategy: it would temporarily
|
||||||
|
* increase the underflow even more, and cause very audible audio glitches.
|
||||||
|
*
|
||||||
|
* Therefore, the player don't drop any sample on underflow, the stream is just
|
||||||
|
* delayed by the number of silent samples inserted. But in return, these
|
||||||
|
* additional samples will increase buffering (latency) when the late packets
|
||||||
|
* will arrive, so they will be taken into account by compensation.
|
||||||
|
*/
|
||||||
|
|
||||||
/** Downcast frame_sink to sc_audio_player */
|
/** Downcast frame_sink to sc_audio_player */
|
||||||
#define DOWNCAST(SINK) container_of(SINK, struct sc_audio_player, frame_sink)
|
#define DOWNCAST(SINK) container_of(SINK, struct sc_audio_player, frame_sink)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user