From da957141b4bc52a5f4ba7f80ff7e5f7b5cddb651 Mon Sep 17 00:00:00 2001 From: pstruebi Date: Thu, 23 Oct 2025 18:32:59 +0200 Subject: [PATCH] refactor: simplify clock drift compensation with hardcoded parameters and improved frame drop logic --- src/auracast/auracast_config.py | 1 - src/auracast/multicast.py | 25 +++++++++++-------------- src/auracast/multicast_script.py | 1 - 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/auracast/auracast_config.py b/src/auracast/auracast_config.py index 06d855f..a283392 100644 --- a/src/auracast/auracast_config.py +++ b/src/auracast/auracast_config.py @@ -42,7 +42,6 @@ class AuracastGlobalConfig(BaseModel): assisted_listening_stream: bool = False # Clock drift compensation: discard excess samples when buffer exceeds threshold enable_drift_compensation: bool = False - drift_threshold_ms: float = 2.0 # Discard threshold in milliseconds # "Audio input. " # "'device' -> use the host's default sound input device, " diff --git a/src/auracast/multicast.py b/src/auracast/multicast.py index 7d5444f..7e7a7c0 100644 --- a/src/auracast/multicast.py +++ b/src/auracast/multicast.py @@ -651,19 +651,22 @@ class Streamer(): bigs = self.bigs self.is_streaming = True - # Sample discard stats (clock drift compensation) + # frame drop algo parameters sample_rate = big['audio_input']._pcm_format.sample_rate samples_discarded_total = 0 # Total samples discarded discard_events = 0 # Number of times we discarded samples frames_since_last_discard = 999 # Guard: frames since last discard (start high to allow first drop) enable_drift_compensation = global_config.enable_drift_compensation - discard_guard_frames = sample_rate // 100 # Don't allow discard within this many frames of previous discard - # Calculate threshold based on config (default 2ms) - drift_threshold_ms = global_config.drift_threshold_ms if global_config.enable_drift_compensation else 0 + # Hardcoded parameters (unit: milliseconds) + drift_threshold_ms = 2.0 if enable_drift_compensation else 0.0 + static_drop_ms = 0.5 if enable_drift_compensation else 0.0 + # Guard interval measured in LC3 frames (10 ms each); 50 => 500 ms cooldown + discard_guard_frames = int(2*sample_rate / 1000) if enable_drift_compensation else 0 + # Derived sample counts drop_threshold_samples = int(sample_rate * drift_threshold_ms / 1000.0) - static_drop_samples = int(sample_rate * 0.0005) # Always drop a static amount of samples - - if global_config.enable_drift_compensation: + static_drop_samples = int(sample_rate * static_drop_ms / 1000.0) + + if enable_drift_compensation: logging.info(f"Clock drift compensation ENABLED: threshold={drift_threshold_ms}ms, guard={discard_guard_frames} frames") else: logging.info("Clock drift compensation DISABLED") @@ -699,12 +702,6 @@ class Streamer(): stream_finished[i] = True continue - # Calculate threshold samples based on sample rate (only once per BIG) - if enable_drift_compensation and drop_threshold_samples == 0: - drop_threshold_samples = int(sample_rate * drift_threshold_ms / 1000.0) - logging.info(f"Drift compensation threshold: {drop_threshold_samples} samples ({drift_threshold_ms}ms @ {sample_rate}Hz)") - logging.info(f"Static drop amount: {static_drop_samples} samples (3.0ms @ {sample_rate}Hz)") - # Discard excess samples in buffer if above threshold (clock drift compensation) if enable_drift_compensation and hasattr(big['audio_input'], '_stream') and big['audio_input']._stream: sd_buffer_samples = big['audio_input']._stream.read_available @@ -713,7 +710,7 @@ class Streamer(): if sd_buffer_samples > drop_threshold_samples and frames_since_last_discard >= discard_guard_frames: # Always drop a static amount (3ms) for predictable behavior # This matches the crossfade duration better for smoother transitions - samples_to_drop = static_drop_samples + samples_to_drop = min(static_drop_samples, max(1, big['lc3_frame_samples'] - 1)) try: discarded_data = await anext(big['audio_input'].frames(samples_to_drop)) samples_discarded_total += samples_to_drop diff --git a/src/auracast/multicast_script.py b/src/auracast/multicast_script.py index 1f410b2..1c71f3e 100644 --- a/src/auracast/multicast_script.py +++ b/src/auracast/multicast_script.py @@ -111,7 +111,6 @@ if __name__ == "__main__": octets_per_frame = OCTETS_PER_FRAME, transport=TRANSPORT1, enable_drift_compensation=True, - drift_threshold_ms=2.0 ) config.debug = False