From de039d531b95342f187a3b607fac565e6e4079f5 Mon Sep 17 00:00:00 2001 From: serifpersia Date: Wed, 16 Jul 2025 15:29:51 +0200 Subject: [PATCH] more feedback sync fixes for playback this manages to run at 64 buffer default period around 1.6ms of latency and its stable, but driver needs to be reloaded to get stable audio again if app ran for the second time. Need to find fix for this. --- us144mkii.c | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/us144mkii.c b/us144mkii.c index 9167755..39927af 100644 --- a/us144mkii.c +++ b/us144mkii.c @@ -109,6 +109,7 @@ struct tascam_card { unsigned int feedback_pattern_out_idx; unsigned int feedback_pattern_in_idx; bool feedback_synced; + unsigned int feedback_consecutive_errors; unsigned int feedback_urb_skip_count; u64 playback_frames_consumed; @@ -589,7 +590,8 @@ static int tascam_pcm_prepare(struct snd_pcm_substream *substream) tascam->feedback_pattern_in_idx = 0; tascam->feedback_pattern_out_idx = 0; tascam->feedback_synced = false; - tascam->feedback_urb_skip_count = NUM_FEEDBACK_URBS * 2; + tascam->feedback_consecutive_errors = 0; + tascam->feedback_urb_skip_count = NUM_FEEDBACK_URBS; /* Initialize feedback accumulator with nominal values */ nominal_frames_per_packet = runtime->rate / 8000; @@ -811,6 +813,7 @@ static void feedback_urb_complete(struct urb *urb) unsigned long flags; u64 current_period, total_frames_in_urb = 0; int ret, p; + unsigned int old_in_idx, new_in_idx; if (urb->status) return; @@ -823,20 +826,16 @@ static void feedback_urb_complete(struct urb *urb) spin_lock_irqsave(&tascam->lock, flags); - /* Let a few URBs pass to allow the hardware to stabilize. */ + /* Hybrid Sync: Initial blind period for hardware to settle. */ if (tascam->feedback_urb_skip_count > 0) { tascam->feedback_urb_skip_count--; goto unlock_and_resubmit; } - /* After the initial skip, we consider the stream synced. */ - if (!tascam->feedback_synced) { - dev_dbg(tascam->card->dev, "Sync Acquired!\n"); - tascam->feedback_synced = true; - } + old_in_idx = tascam->feedback_pattern_in_idx; for (p = 0; p < urb->number_of_packets; p++) { - u8 feedback_value = 0; /* Initialize to a known invalid value */ + u8 feedback_value = 0; const unsigned int *pattern; bool packet_ok = (urb->iso_frame_desc[p].status == 0 && urb->iso_frame_desc[p].actual_length >= 1); @@ -846,8 +845,8 @@ static void feedback_urb_complete(struct urb *urb) if (packet_ok && feedback_value >= tascam->feedback_base_value && feedback_value <= tascam->feedback_max_value) { - /* Valid Feedback: Use the pattern from the table. */ pattern = tascam->feedback_patterns[feedback_value - tascam->feedback_base_value]; + tascam->feedback_consecutive_errors = 0; int i; for (i = 0; i < 8; i++) { unsigned int in_idx = (tascam->feedback_pattern_in_idx + i) % FEEDBACK_ACCUMULATOR_SIZE; @@ -855,26 +854,43 @@ static void feedback_urb_complete(struct urb *urb) total_frames_in_urb += pattern[i]; } } else { - /* Invalid Feedback: Use the nominal pattern as a fallback. */ unsigned int nominal_frames = runtime->rate / 8000; int i; - if (packet_ok) /* Only log if the packet itself was ok but the value was not */ - dev_warn_ratelimited(tascam->card->dev, "Invalid feedback value %u, using nominal rate.\n", feedback_value); - + if (tascam->feedback_synced) { + tascam->feedback_consecutive_errors++; + if (tascam->feedback_consecutive_errors > 10) { + dev_warn_ratelimited(tascam->card->dev, "Feedback sync lost! (value: %u, errors: %u)\n", + feedback_value, tascam->feedback_consecutive_errors); + tascam->feedback_synced = false; + } + } for (i = 0; i < 8; i++) { unsigned int in_idx = (tascam->feedback_pattern_in_idx + i) % FEEDBACK_ACCUMULATOR_SIZE; tascam->feedback_accumulator_pattern[in_idx] = nominal_frames; total_frames_in_urb += nominal_frames; } } - /* Always advance the accumulator index */ tascam->feedback_pattern_in_idx = (tascam->feedback_pattern_in_idx + 8) % FEEDBACK_ACCUMULATOR_SIZE; } + new_in_idx = tascam->feedback_pattern_in_idx; + + /* Hybrid Sync: Pointer Lap check for sync acquisition. */ + if (!tascam->feedback_synced) { + unsigned int out_idx = tascam->feedback_pattern_out_idx; + bool is_ahead = (new_in_idx - out_idx) % FEEDBACK_ACCUMULATOR_SIZE < (FEEDBACK_ACCUMULATOR_SIZE / 2); + bool was_behind = (old_in_idx - out_idx) % FEEDBACK_ACCUMULATOR_SIZE >= (FEEDBACK_ACCUMULATOR_SIZE / 2); + + if (is_ahead && was_behind) { + dev_dbg(tascam->card->dev, "Sync Acquired! (in: %u, out: %u)\n", new_in_idx, out_idx); + tascam->feedback_synced = true; + tascam->feedback_consecutive_errors = 0; + } + } + if (total_frames_in_urb > 0) tascam->playback_frames_consumed += total_frames_in_urb; - /* Check if a period has elapsed and notify ALSA */ current_period = div_u64(tascam->playback_frames_consumed, runtime->period_size); if (current_period > tascam->last_period_pos) { tascam->last_period_pos = current_period; @@ -892,6 +908,8 @@ resubmit: dev_err_ratelimited(tascam->card->dev, "Failed to resubmit feedback URB: %d\n", ret); } + + static int tascam_create_pcm(struct tascam_card *tascam) { struct snd_pcm *pcm;