Skip to content

hippowenc/chipchat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

83 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ChipChat 🎛️💬

ChipChat is a decentralized, peer-to-peer (P2P) chat and voice communication application written in Rust. It utilizes the modern libp2p networking stack and tokio asynchronous runtime to establish direct, authenticated connections between clients. The system handles challenging network topologies using rendezvous peer discovery and interactive hole punching, falling back gracefully to circuit relay nodes when direct communication is impossible.


🏗️ Architecture & Protocols

ChipChat runs on a decentralized architecture where peers coordinate using a hybrid peer discovery and relay infrastructure.

sequenceDiagram
    participant Client A
    participant Rendezvous Server (VM)
    participant Client B

    Note over Client A, Client B: Peer Bootstrapping
    Client A->>Rendezvous Server (VM): Dial & Identify
    Client A->>Rendezvous Server (VM): Register Namespace ("chat")
    Client B->>Rendezvous Server (VM): Dial & Identify
    Client B->>Rendezvous Server (VM): Register Namespace ("chat")

    Note over Client A, Client B: Peer Discovery (Periodic 30s)
    Client A->>Rendezvous Server (VM): Discover Peers in "chat"
    Rendezvous Server (VM)-->>Client A: Discovered Client B (with Multiaddrs)

    Note over Client A, Client B: Connection Establishment
    Client A->>Client B: Dial directly
    rect rgb(240, 248, 255)
        Note over Client A, Client B: If Direct Dial Fails (behind NAT)
        Client A->>Client B: Request Direct Connection Utility (DCUTR) Hole-Punch
        alt Hole-punch succeeds
            Client A<<->>Client B: Direct QUIC / TCP Stream Established
        else Hole-punch fails
            Client A<<->>Client B: Route via Circuit Relay (STUN/Relay VM)
        end
    end

    Note over Client A, Client B: Communication Sessions
    Client A->>Client B: Open Stream (/chat/text/1.0.0 or /chat/audio/1.0.0)
    Client A<<-->>Client B: Exchange Text Messages / Raw PCM Audio Frames
Loading

Key Networking Components

  • Rendezvous Protocol (libp2p-rendezvous): A directory service namespace registration protocol. Client instances register their addresses with a central cloud-hosted server (stun binary) and query it periodically (every 30 seconds) to obtain a live list of other online clients.
  • Direct Connection Utility for Hole Punching (libp2p-dcutr): Enables decentralized hole punching. When two peers behind NATs learn of each other, they execute a synchronized connection attempt to establish direct sockets.
  • Circuit Relay Client/Server (libp2p-relay): A fallback transport mechanism. If direct hole punching fails (e.g., behind symmetric NATs), the clients establish relay connections using a cloud relay server (stun binary acting as a relay node) to route traffic securely.
  • Identity & Identification (libp2p-identify): Automatically exchanges local P2P keypairs, protocols, and observed external addresses between nodes.
  • Substream Protocol multiplexing (libp2p-stream): Dynamically manages custom application-layer streams over existing connection channels.

🎙️ Audio Engine Architecture

ChipChat includes a real-time, low-latency duplex voice-calling engine built using cpal (Cross-Platform Audio Library) for raw I/O.

Frame Formatting

Audio is packetized and transmitted as binary frames over the /chat/audio/1.0.0 protocol. Each packet is formatted as follows:

Field Size Data Type Description
Sequence Number 8 Bytes u64 (Big-Endian) Monotonically increasing ID for packet reordering.
Sample Rate 4 Bytes u32 (Big-Endian) The sample rate of the recorded audio (default: 16000 Hz).
Payload Length 4 Bytes u32 (Big-Endian) The size of the sample payload in bytes.
Samples Variable [u8] Raw little-endian f32 PCM mono audio samples.

Jitter Buffer & Resampling

To counter network jitter and heterogeneous audio hardware configurations, the audio receiver features:

  1. Out-of-Order Reordering: Incoming audio packets are temporarily buffered in a BTreeMap key-value store, indexed by their sequence number. The playback thread continuously pulls the next contiguous packet (next_seq), dropping frames that arrive too late (beyond a configured threshold of AUDIO_JITTER_BUFFER_MAX).
  2. Linear Resampler: Local hardware outputs often run at arbitrary rates (e.g., 44100 Hz or 48000 Hz) while the network stream defaults to 16000 Hz. The playback module runs a linear interpolation algorithm to resample incoming floating-point PCM buffers from their source sample rate to the local hardware output rate.
  3. Headless & File I/O Fallback: If no physical audio input or output hardware is present, ChipChat falls back gracefully:
    • Reads inputs from a raw byte file named audio_input.raw.
    • Writes incoming playback streams to a file named audio_output.raw.

