mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-07-02 00:06:09 -04:00
milan-avb: AAF media-clock recovery estimator + play-loop actuator + io_changed, SET_CLOCK_SOURCE switch, skip CRF audio data plane
This commit is contained in:
parent
66959ca678
commit
90114c9839
5 changed files with 465 additions and 0 deletions
63
src/modules/module-avb/play-loop.h
Normal file
63
src/modules/module-avb/play-loop.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* AVB support */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
/*
|
||||
* play-loop.h — consume-side actuator for the listener.
|
||||
*
|
||||
* Pure (no PipeWire deps) so it can be unit-tested like mc-recover.h. Keeps the
|
||||
* listener ring at a target fill by trimming the output resampler ratio
|
||||
* (SPA_IO_RateMatch). Same loop as module-rtp's receiver:
|
||||
* error = target - avail; corr = spa_dll_update(dll, error); rate = ff / corr
|
||||
* ff = nominal/recovered rate feeds the recovered clock forward; the DLL trims
|
||||
* the rest. The sign is the trap (same as the old mc_recover bug); test_play_loop
|
||||
* locks it: converges on the right sign, diverges on the wrong one.
|
||||
*/
|
||||
|
||||
#ifndef AVB_PLAY_LOOP_H
|
||||
#define AVB_PLAY_LOOP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/dll.h>
|
||||
|
||||
struct play_loop {
|
||||
bool init;
|
||||
struct spa_dll dll;
|
||||
double corr; /* DLL output, ~1.0 */
|
||||
double rate; /* last applied resampler ratio (ff / corr) */
|
||||
};
|
||||
|
||||
static inline void play_loop_reset(struct play_loop *p)
|
||||
{
|
||||
p->init = false;
|
||||
p->corr = 1.0;
|
||||
p->rate = 1.0;
|
||||
}
|
||||
|
||||
/* One step. error_samples = target - avail; max_error clamps a transient;
|
||||
* ff_ratio = nominal/recovered rate (1.0 = no feedforward). Returns the ratio
|
||||
* to apply via pw_stream_set_rate(). */
|
||||
static inline double play_loop_update(struct play_loop *p, double error_samples,
|
||||
double max_error, double ff_ratio, unsigned period, unsigned rate)
|
||||
{
|
||||
if (!p->init) {
|
||||
spa_dll_init(&p->dll);
|
||||
spa_dll_set_bw(&p->dll, SPA_DLL_BW_MIN, period, rate);
|
||||
p->corr = 1.0;
|
||||
p->rate = ff_ratio;
|
||||
p->init = true;
|
||||
}
|
||||
error_samples = SPA_CLAMPD(error_samples, -max_error, max_error);
|
||||
p->corr = spa_dll_update(&p->dll, error_samples);
|
||||
/* clamp ±10 %, guards 1/corr */
|
||||
if (p->corr < 0.9)
|
||||
p->corr = 0.9;
|
||||
else if (p->corr > 1.1)
|
||||
p->corr = 1.1;
|
||||
p->rate = ff_ratio / p->corr;
|
||||
return p->rate;
|
||||
}
|
||||
|
||||
#endif /* AVB_PLAY_LOOP_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue