|
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,54 @@ 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 | + // TC358743 is a V4L2 subdevice at /dev/v4l-subdev2 |
| 228 | + int fd = open("/dev/v4l-subdev2", O_RDWR); |
| 229 | + if (fd < 0) { |
| 230 | + fprintf(stderr, "WARNING: Could not open /dev/v4l-subdev2 to query HDMI audio sample rate: %s\n", strerror(errno)); |
| 231 | + fflush(stderr); |
| 232 | + return 0; |
| 233 | + } |
| 234 | + |
| 235 | + // Use extended controls API for custom V4L2 controls |
| 236 | + struct v4l2_ext_control ext_ctrl = {0}; |
| 237 | + ext_ctrl.id = TC35874X_CID_AUDIO_SAMPLING_RATE; |
| 238 | + |
| 239 | + struct v4l2_ext_controls ext_ctrls = {0}; |
| 240 | + ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_USER; |
| 241 | + ext_ctrls.count = 1; |
| 242 | + ext_ctrls.controls = &ext_ctrl; |
| 243 | + |
| 244 | + if (ioctl(fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) == -1) { |
| 245 | + fprintf(stderr, "WARNING: Could not query TC358743 audio sample rate control: %s (errno=%d)\n", strerror(errno), errno); |
| 246 | + fflush(stderr); |
| 247 | + close(fd); |
| 248 | + return 0; |
| 249 | + } |
| 250 | + |
| 251 | + close(fd); |
| 252 | + |
| 253 | + unsigned int detected_rate = (unsigned int)ext_ctrl.value; |
| 254 | + fprintf(stdout, "DEBUG: TC358743 control read returned: %u Hz (error_idx=%u)\n", detected_rate, ext_ctrls.error_idx); |
| 255 | + fflush(stdout); |
| 256 | + |
| 257 | + if (detected_rate == 0) { |
| 258 | + fprintf(stdout, "INFO: TC358743 reports 0 Hz (no signal or rate not detected yet)\n"); |
| 259 | + fflush(stdout); |
| 260 | + return 0; // No signal or rate not detected |
| 261 | + } |
| 262 | + |
| 263 | + fprintf(stdout, "INFO: TC358743 detected HDMI audio sample rate: %u Hz\n", detected_rate); |
| 264 | + fflush(stdout); |
| 265 | + |
| 266 | + return detected_rate; |
| 267 | +} |
| 268 | + |
212 | 269 | /** |
213 | 270 | * Open ALSA device with exponential backoff retry |
214 | 271 | * @return 0 on success, negative error code on failure |
@@ -365,12 +422,13 @@ static int handle_alsa_error(snd_pcm_t *handle, snd_pcm_t **valid_handle, |
365 | 422 | * @param handle ALSA PCM handle |
366 | 423 | * @param device_name Device name for logging |
367 | 424 | * @param num_channels Number of channels (1=mono, 2=stereo) |
| 425 | + * @param preferred_rate Preferred sample rate (0 = use default 48kHz) |
368 | 426 | * @param actual_rate_out Pointer to store the actual hardware-negotiated rate |
369 | 427 | * @param actual_frame_size_out Pointer to store the actual frame size at hardware rate |
370 | 428 | * @return 0 on success, negative error code on failure |
371 | 429 | */ |
372 | 430 | 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) { |
| 431 | + unsigned int preferred_rate, unsigned int *actual_rate_out, uint16_t *actual_frame_size_out) { |
374 | 432 | snd_pcm_hw_params_t *params; |
375 | 433 | snd_pcm_sw_params_t *sw_params; |
376 | 434 | int err; |
@@ -410,8 +468,8 @@ static int configure_alsa_device(snd_pcm_t *handle, const char *device_name, uin |
410 | 468 | return err; |
411 | 469 | } |
412 | 470 |
|
413 | | - // Try to set 48kHz first (preferred), then let hardware negotiate |
414 | | - unsigned int requested_rate = opus_sample_rate; |
| 471 | + // Use preferred rate if specified, otherwise default to 48kHz |
| 472 | + unsigned int requested_rate = (preferred_rate > 0) ? preferred_rate : opus_sample_rate; |
415 | 473 | err = snd_pcm_hw_params_set_rate_near(handle, params, &requested_rate, 0); |
416 | 474 | if (err < 0) return err; |
417 | 475 |
|
@@ -540,9 +598,19 @@ int jetkvm_audio_capture_init() { |
540 | 598 | return ERR_ALSA_OPEN_FAILED; |
541 | 599 | } |
542 | 600 |
|
| 601 | + // Query TC358743 for detected HDMI audio sample rate |
| 602 | + unsigned int preferred_rate = get_hdmi_audio_sample_rate(); |
| 603 | + if (preferred_rate > 0) { |
| 604 | + fprintf(stdout, "INFO: Using TC358743 detected sample rate: %u Hz\n", preferred_rate); |
| 605 | + } else { |
| 606 | + fprintf(stdout, "INFO: TC358743 sample rate not detected, using default 48kHz\n"); |
| 607 | + preferred_rate = 0; // Will default to 48kHz |
| 608 | + } |
| 609 | + fflush(stdout); |
| 610 | + |
543 | 611 | unsigned int actual_rate = 0; |
544 | 612 | 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); |
| 613 | + err = configure_alsa_device(pcm_capture_handle, "capture", capture_channels, preferred_rate, &actual_rate, &actual_frame_size_with_flag); |
546 | 614 | if (err < 0) { |
547 | 615 | snd_pcm_t *handle = pcm_capture_handle; |
548 | 616 | pcm_capture_handle = NULL; |
@@ -819,7 +887,7 @@ int jetkvm_audio_playback_init() { |
819 | 887 |
|
820 | 888 | unsigned int actual_rate = 0; |
821 | 889 | uint16_t actual_frame_size = 0; |
822 | | - err = configure_alsa_device(pcm_playback_handle, "playback", playback_channels, &actual_rate, &actual_frame_size); |
| 890 | + err = configure_alsa_device(pcm_playback_handle, "playback", playback_channels, 0, &actual_rate, &actual_frame_size); |
823 | 891 | if (err < 0) { |
824 | 892 | snd_pcm_t *handle = pcm_playback_handle; |
825 | 893 | pcm_playback_handle = NULL; |
|
0 commit comments