🔐 Cryptographic Identities

In addition to the default libp2p cryptographic handshake (Noise protocol over QUIC/TCP), ChipChat implements application-level user identities using Ethereum-style cryptography:

  • Local Keys: Upon first launch, the client generates a secp256k1 private key saved to src/user/identity.key (Ethereum format) alongside a standard libp2p cryptographic keypair at src/user/libp2p.key.
  • Ethereum Address: The client derives a 20-byte Ethereum-compatible hex address from the public key, representing the user's secure signature identity.
  • Message Verification: The Message struct bundles the payload, sender address, and a signature. The receiver uses local crypto tools to recover the public key from the signed message string (i.e. recover_address_from_msg using alloy-signer & alloy-primitives) and matches it against the sender's address to prevent impersonation.

📂 Project Structure

.
├── Cargo.toml               # Cargo package configuration
├── Cargo.lock               # Pinned rust dependencies
├── test.txt                 # Example serialized signed message representation
└── src/
    ├── main.rs              # Client application entry point (swarm builder, main loop)
    ├── lib.rs               # Library configuration exporting utility modules
    ├── constants.rs         # System parameters (ports, intervals, sample rates, buffers)
    ├── logs.txt             # Swarm runtime logger output file
    ├── stun/
    │   └── main.rs          # Rendezvous + Relay server daemon entry point
    ├── crypto/
    │   ├── mod.rs           
    │   └── message.rs       # Message representation and cryptographic verification
    ├── network/
    │   ├── mod.rs           
    │   ├── behaviour.rs     # Swarm custom behavior definitions (gossipsub, dcutr, relay, rendezvous)
    │   ├── gossip.rs        # Pubsub topics and serialization helpers
    │   ├── chat.rs          # Direct /chat/text/1.0.0 stream handler and state manager
    │   └── audio.rs         # Direct /chat/audio/1.0.0 voice-call capture, playback, and resampling
    └── user/
        ├── mod.rs           
        ├── user.rs          # User representation and signing functions
        ├── identity.key     # Auto-generated secp256k1 private key
        ├── libp2p.key       # Auto-generated libp2p cryptographic node key
        └── names.txt        # Local mapping of Peer IDs to user nicknames

⚙️ Configuration

System parameters can be adjusted directly in src/constants.rs:

  • VM Infrastructure:
    • VM_IP: The public IP of the coordination server (default: 35.223.40.184).
    • VM_LISTENING_PORT: The listening port of the coordination server (default: 3478).
    • VM_PEER_ID: The static libp2p PeerId of the server.
  • Tuning:
    • DISCOVERY_INTERVAL_SECS: Interval in seconds for client discoveries (default: 30).
    • IDLE_TIMEOUT_SECS: Connection idle timeout before dropping inactive peers.
  • Audio Tuning:
    • AUDIO_SAMPLE_RATE: Capture sample rate (default: 16000).
    • AUDIO_JITTER_BUFFER_MAX: Maximum sequence range for the jitter buffer (default: 50 frames).
    • AUDIO_FALLBACK_INPUT/AUDIO_FALLBACK_OUTPUT: Fallback files for headless execution.

🚀 Getting Started

📋 Prerequisites

To compile and run this application, make sure you have the Rust toolchain installed. On Linux platforms, you also need to install the development packages for ALSA (Audio APIs):

# Ubuntu/Debian
sudo apt-get install libasound2-dev

🏃 Running the Server (STUN / Relay / Rendezvous)

If you wish to host your own rendezvous server or deploy to a virtual machine:

cargo run --bin stun

Note: Make sure to copy the printed server PeerId on launch and update VM_PEER_ID in src/constants.rs if self-hosting.

🏃 Running the Client

To launch the client application:

cargo run --bin FinalProject

On launch, the client automatically loads/generates its local cryptographic identities, dials the rendezvous server, requests circuit-relay reservations, and prints available console commands.


⌨️ CLI Console Commands Reference

Upon successful connection, you enter the ChipChat shell. Use the following commands:

  • cmds: Lists all currently available commands.
  • list: Displays a list of all discovered online peers with their index, Peer ID, and resolved addresses.
  • rename <PeerId> <nickname>: Map a long Peer ID string to a friendly name.
  • chat <index>: Establish a direct P2P text chat session with the peer at the specified list index.
  • call <index>: Initiate a direct P2P voice call with the peer at the specified list index.
  • hangup: End the active call or chat session and return to the main lobby.
  • quit: Write the active peer nickname mappings back to src/user/names.txt and shut down the node.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages