From 0922c0de31270e89d24eb11245aef9085da62334 Mon Sep 17 00:00:00 2001 From: "torlando-agent[bot]" <281092095+torlando-agent[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:19:57 -0400 Subject: [PATCH] fix(voice): send real batch_len, not hardcoded BATCH_BYTES=82, on the call wire call_send_audio_batch shipped a fixed 82-byte bin8 payload+length, correct only for 8-B/frame Codec2 (3200/1600). The ULBW default is 700C at 4 B/frame -> a 42-B batch, so every packet carried 40 B of uninitialized stack and a bin8 length that lied (82 vs 42): pyxis<->pyxis decoded to SILENCE (RX 6400 > 5120 output guard -> ring underrun), pyxis->a length-driven peer (Columba/Python) decoded 10 real + 10 stack-noise frames = audible GARBAGE. Use the batch_len the caller already computes. ULBW stays default (LoRa-first). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01UWZuYkHBRqNb6BZHV8sTG5 --- lib/tdeck_ui/UI/LXMF/UIManager.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/tdeck_ui/UI/LXMF/UIManager.cpp b/lib/tdeck_ui/UI/LXMF/UIManager.cpp index 1c4b4f33..ba579017 100644 --- a/lib/tdeck_ui/UI/LXMF/UIManager.cpp +++ b/lib/tdeck_ui/UI/LXMF/UIManager.cpp @@ -1153,8 +1153,12 @@ void UIManager::call_send_audio_batch(const uint8_t* batch_data, int batch_len, // Each batch = [codec_type(0x02)] + [mode_header] + [10 * raw_codec2]. // Columba's native ring buffer expects exactly frameSamples (1600) decoded // samples per writeEncodedPacket call. For Codec2 3200: 10 * 160 = 1600. - // batch_data contains batch_count concatenated batches of 82 bytes each. - static constexpr int BATCH_BYTES = 82; // codec_type(1) + mode(1) + 10*8 + // batch_data contains batch_count concatenated batches of batch_len bytes each. + // FIX: was a hardcoded BATCH_BYTES=82 (correct only for 8-byte/frame modes like + // 3200/1600); the shipping ULBW default is Codec2-700C at 4 B/frame -> the real batch + // is 42 B. The 82 mis-sized every 700C packet on the wire (40 B of uninitialized stack + // + a bin8 length that lies): pyxis<->pyxis SILENCE, pyxis->length-driven peer GARBAGE. + // Use batch_len, the exact length the caller already computed. uint8_t packet_buf[256]; int pos = 0; @@ -1165,17 +1169,17 @@ void UIManager::call_send_audio_batch(const uint8_t* batch_data, int batch_len, if (batch_count == 1) { // Single batch: bare bin8 packet_buf[pos++] = 0xC4; // bin8 - packet_buf[pos++] = (uint8_t)BATCH_BYTES; - memcpy(packet_buf + pos, batch_data, BATCH_BYTES); - pos += BATCH_BYTES; + packet_buf[pos++] = (uint8_t)batch_len; + memcpy(packet_buf + pos, batch_data, batch_len); + pos += batch_len; } else { // Multiple batches: fixarray(N) of bin8 entries packet_buf[pos++] = 0x90 | (uint8_t)batch_count; // fixarray(N), N≤15 for (int b = 0; b < batch_count; b++) { packet_buf[pos++] = 0xC4; // bin8 - packet_buf[pos++] = (uint8_t)BATCH_BYTES; - memcpy(packet_buf + pos, batch_data + b * BATCH_BYTES, BATCH_BYTES); - pos += BATCH_BYTES; + packet_buf[pos++] = (uint8_t)batch_len; + memcpy(packet_buf + pos, batch_data + b * batch_len, batch_len); + pos += batch_len; } }