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) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01UWZuYkHBRqNb6BZHV8sTG5
This commit is contained in:
torlando-agent[bot]
2026-06-24 23:19:57 -04:00
co-authored by Claude Opus 4.8
parent 6f9ebf5570
commit 0922c0de31
+12 -8
View File
@@ -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;
}
}