• Stars
    star
    1,955
  • Rank 23,715 (Top 0.5 %)
  • Language
    C++
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Serverless, peer-to-peer, local file sharing through sound

wave-share

A proof-of-concept for WebRTC signaling using sound. Works with all devices that have microphone + speakers. Runs in the browser.

Nearby devices negotiate the WebRTC connection by exchanging the necessary Session Description Protocol (SDP) data via a sequence of audio tones. Upon successful negotiation, a local WebRTC connection is established between the browsers allowing data to be exchanged via LAN.

See it in action (2min video):

CG++ Data over sound

Try it yourself: ggerganov.github.io/wave-share

Latest news:
I've extracted the data-over-sound algorithm into a standalone library called ggwave.
It can be embedded easily into other projects.

How it works

The WebRTC technology allows two browsers running on different devices to connect with each other and exchange data. There is no need to install plugins or download applications. To initiate the connection, the peers exchange contact information (ip address, network ports, session id, etc.). This process is called "signaling". The WebRTC specification does not define any standard for signaling - the contact exchange can be achieved by any protocol or technology.

In this project the signaling is performed via sound. The signaling sequence looks like this:

  • Peer A broadcasts an offer for a WebRTC connection by encoding the session data into audio tones
  • Nearby peer(s) capture the sound emitted by peer A and decode the WebRTC session data
  • Peer B, who wants to establish connection with peer A, responds with an audio answer. The answer has peer B's contact information encoded in it. Additionally, peer B starts trying to connect to peer A
  • Peer A receives the answer from peer B, decodes the transmitted contact data and allows peer B to connect
  • Connection is established

The described signaling sequence does not involve a signaling server. Therefore, an application using signaling through sound can be, for example, served by a static web page. The only requirement is to have control over the audio output/capture devices.

An obvious limitation (feature) of the current approach is that only nearby devices (e.g. within the same room) can establish connection with each other. Moreover, the devices have to be connected in the same local network, because NAT is not available.

Sound Tx/Rx

The data communicated through sound contains the contact information required to initialize the WebRTC connection. This data is stored in the Session Description Protocol (SDP) format. Since data-over-sound has significant limitations in terms of bandwidth and robustness it is desirable to transmit as few data as possible. Therefore, the SDP is stripped from all irrelevant information and only the essential data needed to establish the connection is transmitted. Currently, the sound packet containing the minimum required SDP data has the following format:

Size, [B] Description
1 Type of the SDP - Offer or Answer
1 Packet size in bytes (not including ECC bytes)
4 IP address of the transmitting peer
2 Network port that will be used for the communication
32 SHA-256 fingerprint of the session data
40 ICE Credentials - 16 bytes username + 24 bytes password
32 ECC correction bytes used to correct errors during Tx

The total size of the audio packet is 112 bytes. With the current audio encoding algorithm, the SDP packet can be transmitted in 5-10 seconds (depending on the Tx protocol used). Using slower protocols provides more reliable transmission in noisy environments or if the communicating devices are far from each other.

Data-to-sound encoding

The current approach uses a multi-frequency Frequency-Shift Keying (FSK) modulation scheme. The data to be transmitted is first split into 4-bit chunks. At each moment of time, 3 bytes are transmitted using 6 tones - one tone for each 4-bit chunk. The 6 tones are emitted in a 4.5kHz range divided in 96 equally-spaced frequencies:

Freq, [Hz] Value, [bits] Freq, [Hz] Value, [bits] ... Freq, [Hz] Value, [bits]
F0 + 00*dF Chunk 0: 0000 F0 + 16*dF Chunk 1: 0000 ... F0 + 80*dF Chunk 5: 0000
F0 + 01*dF Chunk 0: 0001 F0 + 17*dF Chunk 1: 0001 ... F0 + 81*dF Chunk 5: 0001
F0 + 02*dF Chunk 0: 0010 F0 + 18*dF Chunk 1: 0010 ... F0 + 82*dF Chunk 5: 0010
... ... ... ... ... ... ...
F0 + 14*dF Chunk 0: 1110 F0 + 30*dF Chunk 1: 1110 ... F0 + 94*dF Chunk 5: 1110
F0 + 15*dF Chunk 0: 1111 F0 + 31*dF Chunk 1: 1111 ... F0 + 95*dF Chunk 5: 1111

For all protocols: dF = 46.875 Hz. For non-ultrasonic protocols: F0 = 1875.000 Hz. For ultrasonic protocols: F0 = 15000.000 Hz.

Getting the local IP address

For convenience, a simple WebRTC hack is used to automatically detect the local IP address of your machine, so you don't have to provide it manually. However, the latest WebRTC spec prevents this from being possible for security reasons, so at some point this "feature" will stop working in all browsers. For example, it no longer works on Safari.

Build

Web Assembly module wave.wasm

You will need an Emscripten compiler. Run the compile.sh script.

CLI tool wave-share


