Voice is the reason MeshTRX exists, and the thing similar LoRa projects usually do not have. Here is how voice in MeshTRX works: why it should not have been possible, what had to go, and what we paid for it.
Every number below comes from the firmware and client sources, not from the project description.
Why voice over LoRa is considered impossible
LoRa was not designed for conversations. Its job is to carry a dozen bytes from a humidity sensor to a gateway, on microwatts, across several kilometres and through walls. Everything else follows from that: slow modulation, narrow bandwidth, small packets.
At the MeshTRX settings — SF7, 250 kHz bandwidth, 4/7 coding rate — the channel gives about 7.8 kbps. That is on paper, before the preamble, the headers and the gaps between transmissions, so the real figure is noticeably lower.
For comparison: GSM voice runs at 13 kbps, and the most modest internet call at 8–16 kbps. The usual ways of carrying speech do not fit into this channel at all. Not "work poorly" — do not fit. The problem MeshTRX set out to solve starts exactly here.
Codec2: voice as a description, not as sound
The way out was not better compression but a different approach.
An ordinary codec stores the sound wave — more or less accurately, but the wave itself. Codec2 by David Rowe works differently: it is a vocoder. It does not transmit the waveform at all. What goes on air instead is a description of how the speech was shaped at that moment: pitch, energy, spectral envelope. At the far end the decoder synthesises speech anew from that description, from scratch.
MeshTRX uses mode 3200 — 3200 bits per second. It is the same codec in the same mode across all three parts of the project: the radio firmware, the Android app and the desktop client. One frame is 20 ms of audio, 160 samples at an 8 kHz sampling rate, and it fits into 8 bytes.
Eight bytes per twenty milliseconds of speech. That is the whole point: 3200 bps fit into the channel with almost a twofold margin, leaving room for control data, text and files.
What is inside a packet
Every 80 ms the MeshTRX firmware assembles one packet: four consecutive Codec2 frames — 32 bytes. Seven bytes of header go with them:
| Byte | Field | Purpose |
|---|---|---|
| 0 | type | What this is: audio, text, file, control |
| 1 | channel | Channel number, 0–22 |
| 2 | seq | Packet sequence number |
| 3 | flags | Start and end of transmission, voice activation |
| 4 | ttl | How many more hops are allowed |
| 5–6 | sender | Last two bytes of the MAC — who is speaking |
A complete MeshTRX voice packet looks like this:
That makes 39 bytes on air, 32 of them actual speech. The header takes almost a fifth of the packet, and that is not waste: without seq the receiver would not notice a loss, without flags it would not know the transmission has ended, without ttl the packet would circle the network forever.
Why four frames and not eight or sixteen? The more frames in a packet, the smaller the header's share — but the longer audio accumulates before it is sent, and the more each loss costs. Eighty milliseconds turned out to be the compromise: a lost packet cuts out less than a tenth of a second of speech, which sounds like a click rather than a hole in the middle of a word.
Half-duplex and the ten-second limit
A MeshTRX radio has one antenna and one transceiver. While it transmits, it does not receive. Not "receives worse" — does not receive at all.
From this follows something mesh network descriptions usually leave out: while one person is speaking, nobody else is in the channel. Not just their correspondent — everyone. No one can answer, cut in, or call for help. The channel belongs to whoever pressed the button, for exactly as long as they hold it.
That is why a transmission in MeshTRX is capped at ten seconds. The limit sits in two places at once: in the app, where the button counts down, and in the radio itself, as a constant in the firmware. The second one is not code redundancy but protection against an entirely ordinary case: the phone froze, the system killed the app, the button got pressed inside a pocket. The radio then goes silent on its own and shows LIMIT 10s on its screen.
Ten seconds is enough for a meaningful sentence and not enough for a monologue. That is the intent.
Where the delay comes from
There is waiting in several places, and the first of them cannot be removed: until 80 ms of speech has accumulated, there is nothing to send. That is the floor, set by the packet size.
On top of it come the Bluetooth hop to the radio, the packet's time on air — a few tens of milliseconds, the Bluetooth hop back into someone else's phone, and the receive buffer that smooths out the uneven arrival of packets.
The result is a delay you get used to within a minute but cannot fail to notice. It changes the shape of a conversation in MeshTRX: it goes the way it goes on a radio, not on a phone — speak, release, wait for the answer. Interrupting is pointless anyway, since nobody can hear you while the other station is transmitting.
What we paid for it
The honest part.
Voices are harder to recognise. Codec2 3200, the mode MeshTRX runs on, is not compressed audio but resynthesised speech. Words are clear, intonation is mostly there, but timbre is the first thing a vocoder gives up: you will probably recognise someone close to you, but you will not always tell one stranger from another.
Speech only. The model assumes a single speaker. Music, wind noise, a second voice in the background simply do not survive the trip — what comes out is mush.
The air is open. MeshTRX has no encryption yet, packets travel in the clear, and anyone with the same module can receive them. A shared per-channel key is planned, but that is how it stands today.
The range figure is honest, not promotional. The five kilometres claimed for MeshTRX mean line of sight. In a city, in a forest, between floors it will be less, sometimes much less. A repeater helps, but it also occupies the channel.
What is next
Voice is the most visible part of MeshTRX but not the only one: text, files, map positions and the radar live in the same network. How MeshTRX works as a whole and how to use it is in the documentation. What we are doing next and what we deliberately dropped is on the about page.
Questions and remarks go to the Telegram group. The sources, including everything described here, are on GitHub.