[client] audio: increase startup latency

Underruns can still happen quite easily at the beginning of playback,
particularly at very low latency settings. Further increase the startup
latency to avoid this.
This commit is contained in:
Chris Spencer 2022-02-05 09:53:06 +00:00 committed by Geoffrey McRae
parent 5e1b8f2abe
commit 0d97a51802
4 changed files with 25 additions and 36 deletions

View File

@ -287,12 +287,10 @@ static void pipewire_playbackSetup(int channels, int sampleRate,
pw_thread_loop_unlock(pw.thread);
}
static bool pipewire_playbackStart(int framesBuffered)
static void pipewire_playbackStart(void)
{
if (!pw.playback.stream)
return false;
bool start = false;
return;
if (pw.playback.state != STREAM_STATE_ACTIVE)
{
@ -301,17 +299,8 @@ static bool pipewire_playbackStart(int framesBuffered)
switch (pw.playback.state)
{
case STREAM_STATE_INACTIVE:
// PipeWire startup latency varies wildly depending on what else is, or
// was last using the audio device. In the worst case, PipeWire can
// request two full buffers within a very short period of time
// immediately at the start of playback, so make sure we've got enough
// data in the buffer to support this
if (framesBuffered >= pw.playback.maxPeriodFrames * 2)
{
pw_stream_set_active(pw.playback.stream, true);
pw.playback.state = STREAM_STATE_ACTIVE;
start = true;
}
pw_stream_set_active(pw.playback.stream, true);
pw.playback.state = STREAM_STATE_ACTIVE;
break;
case STREAM_STATE_DRAINING:
@ -325,8 +314,6 @@ static bool pipewire_playbackStart(int framesBuffered)
pw_thread_loop_unlock(pw.thread);
}
return start;
}
static void pipewire_playbackStop(void)

View File

@ -37,7 +37,7 @@ struct PulseAudio
int sinkIndex;
bool sinkCorked;
bool sinkMuted;
int sinkStart;
int sinkMaxPeriodFrames;
int sinkSampleRate;
int sinkChannels;
int sinkStride;
@ -250,7 +250,7 @@ static void pulseaudio_setup(int channels, int sampleRate,
{
if (pa.sink && pa.sinkChannels == channels && pa.sinkSampleRate == sampleRate)
{
*maxPeriodFrames = pa.sinkStart;
*maxPeriodFrames = pa.sinkMaxPeriodFrames;
return;
}
@ -287,30 +287,25 @@ static void pulseaudio_setup(int channels, int sampleRate,
PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY,
NULL, NULL);
pa.sinkStride = channels * sizeof(float);
pa.sinkPullFn = pullFn;
pa.sinkStart = attribs.tlength / pa.sinkStride;
pa.sinkCorked = true;
pa.sinkStride = channels * sizeof(float);
pa.sinkPullFn = pullFn;
pa.sinkMaxPeriodFrames = attribs.tlength / pa.sinkStride;
pa.sinkCorked = true;
*maxPeriodFrames = pa.sinkStart;
*maxPeriodFrames = pa.sinkMaxPeriodFrames;
pa_threaded_mainloop_unlock(pa.loop);
}
static bool pulseaudio_start(int framesBuffered)
static void pulseaudio_start(void)
{
if (!pa.sink)
return false;
if (framesBuffered < pa.sinkStart)
return false;
return;
pa_threaded_mainloop_lock(pa.loop);
pa_stream_cork(pa.sink, 0, NULL, NULL);
pa.sinkCorked = false;
pa_threaded_mainloop_unlock(pa.loop);
return true;
}
static void pulseaudio_stop(void)

View File

@ -50,9 +50,8 @@ struct LG_AudioDevOps
void (*setup)(int channels, int sampleRate, int * maxPeriodFrames,
LG_AudioPullFn pullFn);
/* called when there is data available to start playback
* return true if playback should start */
bool (*start)(int framesBuffered);
/* called when there is data available to start playback */
void (*start)(void);
/* called when SPICE reports the audio stream has stopped */
void (*stop)(void);

View File

@ -612,9 +612,17 @@ void audio_playbackData(uint8_t * data, size_t size)
if (audio.playback.state == STREAM_STATE_SETUP)
{
frames = ringbuffer_getCount(audio.playback.buffer);
if (audio.audioDev->playback.start(frames))
// In the worst case, the audio device can immediately request two full
// buffers at the beginning of playback. Latency corrections at startup can
// also be quite significant due to poor packet pacing from Spice, so
// additionally require at least two full Spice periods' worth of data
// before starting playback to minimise the chances of underrunning
int startFrames =
spiceData->periodFrames * 2 + audio.playback.deviceMaxPeriodFrames * 2;
if (spiceData->nextPosition >= startFrames) {
audio.audioDev->playback.start();
audio.playback.state = STREAM_STATE_RUN;
}
}
double latencyFrames = actualOffset;