mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-13 07:17:28 +00:00
[client] audio: minimize LGMP playback latency
Scope the legacy latency offset to classic SPICE and use the LGMP poll bound as its fixed arrival reserve. Keep learned jitter additive. Select provider clock feedback only when the current remote endpoint advertises it, avoiding a failed startup attempt on broker v1.
This commit is contained in:
@@ -853,6 +853,7 @@ if(ENABLE_AUDIO)
|
||||
recovery
|
||||
stable-underrun
|
||||
resume
|
||||
latency-policy
|
||||
consent
|
||||
quiesce
|
||||
)
|
||||
|
||||
@@ -660,7 +660,8 @@ static void testPlaybackRecovery(void)
|
||||
startAudio();
|
||||
|
||||
const LG_AudioFormat format = makeFormat(LG_AUDIO_FMT_S16_LE);
|
||||
CHECK(playbackStart(&format, NULL, false, false));
|
||||
const PlaybackPolicy policy = playbackPolicyFromOps(&ops);
|
||||
CHECK(playbackStart(&format, NULL, false, false, &policy));
|
||||
CHECK(audio.playback.rateControl == PLAYBACK_RATE_BACKEND);
|
||||
playbackSetState(STREAM_STATE_RUN);
|
||||
|
||||
@@ -708,7 +709,8 @@ static void testPlaybackStableUnderrun(void)
|
||||
startAudio();
|
||||
|
||||
const LG_AudioFormat format = makeFormat(LG_AUDIO_FMT_S16_LE);
|
||||
CHECK(playbackStart(&format, NULL, false, false));
|
||||
const PlaybackPolicy policy = playbackPolicyFromOps(&ops);
|
||||
CHECK(playbackStart(&format, NULL, false, false, &policy));
|
||||
CHECK(audio.playback.rateControl == PLAYBACK_RATE_BACKEND);
|
||||
playbackSetState(STREAM_STATE_RUN);
|
||||
|
||||
@@ -892,6 +894,91 @@ static void testPlaybackResume(void)
|
||||
stopAudio();
|
||||
}
|
||||
|
||||
static bool testClockFeedback(void * opaque, uint32_t generation,
|
||||
const LG_AudioClock * clock, double targetRate)
|
||||
{
|
||||
(void)opaque;
|
||||
(void)generation;
|
||||
(void)clock;
|
||||
(void)targetRate;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool testClockFeedbackAvailable(void * opaque)
|
||||
{
|
||||
return *(const bool *)opaque;
|
||||
}
|
||||
|
||||
static void testLatencyPolicy(void)
|
||||
{
|
||||
LG_AudioOps providerOps = ops;
|
||||
PlaybackPolicy policy = playbackPolicyFromOps(&providerOps);
|
||||
CHECK(policy.flags == 0);
|
||||
CHECK(policy.arrivalReserveUs ==
|
||||
PLAYBACK_DEFAULT_ARRIVAL_RESERVE_US);
|
||||
CHECK(playbackComputeLatencyOffsetFrames(
|
||||
false, &policy, 6, 48000) == 0.0);
|
||||
|
||||
providerOps.playbackFlags =
|
||||
LG_AUDIO_PLAYBACK_LEGACY_LATENCY_OFFSET;
|
||||
policy = playbackPolicyFromOps(&providerOps);
|
||||
CHECK(playbackComputeLatencyOffsetFrames(
|
||||
false, &policy, 6, 48000) == 288.0);
|
||||
CHECK(playbackComputeLatencyOffsetFrames(
|
||||
true, &policy, 6, 48000) == 0.0);
|
||||
|
||||
providerOps.playbackFlags = 0;
|
||||
providerOps.playbackArrivalReserveUs = 250;
|
||||
const PlaybackPolicy lowLatencyPolicy =
|
||||
playbackPolicyFromOps(&providerOps);
|
||||
CHECK(lowLatencyPolicy.arrivalReserveUs == 250);
|
||||
CHECK(fabs(playbackArrivalReserveFrames(
|
||||
0.0, 48000, lowLatencyPolicy.arrivalReserveUs) - 12.0) < 0.001);
|
||||
CHECK(fabs(playbackArrivalReserveFrames(
|
||||
0.010, 48000, lowLatencyPolicy.arrivalReserveUs) - 492.0) <
|
||||
0.001);
|
||||
|
||||
CHECK(validOps(&providerOps));
|
||||
providerOps.playbackFlags = 1U << 31;
|
||||
CHECK(!validOps(&providerOps));
|
||||
providerOps.playbackFlags = 0;
|
||||
providerOps.playbackArrivalReserveUs =
|
||||
PLAYBACK_MAX_ARRIVAL_RESERVE_US + 1U;
|
||||
CHECK(!validOps(&providerOps));
|
||||
|
||||
providerOps.playbackArrivalReserveUs = 0;
|
||||
providerOps.clockFeedback = testClockFeedback;
|
||||
CHECK(playbackProviderRateControlAvailable(&providerOps, NULL));
|
||||
providerOps.clockFeedbackAvailable = testClockFeedbackAvailable;
|
||||
bool feedbackAvailable = false;
|
||||
CHECK(!playbackProviderRateControlAvailable(
|
||||
&providerOps, &feedbackAvailable));
|
||||
feedbackAvailable = true;
|
||||
CHECK(playbackProviderRateControlAvailable(
|
||||
&providerOps, &feedbackAvailable));
|
||||
providerOps.clockFeedback = NULL;
|
||||
CHECK(!validOps(&providerOps));
|
||||
|
||||
reset();
|
||||
startAudio();
|
||||
const LG_AudioFormat format = makeFormat(LG_AUDIO_FMT_S16_LE);
|
||||
const PlaybackPolicy defaultPolicy = playbackPolicyFromOps(&ops);
|
||||
CHECK(playbackStart(&format, NULL, false, false, &defaultPolicy));
|
||||
CHECK(atomic_load(&b.setupN) == 1);
|
||||
|
||||
playbackSetState(STREAM_STATE_KEEP_ALIVE);
|
||||
CHECK(playbackStart(&format, NULL, false, false, &defaultPolicy));
|
||||
CHECK(atomic_load(&b.setupN) == 1);
|
||||
CHECK(playbackGetState() == STREAM_STATE_RESUMING);
|
||||
|
||||
playbackSetState(STREAM_STATE_KEEP_ALIVE);
|
||||
CHECK(playbackStart(
|
||||
&format, NULL, false, false, &lowLatencyPolicy));
|
||||
CHECK(atomic_load(&b.setupN) == 2);
|
||||
CHECK(playbackGetState() == STREAM_STATE_SETUP_SOURCE);
|
||||
stopAudio();
|
||||
}
|
||||
|
||||
static void testConsent(void)
|
||||
{
|
||||
reset();
|
||||
@@ -1022,6 +1109,7 @@ static const struct Test tests[] =
|
||||
{ "recovery" , testPlaybackRecovery },
|
||||
{ "stable-underrun", testPlaybackStableUnderrun },
|
||||
{ "resume" , testPlaybackResume },
|
||||
{ "latency-policy" , testLatencyPolicy },
|
||||
{ "consent" , testConsent },
|
||||
{ "quiesce" , testQuiesce },
|
||||
};
|
||||
|
||||
@@ -308,6 +308,10 @@ static bool fixtureInit(struct Fixture * fixture)
|
||||
CHECK(lgmpAudio_connect(fixture->audio, fixture->clientID));
|
||||
fixture->ops = lgmpAudio_getOps();
|
||||
CHECK(fixture->ops);
|
||||
CHECK(fixture->ops->playbackFlags == 0);
|
||||
CHECK(fixture->ops->playbackArrivalReserveUs == 250);
|
||||
CHECK(fixture->ops->clockFeedbackAvailable);
|
||||
CHECK(!fixture->ops->clockFeedbackAvailable(fixture->audio));
|
||||
fixture->endpointGeneration = UINT64_C(0x100000001);
|
||||
return true;
|
||||
}
|
||||
@@ -930,6 +934,7 @@ static bool testDataPlane(void)
|
||||
};
|
||||
CHECK(!fixture.ops->clockFeedback(fixture.audio, playbackLocal,
|
||||
&playbackClock, 192000.0));
|
||||
CHECK(!fixture.ops->clockFeedbackAvailable(fixture.audio));
|
||||
|
||||
const uint64_t currentPlayWire =
|
||||
UINT64_C(0x300000000) + KVMFR_AUDIO_MAX_CHANNELS - 1;
|
||||
@@ -946,6 +951,7 @@ static bool testDataPlane(void)
|
||||
captureWire, &captureFormat));
|
||||
CHECK(waitCount(&fixture, &fixture.trace.statusCount,
|
||||
clockStatusBefore + 1, WAIT_MS));
|
||||
CHECK(fixture.ops->clockFeedbackAvailable(fixture.audio));
|
||||
CHECK(fixture.ops->clockFeedback(fixture.audio, playbackLocal,
|
||||
&playbackClock, 192000.0));
|
||||
CHECK(readC2HType(&fixture, KVMFR_AUDIO_MESSAGE_CLOCK_FEEDBACK,
|
||||
|
||||
Reference in New Issue
Block a user