An offline-first acoustic mesh network that transmits data over sound
This project was built at IC Hack 2026. For motivation, see our Devpost page.
EchoMesh is a peer-to-peer mesh network application that enables communication between devices using sound waves instead of traditional wireless protocols. Using the ggwave library, messages are encoded into audio frequencies and transmitted through device speakers, then received and decoded by nearby device microphones.
This enables communication in scenarios where:
- No internet or cellular connectivity is available
- Radio silence is required (no RF emissions)
- Quick ad-hoc networks need to be established
- Short-range, line-of-sight communication is sufficient
- Data-Over-Sound Transmission — Send and receive messages using acoustic signals
- Automatic Mesh Relay — Messages automatically hop through intermediate nodes to reach their destination
- Voice Input — Speak your message using speech recognition
- Text-to-Speech — Incoming messages are read aloud with a preparation countdown for relay
- Real-time Statistics — Track sent, received, relayed, and dropped messages
- Deduplication — Smart packet tracking prevents message loops in the mesh
- Broadcast & Direct Messaging — Send to everyone (
ALL) or specific callsigns - Persistent State — Callsign and settings survive page refreshes
- Responsive Design — Works on desktop and mobile browsers
- An emergency needs to be reported to a destination that is not directly accessible without a middleman relaying the message.
- Initial sender types or uses speech to text to input text.
- Text is converted into a waveform transmission using multi-frequency frequency-shift keying (FSK). The bit rate is 16/bytes per second (equivalent to speaking at 192 wpm). Transmissions have a header and a body:
- The header identifies the sender, receiver and also has time to live (the number of hops before the message is discarded).
- The body contains the message.
- Using the first device's speaker the transmission is played into the walkie-talkie.
- Nearby walkie-talkies receive and play the transmission into their corresponding device's microphone.
- The app interprets the transmission and decides what to do next depending on the header of the message.
- If our current receiver is the intended recipient (identified in the header) then the transmission chain is terminated.
- If the time to live reaches 0 the message is discarded.
- If either of these conditions is not met, the message is relayed with a decremented time to live.
- If the intended recipient receives the transmission, it is interpreted and the text body is read out using text to speech.
Messages are transmitted as compact packets with the following format:
uid8|from|dest|ttl|body
| Field | Description |
|---|---|
uid8 |
8-character unique identifier for deduplication |
from |
Sender's callsign |
dest |
Destination callsign or ALL for broadcast |
ttl |
Time-to-live (hop count remaining) |
body |
Message content |
- Receive — When a packet is received, it's checked against seen messages
- Deduplicate — If already seen, the packet is dropped to prevent loops
- Accept — If the message is for this node (or broadcast), it's displayed
- Relay — If TTL > 0 and message needs forwarding, a countdown begins
- Transmit — After the countdown (and TTS), the packet is relayed with decremented TTL
- Sample Rate: 48,000 Hz
- Protocol: DT_FASTEST (optimized for speed)
- Max Packet Size: 140 bytes
- Volume: 100% for reliable transmission
- Node.js 18+
- A modern browser with Web Audio API support (Chrome, Firefox, Edge, Safari)
- Microphone access permission
# Clone the repository
git clone https://github.com/yourusername/echomesh.git
cd echomesh
# Install dependencies
npm install
# Start development server
npm run devThe app will be available at http://localhost:5173 (and on your local network if using --host).
npm run build
npm run preview- Set Your Callsign — Enter a unique identifier in the callsign field (e.g.,
ALPHA,BASE1) - Start Listening — Click the "START LISTENING" button to begin receiving messages
- Send a Message — Type a message and click "SEND" or press Enter
- Broadcast: Leave destination as
ALLto send to everyone in range - Direct Message: Enter a specific callsign (e.g.,
BRAVO) to send to that node only - Voice Input: Click the microphone button to speak your message
When a message arrives:
- A purple banner appears while the message is read aloud (TTS)
- If relaying is needed, a yellow countdown banner appears
- Position your device near a walkie-talkie or other relay device during countdown
- The message is automatically retransmitted after the countdown
| Color | Meaning |
|---|---|
| Green border | Ready / Idle |
| Purple border | TTS speaking or voice input active |
| Yellow border | Relay countdown in progress |
| Orange border | Receiving audio |
| Blue border | Transmitting audio |
- React 19 — UI framework
- TypeScript — Type-safe JavaScript
- Vite — Fast build tool and dev server
- Tailwind CSS v4 — Utility-first styling
- Zustand — Lightweight state management
- ggwave — Data-over-sound encoding/decoding (WASM)
- Web Audio API — Audio capture and playback
- Web Speech API — Text-to-speech and speech recognition
src/
├── App.tsx # Main UI component
├── store.ts # Zustand state management
├── types.d.ts # TypeScript type definitions
└── hooks/
├── useAudioModem.ts # ggwave TX/RX logic
├── useTextToSpeech.ts # TTS functionality
└── useSpeechRecognition.ts # Voice input
Key constants in the codebase:
| Constant | Value | Location |
|---|---|---|
MAX_PACKET_SIZE |
140 bytes | App.tsx |
RELAY_DELAY |
2000ms | useAudioModem.ts |
DEFAULT_TTL |
3 hops | store.ts |
SAMPLE_RATE |
48000 Hz | useAudioModem.ts |
| Browser | TX | RX | TTS | Voice Input |
|---|---|---|---|---|
| Chrome | Yes | Yes | Yes | Yes |
| Firefox | Yes | Yes | Yes | Limited |
| Safari | Yes | Yes | Yes | Yes |
| Edge | Yes | Yes | Yes | Yes |
Note: HTTPS is required for microphone access on most browsers.
MIT License — see LICENSE for details.
- ggwave by Georgi Gerganov for the incredible data-over-sound library
- Built at IC Hack 2026