[client] audio: allow the audiodev to determine the start fill level

This commit is contained in:
Geoffrey McRae 2022-01-19 01:52:19 +11:00
parent 46da447429
commit 04ae9217e8
4 changed files with 36 additions and 23 deletions

View File

@ -53,6 +53,7 @@ struct PipeWire
int sampleRate; int sampleRate;
int stride; int stride;
LG_AudioPullFn pullFn; LG_AudioPullFn pullFn;
int startFrames;
StreamState state; StreamState state;
} }
@ -224,16 +225,16 @@ static void pipewire_playbackSetup(int channels, int sampleRate,
pipewire_playbackStopStream(); pipewire_playbackStopStream();
int bufferFrames = sampleRate / 10; int bufferFrames = sampleRate / 10;
int maxLatencyFrames = bufferFrames / 2;
char maxLatency[32];
snprintf(maxLatency, sizeof(maxLatency), "%d/%d", maxLatencyFrames,
sampleRate);
pw.playback.channels = channels; pw.playback.channels = channels;
pw.playback.sampleRate = sampleRate; pw.playback.sampleRate = sampleRate;
pw.playback.stride = sizeof(uint16_t) * channels; pw.playback.stride = sizeof(uint16_t) * channels;
pw.playback.pullFn = pullFn; pw.playback.pullFn = pullFn;
pw.playback.startFrames = maxLatencyFrames;
int maxLatencyFrames = bufferFrames / 2;
char maxLatency[32];
snprintf(maxLatency, sizeof(maxLatency), "%d/%d", maxLatencyFrames,
sampleRate);
pw_thread_loop_lock(pw.thread); pw_thread_loop_lock(pw.thread);
pw.playback.stream = pw_stream_new_simple( pw.playback.stream = pw_stream_new_simple(
@ -278,10 +279,12 @@ static void pipewire_playbackSetup(int channels, int sampleRate,
pw_thread_loop_unlock(pw.thread); pw_thread_loop_unlock(pw.thread);
} }
static void pipewire_playbackStart(void) static bool pipewire_playbackStart(int framesBuffered)
{ {
if (!pw.playback.stream) if (!pw.playback.stream)
return; return false;
bool start = false;
if (pw.playback.state != STREAM_STATE_ACTIVE && if (pw.playback.state != STREAM_STATE_ACTIVE &&
pw.playback.state != STREAM_STATE_RESTARTING) pw.playback.state != STREAM_STATE_RESTARTING)
@ -291,13 +294,18 @@ static void pipewire_playbackStart(void)
switch (pw.playback.state) switch (pw.playback.state)
{ {
case STREAM_STATE_INACTIVE: case STREAM_STATE_INACTIVE:
if (framesBuffered >= pw.playback.startFrames)
{
pw_stream_set_active(pw.playback.stream, true); pw_stream_set_active(pw.playback.stream, true);
pw.playback.state = STREAM_STATE_ACTIVE; pw.playback.state = STREAM_STATE_ACTIVE;
start = true;
}
break; break;
case STREAM_STATE_FLUSHING: case STREAM_STATE_FLUSHING:
// We were preparing to stop; just carry on as if nothing happened // We were preparing to stop; just carry on as if nothing happened
pw.playback.state = STREAM_STATE_ACTIVE; pw.playback.state = STREAM_STATE_ACTIVE;
start = true;
break; break;
case STREAM_STATE_DRAINING: case STREAM_STATE_DRAINING:
@ -312,6 +320,8 @@ static void pipewire_playbackStart(void)
pw_thread_loop_unlock(pw.thread); pw_thread_loop_unlock(pw.thread);
} }
return start;
} }
static void pipewire_playbackStop(void) static void pipewire_playbackStop(void)

View File

@ -288,15 +288,20 @@ static void pulseaudio_setup(int channels, int sampleRate,
pa_threaded_mainloop_unlock(pa.loop); pa_threaded_mainloop_unlock(pa.loop);
} }
static void pulseaudio_start(void) static bool pulseaudio_start(int framesBuffered)
{ {
if (!pa.sink) if (!pa.sink)
return; return false;
if (framesBuffered < pa.sinkStart)
return false;
pa_threaded_mainloop_lock(pa.loop); pa_threaded_mainloop_lock(pa.loop);
pa_stream_cork(pa.sink, 0, NULL, NULL); pa_stream_cork(pa.sink, 0, NULL, NULL);
pa.sinkCorked = false; pa.sinkCorked = false;
pa_threaded_mainloop_unlock(pa.loop); pa_threaded_mainloop_unlock(pa.loop);
return true;
} }
static void pulseaudio_stop(void) static void pulseaudio_stop(void)

View File

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

View File

@ -167,7 +167,7 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
playbackStopNL(); playbackStopNL();
} }
const int bufferFrames = sampleRate / 10; const int bufferFrames = sampleRate;
audio.playback.buffer = ringbuffer_new(bufferFrames, audio.playback.buffer = ringbuffer_new(bufferFrames,
channels * sizeof(uint16_t)); channels * sizeof(uint16_t));
@ -247,17 +247,14 @@ void audio_playbackData(uint8_t * data, size_t size)
if (!STREAM_ACTIVE(audio.playback.state)) if (!STREAM_ACTIVE(audio.playback.state))
return; return;
const int frames = size / audio.playback.stride; int frames = size / audio.playback.stride;
ringbuffer_append(audio.playback.buffer, data, frames); ringbuffer_append(audio.playback.buffer, data, frames);
// don't start playback until the buffer is sifficiently full to avoid if (audio.playback.state == STREAM_STATE_SETUP)
// glitches
if (audio.playback.state == STREAM_STATE_SETUP &&
ringbuffer_getCount(audio.playback.buffer) >=
ringbuffer_getLength(audio.playback.buffer) / 4)
{ {
frames = ringbuffer_getLength(audio.playback.buffer);
if (audio.audioDev->playback.start(frames))
audio.playback.state = STREAM_STATE_RUN; audio.playback.state = STREAM_STATE_RUN;
audio.audioDev->playback.start();
} }
} }