|
30 | 30 | #include <signal.h> |
31 | 31 | #include <pthread.h> |
32 | 32 | #include <stdatomic.h> |
| 33 | +#include <fcntl.h> |
| 34 | +#include <sys/ioctl.h> |
| 35 | +#include <linux/videodev2.h> |
33 | 36 |
|
34 | 37 | // ARM NEON SIMD optimizations (Cortex-A7 accelerates buffer operations, with scalar fallback) |
35 | 38 | #include <arm_neon.h> |
36 | 39 |
|
| 40 | +// TC358743 V4L2 control IDs for audio |
| 41 | +#ifndef V4L2_CID_USER_TC35874X_BASE |
| 42 | +#define V4L2_CID_USER_TC35874X_BASE (V4L2_CID_USER_BASE + 0x10a0) |
| 43 | +#endif |
| 44 | +#define TC35874X_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC35874X_BASE + 0) |
| 45 | + |
37 | 46 | // RV1106 (Cortex-A7) has 64-byte cache lines |
38 | 47 | #define CACHE_LINE_SIZE 64 |
39 | 48 | #define SIMD_ALIGN __attribute__((aligned(16))) |
@@ -209,6 +218,42 @@ static volatile sig_atomic_t playback_initialized = 0; |
209 | 218 |
|
210 | 219 | // ALSA UTILITY FUNCTIONS |
211 | 220 |
|
| 221 | +/** |
| 222 | + * Query TC358743 HDMI receiver for detected audio sample rate |
| 223 | + * Reads the hardware-detected sample rate from V4L2 control |
| 224 | + * @return detected sample rate (44100, 48000, etc.) or 0 if detection fails |
| 225 | + */ |
| 226 | +static unsigned int get_hdmi_audio_sample_rate(void) { |
| 227 | + int fd = open("/dev/video0", O_RDWR); |
| 228 | + if (fd < 0) { |
| 229 | + fprintf(stderr, "WARNING: Could not open /dev/video0 to query HDMI audio sample rate: %s\n", strerror(errno)); |
| 230 | + fflush(stderr); |
| 231 | + return 0; |
| 232 | + } |
| 233 | + |
| 234 | + struct v4l2_control control = {0}; |
| 235 | + control.id = TC35874X_CID_AUDIO_SAMPLING_RATE; |
| 236 | + |
| 237 | + if (ioctl(fd, VIDIOC_G_CTRL, &control) == -1) { |
| 238 | + fprintf(stderr, "WARNING: Could not query TC358743 audio sample rate control: %s\n", strerror(errno)); |
| 239 | + fflush(stderr); |
| 240 | + close(fd); |
| 241 | + return 0; |
| 242 | + } |
| 243 | + |
| 244 | + close(fd); |
| 245 | + |
| 246 | + unsigned int detected_rate = (unsigned int)control.value; |
| 247 | + if (detected_rate == 0) { |
| 248 | + return 0; // No signal or rate not detected |
| 249 | + } |
| 250 | + |
| 251 | + fprintf(stdout, "INFO: TC358743 detected HDMI audio sample rate: %u Hz\n", detected_rate); |
| 252 | + fflush(stdout); |
| 253 | + |
| 254 | + return detected_rate; |
| 255 | +} |
| 256 | + |
212 | 257 | /** |
213 | 258 | * Open ALSA device with exponential backoff retry |
214 | 259 | * @return 0 on success, negative error code on failure |
@@ -365,12 +410,13 @@ static int handle_alsa_error(snd_pcm_t *handle, snd_pcm_t **valid_handle, |
365 | 410 | * @param handle ALSA PCM handle |
366 | 411 | * @param device_name Device name for logging |
367 | 412 | * @param num_channels Number of channels (1=mono, 2=stereo) |
| 413 | + * @param preferred_rate Preferred sample rate (0 = use default 48kHz) |
368 | 414 | * @param actual_rate_out Pointer to store the actual hardware-negotiated rate |
369 | 415 | * @param actual_frame_size_out Pointer to store the actual frame size at hardware rate |
370 | 416 | * @return 0 on success, negative error code on failure |
371 | 417 | */ |
372 | 418 | static int configure_alsa_device(snd_pcm_t *handle, const char *device_name, uint8_t num_channels, |
373 | | - unsigned int *actual_rate_out, uint16_t *actual_frame_size_out) { |
| 419 | + unsigned int preferred_rate, unsigned int *actual_rate_out, uint16_t *actual_frame_size_out) { |
374 | 420 | snd_pcm_hw_params_t *params; |
375 | 421 | snd_pcm_sw_params_t *sw_params; |
376 | 422 | int err; |
@@ -410,8 +456,8 @@ static int configure_alsa_device(snd_pcm_t *handle, const char *device_name, uin |
410 | 456 | return err; |
411 | 457 | } |
412 | 458 |
|
413 | | - // Try to set 48kHz first (preferred), then let hardware negotiate |
414 | | - unsigned int requested_rate = opus_sample_rate; |
| 459 | + // Use preferred rate if specified, otherwise default to 48kHz |
| 460 | + unsigned int requested_rate = (preferred_rate > 0) ? preferred_rate : opus_sample_rate; |
415 | 461 | err = snd_pcm_hw_params_set_rate_near(handle, params, &requested_rate, 0); |
416 | 462 | if (err < 0) return err; |
417 | 463 |
|
@@ -540,9 +586,19 @@ int jetkvm_audio_capture_init() { |
540 | 586 | return ERR_ALSA_OPEN_FAILED; |
541 | 587 | } |
542 | 588 |
|
| 589 | + // Query TC358743 for detected HDMI audio sample rate |
| 590 | + unsigned int preferred_rate = get_hdmi_audio_sample_rate(); |
| 591 | + if (preferred_rate > 0) { |
| 592 | + fprintf(stdout, "INFO: Using TC358743 detected sample rate: %u Hz\n", preferred_rate); |
| 593 | + } else { |
| 594 | + fprintf(stdout, "INFO: TC358743 sample rate not detected, using default 48kHz\n"); |
| 595 | + preferred_rate = 0; // Will default to 48kHz |
| 596 | + } |
| 597 | + fflush(stdout); |
| 598 | + |
543 | 599 | unsigned int actual_rate = 0; |
544 | 600 | uint16_t actual_frame_size_with_flag = 0; |
545 | | - err = configure_alsa_device(pcm_capture_handle, "capture", capture_channels, &actual_rate, &actual_frame_size_with_flag); |
| 601 | + err = configure_alsa_device(pcm_capture_handle, "capture", capture_channels, preferred_rate, &actual_rate, &actual_frame_size_with_flag); |
546 | 602 | if (err < 0) { |
547 | 603 | snd_pcm_t *handle = pcm_capture_handle; |
548 | 604 | pcm_capture_handle = NULL; |
@@ -819,7 +875,7 @@ int jetkvm_audio_playback_init() { |
819 | 875 |
|
820 | 876 | unsigned int actual_rate = 0; |
821 | 877 | uint16_t actual_frame_size = 0; |
822 | | - err = configure_alsa_device(pcm_playback_handle, "playback", playback_channels, &actual_rate, &actual_frame_size); |
| 878 | + err = configure_alsa_device(pcm_playback_handle, "playback", playback_channels, 0, &actual_rate, &actual_frame_size); |
823 | 879 | if (err < 0) { |
824 | 880 | snd_pcm_t *handle = pcm_playback_handle; |
825 | 881 | pcm_playback_handle = NULL; |
|
0 commit comments