Add automatic HDMI sample rate change detection

Implement periodic polling (every ~1 second) to detect HDMI audio sample
rate changes and trigger automatic reconfiguration. This prevents audio
distortion when switching between 44.1kHz and 48kHz sources.

Key changes:
- Poll TC358743 V4L2 control every 50 frames in capture hot path
- Trigger reconnection when sample rate changes
- Optimize logging to only output on rate changes (reduces log spam)
- Add proper state tracking to prevent duplicate logging
- Fix comment accuracy and ensure all state updates are consistent

Performance impact: ~100-500μs overhead every second (~0.01-0.05% CPU)
This commit is contained in:
Alex P 2025-11-24 23:06:12 +02:00
parent 8debd07b04
commit cc7e6081da
1 changed files with 36 additions and 10 deletions

View File

@ -267,23 +267,34 @@ static unsigned int get_hdmi_audio_sample_rate(void) {
close(fd); close(fd);
unsigned int detected_rate = (unsigned int)ext_ctrl.value; unsigned int detected_rate = (unsigned int)ext_ctrl.value;
static unsigned int last_logged_rate = 0; // Track last logged rate to suppress duplicate messages
if (detected_rate == 0) { if (detected_rate == 0) {
fprintf(stdout, "INFO: TC358743 reports 0 Hz (no HDMI signal or audio not detected yet)\n"); if (last_logged_rate != 0) {
fprintf(stdout, " Will use 48kHz default and resample if needed when signal detected\n"); fprintf(stdout, "INFO: TC358743 reports 0 Hz (no HDMI signal or audio not detected yet)\n");
fflush(stdout); fprintf(stdout, " Will use 48kHz default and resample if needed when signal detected\n");
return 0; // No signal or rate not detected - this is expected during hotplug fflush(stdout);
last_logged_rate = 0;
}
return 0;
} }
// Validate detected rate is reasonable // Validate detected rate is reasonable (log warning only on rate changes)
if (detected_rate < 8000 || detected_rate > 192000) { if (detected_rate < 8000 || detected_rate > 192000) {
fprintf(stderr, "WARNING: TC358743 reported unusual sample rate: %u Hz (expected 32k-192k)\n", detected_rate); if (detected_rate != last_logged_rate) {
fprintf(stderr, " Using detected rate anyway, but audio may not work correctly\n"); fprintf(stderr, "WARNING: TC358743 reported unusual sample rate: %u Hz (expected 32k-192k)\n", detected_rate);
fflush(stderr); fprintf(stderr, " Using detected rate anyway, but audio may not work correctly\n");
fflush(stderr);
last_logged_rate = detected_rate;
}
} }
fprintf(stdout, "INFO: TC358743 detected HDMI audio sample rate: %u Hz\n", detected_rate); // Log rate changes and update tracking state to suppress duplicate logging
fflush(stdout); if (detected_rate != last_logged_rate) {
fprintf(stdout, "INFO: TC358743 detected HDMI audio sample rate: %u Hz\n", detected_rate);
fflush(stdout);
last_logged_rate = detected_rate;
}
return detected_rate; return detected_rate;
} }
@ -800,6 +811,7 @@ __attribute__((hot)) int jetkvm_audio_read_encode(void * __restrict__ opus_buf)
// Two buffers: hardware buffer + resampled buffer (at 48kHz) // Two buffers: hardware buffer + resampled buffer (at 48kHz)
static short CACHE_ALIGN pcm_hw_buffer[MAX_HARDWARE_FRAME_SIZE * 2]; // Max hardware rate * stereo static short CACHE_ALIGN pcm_hw_buffer[MAX_HARDWARE_FRAME_SIZE * 2]; // Max hardware rate * stereo
static short CACHE_ALIGN pcm_opus_buffer[960 * 2]; // 48kHz @ 20ms * 2 channels static short CACHE_ALIGN pcm_opus_buffer[960 * 2]; // 48kHz @ 20ms * 2 channels
static uint16_t sample_rate_check_counter = 0;
unsigned char * __restrict__ out = (unsigned char*)opus_buf; unsigned char * __restrict__ out = (unsigned char*)opus_buf;
int32_t pcm_rc, nb_bytes; int32_t pcm_rc, nb_bytes;
int32_t err = 0; int32_t err = 0;
@ -852,6 +864,20 @@ retry_read:
} }
} }
// Periodic sample rate change detection (every 50 frames = ~1 second)
if (__builtin_expect(++sample_rate_check_counter >= 50, 0)) {
sample_rate_check_counter = 0;
unsigned int current_rate = get_hdmi_audio_sample_rate();
if (current_rate != 0 && current_rate != hardware_sample_rate) {
fprintf(stderr, "ERROR: capture: HDMI sample rate changed from %u to %u Hz\n",
hardware_sample_rate, current_rate);
fprintf(stderr, " Triggering reconnection for automatic reconfiguration\n");
fflush(stderr);
pthread_mutex_unlock(&capture_mutex);
return -1;
}
}
if (__builtin_expect(pcm_rc < hardware_frame_size, 0)) { if (__builtin_expect(pcm_rc < hardware_frame_size, 0)) {
uint32_t remaining_samples = (hardware_frame_size - pcm_rc) * capture_channels; uint32_t remaining_samples = (hardware_frame_size - pcm_rc) * capture_channels;
simd_clear_samples_s16(&pcm_hw_buffer[pcm_rc * capture_channels], remaining_samples); simd_clear_samples_s16(&pcm_hw_buffer[pcm_rc * capture_channels], remaining_samples);