Important: This CLI tool was the prototype for the now standalone library ggwave. Make sure to check it out, as it has more up-to-date examples for the application of this data-over-sound type of communication.


This is a simple tool that receives and sends data using the explained wave-share sound tx/rx protocol. Type some text on the standard input and press Enter to transmit.

# build
git clone https://github.com/ggerganov/wave-share
cd wave-share && mkdir build && cd build
cmake ..
make

# running
./wave-share

Here is a short video demonstrating how to use the CLI tool:

Wave-share: command line tool

Known problems / stuff to improve

  • Does not work with: IE, IE Edge, Chrome/Firefox on iOS, Safari on macOS
  • Ultrasonic sound transmission does not work on most devices. Probably hardware limitations?
  • In presence of multiple local networks, cannot currently select which one to use. Always the first one is used
  • There is occasionally sound cracking during transmission. Need to optimize the Tx code
  • The size of the emscripten generated .js is too big (~1MB). Rewrite in pure JS?
  • On mobile, using Firefox, the page can remain running in the background even after closing the tab

More Repositories

1

llama.cpp

LLM inference in C/C++
C++
66,953
star
2

whisper.cpp

Port of OpenAI's Whisper model in C/C++
C++
33,134
star
3

ggml

Tensor library for machine learning
C++
10,796
star
4

kbd-audio

🎤⌨️ Acoustic keyboard eavesdropping
C++
7,569
star
5

imtui

ImTui: Immediate Mode Text-based User Interface C++ Library
C++
2,421
star
6

ggwave

Tiny data-over-sound library
C++
1,496
star
7

imgui-ws

Dear ImGui over WebSockets
C++
373
star
8

dot-to-ascii

Graphviz to ASCII converter using Graph::Easy
HTML
371
star
9

hnterm

📃 Hacker News in the terminal
C++
144
star
10

ggmorse

Morse code decoding library
C++
136
star
11

whisper.spm

whisper.cpp package for the Swift Package Manager
C
120
star
12

tweet2doom

Tweet to play Doom
Shell
83
star
13

wave-gui

Yet another data-over-sound tool
C++
70
star
14

wtf-tui

Text-based UI tool for configuring the WTF terminal dashboard
C++
66
star
15

incppect

Inspect C++ memory in the browser
C++
63
star
16

ggweb

Template for C++ GUI apps that can run in the browser
C
54
star
17

ggterm

Terminal configuration for C++ development with Vim
Vim Script
34
star
18

diff-challenge

Is this even possible?
Shell
27
star
19

wordle-bg

🇧🇬 Wordle clone in Bulgarian
C++
27
star
20

hnreplies

Scrape Hacker News replies
C++
22
star
21

intervals

Downsampling array of intervals
C++
21
star
22

wave-em

Data over sound in the browser
C++
20
star
23

typing-battles

A multiplayer typing game (server: C++/WebSockets, client: JS)
C++
18
star
24

morse-meme

Meme generator in Bash
Shell
16
star
25

tweet2doom-data

@tweet2doom data and tools
JavaScript
16
star
26

ggwave-java

Minimal Java app for Android using ggwave
Java
14
star
27

ggwave-arduino

Mirror of ggwave used in the Arduino Library Manager
C++
14
star
28

imgui-em

Emscripten port of Dear ImGui (not maintained)
C++
14
star
29

ggwave-objc

Minimal Objective-C app for iOS using ggwave
Objective-C
10
star
30

ggwords

Generate language n-gram statistics
C++
10
star
31

ggerganov.github.io

JavaScript
10
star
32

imtui-template

Template repo for simple ImTui apps
C++
9
star
33

ggwave-spm

ggwave package for the Swift Package Manager
C++
8
star
34

asteroid-generator

The demo generates and renders asteroids floating in space. The shape and the texture of the generated asteroids are procedurally generated. The space background is procedurally generated as well.
C++
7
star
35

ggint

Poor man's big integer arithmetic operations
C++
6
star
36

ggsock

Non-blocking sockets wrapper
C++
5
star
37

hnguessr

Guess the Hacker News titles
C++
5
star
38

ggimg

Poor man's 2d and 3d image operations
C++
4
star
39

load-em

Load a local file in C++ Emscripten program
HTML
4
star
40

the-story

Collaborative storytelling experiment
HTML
4
star
41

tweet2btc

BTC price predictions via Twitter Polls
Shell
3
star
42

site-wave-share

A dedicated page for the wave-share tool:
JavaScript
3
star
43

ocl-lights

Pixel perfect 2D shadows on the GPU
C++
3
star
44

font-rasterizer

Simple TTF rasterizer
C
3
star
45

toto-check

See how many times you could have won the lottery
HTML
3
star
46

puzzle-solver

C++
2
star
47

OSSRH-94491

Jira
1
star
48

homebrew-ggerganov

My Homebrew tap for projects that are not notable enough
Ruby
1
star