ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
Session Module Documentation

Session Module Documentation

Overview

The session module (src/common/session/) provides a unified abstraction for managing real-time audio-video sessions in ascii-chat. It encapsulates:

  • Server-side session hosting (client management, media mixing, broadcast)
  • Client-side session participation (connection management, media streaming)
  • Shared session infrastructure (capture, rendering, display, audio handling)
  • Interactive controls (keyboard input, help screens, status displays)

The module is used by all display modes:

  • Server mode: Hosts sessions with multiple connected clients
  • Client mode: Connects to a server and streams media
  • Mirror mode: Local testing without networking
  • Discovery mode: P2P session discovery and establishment

Architecture

Participant protocol

protocol.c and protocol.h provide the participant protocol used by native client mode and the discovery WebRTC receiver. Each receive worker has its own session_protocol_t: packet/frame/audio counters, server participant count, and pending layout state. The protocol borrows its transport until the worker joins.

The ACIP receive layer validates packet envelopes and decrypts them before the session protocol dispatches media and control messages. Shared media handling validates and decompresses ASCII frames, checks frame CRCs, dequantizes PCM, and validates Opus batch boundaries before decoding. Decoded buffers are borrowed only for the duration of a callback; a mode that defers presentation must copy them. Callback failures propagate through the receive result, and packet allocations are released on success and failure.

src/client/protocol_adapter.c retains client worker startup, snapshot/display effects, and crypto/control callbacks. Discovery retains negotiation, host migration, audio-device effects, and newest-frame presentation. Both call network_connection_run() and session_protocol_dispatch(); neither implements its own media packet parser. Mirror mode does not use this network protocol.

Core Components

┌─────────────────────────────────────────────────────────────┐
│ Session Module │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Host-Side (Server) │ │ Client-Side (Participant) │
│ ├──────────────────────┤ ├──────────────────────┤ │
│ │ session_host_t │ │ session_participant_t │ │
│ │ - Client management │ │ - Connection mgmt │ │
│ │ - Media mixing │ │ - Stream control │ │
│ │ - Broadcasting │ │ - Frame rendering │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │ │ │
│ └───────────────┬───────────────┘ │
│ │ │
│ ┌───────────────V────────────────┐ │
│ │ Shared Infrastructure │ │
│ ├───────────────────────────────┤ │
│ │ - Capture (capture.h) │ │
│ │ - Display (display.h) │ │
│ │ - Render loop (render.h) │ │
│ │ - Audio handling (audio.h) │ │
│ │ - Keyboard input (keyboard_handler.h) │ │
│ │ - Session settings (settings.h) │ │
│ │ - Consensus protocol (consensus.h) │ │
│ │ - Logging (session_log_buffer.h) │ │
│ └───────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

Component Breakdown

Host-Side (host.h)

Server abstractions for managing client sessions:

  • Lifecycle: Create → Start → Stop → Destroy
  • Client Management: Add, remove, find, list clients
  • Media Injection: For host's own webcam/audio participation
  • Broadcasting: Send ASCII frames to individual clients or broadcast to all
  • Callbacks: Join/leave events, frame/audio received, errors
  • Transport Abstraction: Support for TCP sockets, WebRTC DataChannels, WebSockets

Client-Side (participant.h)

Client abstractions for connecting to sessions:

  • Lifecycle: Create → Connect → Disconnect → Destroy
  • Stream Control: Start/stop video and audio streaming
  • Media Reception: Receive mixed ASCII frames and audio from server
  • Callbacks: Connected/disconnected events, frame/audio received, errors
  • Reconnection: Automatic reconnection on network failure

Shared Client-Like Framework (client_like.h)

Unified initialization framework for client-like modes:

  • Handles boilerplate setup for mirror, client, and discovery modes
  • Media source selection and FPS detection
  • Audio initialization and lifecycle
  • Terminal management and keepawake
  • Splash screen lifecycle
  • Keyboard input integration
  • Proper resource cleanup ordering

Session Lifecycle

Host-Side Lifecycle

1. Configuration
session_host_config_t config = { ... };
2. Creation
host = session_host_create(&config);
→ Host is ready but not accepting connections
3. Start Server
session_host_start(host);
→ Listen for incoming client connections
→ Accept loop running
4. Client Connection
session_host_add_client(host, transport, ACIP_TRANSPORT_BORROWED, ip, port);
→ on_client_join() callback fired
→ Client registered and ready
5. Media Handling
session_host_inject_frame(host, client_id, frame);
→ Frame from host's own webcam
On frame received from client:
→ on_frame_received() callback
6. Rendering (Optional)
session_host_start_render(host);
→ Render thread mixing video/audio
→ Broadcasting frames to all clients
7. Client Disconnection
session_host_remove_client(host, client_id);
→ on_client_leave() callback fired
8. Stop Server
session_host_stop(host);
→ Stop accepting connections
→ Disconnect remaining clients
9. Cleanup
session_host_destroy(host);
→ Free all resources

Client-Side Lifecycle

1. Configuration
session_participant_config_t config = { ... };
2. Creation
participant = session_participant_create(&config);
→ Participant object created
3. Connection
session_participant_connect(participant);
→ Establish connection to server
→ Crypto handshake
→ on_connected() callback fired with assigned ID
4. Stream Control
session_participant_start_video(participant);
session_participant_start_audio(participant);
→ Begin streaming media to server
5. Receiving
Continuously receive frames/audio via callbacks:
→ on_frame_received()
→ on_audio_received()
6. Stream Control
session_participant_stop_video(participant);
session_participant_stop_audio(participant);
→ Stop streaming (optional)
7. Disconnection
session_participant_disconnect(participant);
→ Close connection to server
→ on_disconnected() callback fired
8. Cleanup
session_participant_destroy(participant);
→ Free all resources

Client-Like Mode Lifecycle

1. Configuration
session_client_like_config_t config = {
.media_source = { ... },
.run_fn = mode_specific_main_loop,
...
};
2. Initialization
session_client_like_run(&config)
→ Terminal output check
→ Keepawake system
→ Media source selection
→ FPS probing
→ Audio initialization
→ Display creation
→ Splash screen animation
3. Mode-Specific Loop
mode_specific_main_loop(capture, display, user_data)
→ Network loop (client mode)
→ Render loop (mirror/discovery)
→ Keyboard input handling
→ Protocol handling
4. Cleanup (Automatic)
← Teardown in correct order:
→ Stop render loop
→ Close display
→ Shutdown audio
→ Close media
→ Disable keepawake
→ Restore terminal

Shared Data Structures

Opaque Handles

These are opaque forward-declared types. Implementation details are hidden.

// Host side
// Client side
// Shared
struct session_log_buffer session_log_buffer_t
Thread-safe fixed-size history ring for session-screen log lines.
struct session_participant session_participant_t
Client session state spanning connection, transport, media workers, and callbacks.
struct session_display_ctx session_display_ctx_t
session display config is intentionally a small, concrete record. Fields such as snapshot_mode,...
struct session_host session_host_t
Opaque session host handle.
struct session_capture_ctx session_capture_ctx_t
session capture config keeps the values that move through the subsystem: type, path,...
Runtime state for media loading, frame timing, and source switching.
Runtime terminal state and reusable workspaces for ASCII rendering.
Thread-safe fixed-size history ring for session-screen log lines.
Client session state spanning connection, transport, media workers, and callbacks.
Definition participant.c:58

Configuration Structures

Host Configuration (host.h)

typedef struct {
int port; // Listen port (27224)
const char *ipv4_address; // IPv4 bind address
const char *ipv6_address; // IPv6 bind address
int max_clients; // Max concurrent clients
bool encryption_enabled; // E2E encryption
const char *key_path; // Server identity key
const char *password; // Optional password auth
session_host_callbacks_t callbacks; // Event callbacks
void *user_data; // Context for callbacks
Snapshot of the address, identity, activity, and connection time for one host client.
Definition host.h:108
Host-side event hooks for joins, departures, media, and errors.
Definition host.h:159

Participant Configuration (participant.h)

typedef struct {
const char *address; // Server address
int port; // Server port
bool encryption_enabled; // E2E encryption
const char *key_path; // Client key (optional)
const char *password; // Password auth (optional)
void *user_data; // Context for callbacks
Client-side event hooks for connection, media, settings, and errors.
Definition participant.h:83
Client-side event hooks for connection, media, settings, and errors.

Client-Like Configuration (client_like.h)

typedef struct {
session_media_source_t media_source; // What to capture
session_client_like_run_fn run_fn; // Mode-specific loop
void *run_user_data; // Context for run_fn
// ... audio, display, keyboard config ...
struct session_client_like_config session_client_like_config_t
asciichat_error_t(* session_client_like_run_fn)(session_capture_ctx_t *capture, session_display_ctx_t *display, void *user_data)
This is the handoff point for session client like config. Callers fill run_fn, run_user_data,...

Callback Structures

Host Callbacks

typedef struct {
void (*on_client_join)(session_host_t *h, uint32_t client_id, void *data);
void (*on_client_leave)(session_host_t *h, uint32_t client_id, void *data);
void (*on_frame_received)(session_host_t *h, uint32_t client_id,
const image_t *frame, void *data);
void (*on_audio_received)(session_host_t *h, uint32_t client_id,
const float *samples, size_t count, void *data);
void (*on_error)(session_host_t *h, asciichat_error_t error,
const char *message, void *data);
unsigned int uint32_t
Definition common.h:62
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
SIMD-friendly storage for one RGB pixel. r, g, and b hold the color channels and padding keeps the la...

Participant Callbacks

typedef struct {
void (*on_connected)(session_participant_t *p, uint32_t id, void *data);
void (*on_disconnected)(session_participant_t *p, void *data);
void (*on_frame_received)(session_participant_t *p, const char *frame, void *data);
void (*on_audio_received)(session_participant_t *p,
const float *samples, size_t count, void *data);
void (*on_error)(session_participant_t *p, asciichat_error_t error,
const char *message, void *data);

Log Entry Structure

typedef struct {
char message[SESSION_LOG_LINE_MAX]; // Formatted log (with ANSI colors)
uint64_t sequence; // Monotonic ordering sequence
unsigned long long uint64_t
Definition common.h:63
#define SESSION_LOG_LINE_MAX
One formatted session log line and its monotonic history sequence.

Common Patterns and Utilities

Capture (capture.h)

Purpose: Abstract media source reading (webcam, files, URLs)

Key Functions:

Supported Sources:

  • Webcam (platform-specific)
  • Local files (MP4, MKV, etc. via FFmpeg)
  • URLs (HTTP/HTTPS/RTSP/DASH/HLS)
  • YouTube/TikTok (via yt-dlp)

Display (display.h)

Purpose: Terminal abstraction and ASCII rendering

Key Functions:

Features:

  • Terminal capability detection (ANSI support)
  • Color palette selection
  • Snapshot mode support
  • Help screen integration

Render Loop (render.h)

Purpose: Unified frame processing for all display modes

Two Modes:

  1. Synchronous Mode (with capture context)

    session_render_loop(capture, display, should_exit_fn,
    NULL, NULL, keyboard_handler, user_data);
    asciichat_error_t session_render_loop(session_capture_ctx_t *capture, session_display_ctx_t *display, session_should_exit_fn should_exit, session_capture_fn capture_cb, session_sleep_for_frame_fn sleep_cb, session_keyboard_handler_fn keyboard_handler, void *user_data)
    Unified render loop for all display modes.
    • Capture → ASCII conversion → Render loop
    • Frame rate driven by media source
  2. Event-Driven Mode (with callbacks, no capture)

    session_render_loop(NULL, display, should_exit_fn,
    capture_fn, sleep_fn, keyboard_handler, user_data);
    • Custom frame/sleep callbacks
    • Protocol-driven (client mode)

Audio (audio.h)

Purpose: Audio capture, processing, and playback

Key Functions:

  • session_audio_capture_init() - Start audio input
  • session_audio_capture_read() - Get audio samples
  • session_audio_playback_init() - Start audio output
  • session_audio_playback_write() - Send audio samples
  • Volume control and mixing

Features:

  • Platform abstraction (PortAudio)
  • Format conversion (PCM float)
  • Volume normalization
  • Optional JACK audio system support

Keyboard Input (keyboard_handler.h)

Purpose: Interactive session controls

Supported Controls:

  • ? - Toggle help screen
  • (spacebar) - Play/pause
  • ← / → - Seek ±30s
  • ↑ / ↓ - Volume ±10%
  • m - Mute toggle
  • c - Cycle color modes
  • f - Flip webcam (mirror mode)

Thread-Safe: Can be called from any thread

Session Log Buffer (session_log_buffer.h)

Purpose: Capture logs for status/splash screens

Functions:

Features:

  • Thread-safe circular buffer
  • ANSI color support
  • Automatic sequence numbering

Settings (settings.h)

Purpose: Session-wide configuration and state

Manages:

  • Color mode
  • Pause state
  • Volume level
  • Flip state (for webcam)
  • Help screen visibility

Thread-Safe: Uses RCU (Read-Copy-Update) for atomic access


State Management

Host State Transitions

INIT → RUNNING → STOPPED → DESTROYED
With clients:
RUNNING:
- Clients can join/leave
- Media accepted from clients
- Frames broadcast to all
- Optional rendering thread

Participant State Transitions

INIT → CONNECTING → CONNECTED → STREAMING → DISCONNECTED → DESTROYED
CONNECTED:
- Ready to send/receive frames
- Streams can be started/stopped
STREAMING:
- Actively sending/receiving media

Settings State (Thread-Safe)

All settings use RCU for lock-free reads:

// Read (lock-free)
session_settings_get_volume();
// Write (brief lock, copies old data)
session_settings_set_color_mode(COLOR_MODE_256);
#define COLOR_MODE_256
256-color mode (alias)
Definition options.h:226

Encryption and Authentication

Default Behavior

All connections are encrypted by default using:

  • X25519 - Key exchange
  • XSalsa20-Poly1305 - AEAD symmetric cipher
  • Ed25519 - Signature verification

Authentication Methods

  1. Ephemeral DH (default)
    • Encrypted but no identity verification
    • Keys negotiated at connection time
  2. Password Authentication
    • Both sides prove knowledge of password
    • No long-term keys needed
  3. SSH Key Authentication
    • Server authenticates with Ed25519 key
    • Client verifies against known_hosts
    • TOFU (Trust On First Use) supported

Configuration

// Ephemeral (default)
config.encryption_enabled = true;
// Password
config.password = "secret";
// SSH key
config.key_path = "~/.ssh/id_ed25519";
// Disable (testing only)
config.encryption_enabled = false;

Error Handling

All functions return asciichat_error_t:

if (result != ASCIICHAT_OK) {
if (HAS_ERRNO(&ctx)) {
log_error("Failed: %s", ctx.context_message);
}
return result;
}
#define HAS_ERRNO(context)
@ ASCIICHAT_OK
Definition error_codes.h:46
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
asciichat_error_t session_host_start(session_host_t *host)
Start accepting client connections.
Definition host.c:1037

Consensus Protocol (consensus.h)

The session module implements a consensus protocol for coordinating state across participants:

Purpose

  • Synchronize pause/play state
  • Coordinate media timing
  • Handle late-join clients
  • Support participant discovery

Key Concepts

  • Sequence Numbers: Track state changes
  • Vector Clocks: Causal ordering
  • Gossip Protocol: Distributed state propagation

Typical Usage Patterns

Server with Client Hosting

// Create server host
.port = 27224,
.max_clients = 32,
.callbacks = {
.on_client_join = handle_client_join,
.on_frame_received = handle_frame,
// ...
},
.user_data = app_context
};
// Start accepting clients
// Add host's own participation (optional)
// Start rendering thread (mixes video/audio)
// Cleanup
void session_host_stop_render(session_host_t *host)
Stop media rendering thread.
Definition host.c:1669
asciichat_error_t session_host_destroy(session_host_t *host)
Destroy session host and free resources.
Definition host.c:289
asciichat_error_t session_host_stop(session_host_t *host)
Stop accepting connections and disconnect all clients.
Definition host.c:1076
uint32_t session_host_add_memory_participant(session_host_t *host)
Add a memory participant (host's own media).
Definition host.c:1213
session_host_t * session_host_create(const session_host_config_t *config)
Create a new session host.
Definition host.c:234
asciichat_error_t session_host_start_render(session_host_t *host)
Start media rendering thread (video mixing and audio distribution).
Definition host.c:1632

Client Connection

// Create client participant
.address = "127.0.0.1",
.port = 27224,
.callbacks = {
.on_connected = handle_connected,
.on_frame_received = render_frame,
// ...
},
.user_data = app_context
};
// Connect to server
// Start streaming (automatic after connect)
// Cleanup
asciichat_error_t session_participant_connect(session_participant_t *p)
Connect to session server.
asciichat_error_t session_participant_start_video(session_participant_t *p)
Start video capture and streaming.
void session_participant_destroy(session_participant_t *p)
Destroy session participant and free resources.
session_participant_t * session_participant_create(const session_participant_config_t *config)
Server address, security, media, transport, and callback settings for a participant.
void session_participant_disconnect(session_participant_t *p)
Disconnect from session server.
asciichat_error_t session_participant_start_audio(session_participant_t *p)
Start audio capture and streaming.

Mirror/Discovery Mode (via client_like)

// Configure media source
session_media_source_t source = {
};
// Configure client-like framework
.media_source = source,
.run_fn = my_render_loop,
.run_user_data = my_context,
// ... audio, display config ...
};
// Run unified initialization and mode loop
// All initialization, teardown, and cleanup handled automatically
asciichat_error_t session_client_like_run(const session_client_like_config_t *config)
audio_visualization_source_t source
Definition fft.c:24
@ MEDIA_SOURCE_WEBCAM
Hardware webcam device.
Definition source.h:98

Key Implementation Details

Thread Safety

Host: Thread-safe for all operations

  • Client operations are atomic
  • Callbacks can be from any thread
  • Safe to call from audio/video threads

Participant: Thread-safe for stream control

  • Send operations are async
  • Receive callbacks from dedicated thread
  • Settings updates are RCU-protected

Render Loop: Single-threaded by design

  • Keyboard input can be called from any thread
  • Frame operations must be synchronized by caller

Memory Management

All allocations tracked with SAFE_MALLOC/CALLOC/FREE:

  • Automatic leak detection in debug builds
  • Memory reports printed at exit

Event Loop Integration

Host and participant both provide callback-based interfaces for integration with custom event loops:

  • No internal threads required
  • Can be used with epoll/kqueue/select
  • Suitable for embedded systems

Files Overview

File Purpose
host.h Server session management
participant.h Client session participation
client_like.h Unified client-like mode framework
capture.h Media source abstraction
display.h Terminal abstraction and rendering
render.h Unified render loop
audio.h Audio capture/playback
keyboard_handler.h Interactive controls
session_log_buffer.h Log capture for screens
settings.h Thread-safe session settings
consensus.h State coordination protocol
consensus_integration.h Consensus integration helpers

See Also

  • Crypto Protocol: docs/crypto.md - Detailed cryptographic handshake
  • Network Protocol: lib/network/ - ACIP packet protocol
  • Platform Abstraction: lib/platform/ - Cross-platform internals
  • Media Resolution: lib/media/ - FFmpeg/yt-dlp integration

Participant media lifecycle

Use session_participant_start_video/audio() and session_participant_stop_video/audio(). The duplicate _capture entry points have been removed. Start creates the device context and worker, and reports active only after successful startup. Repeated start is idempotent; stop joins the worker before releasing capture and codec resources. Disconnect and destruction stop streams even after a partial connection failure. When audio borrows a video's file source, stopping video first stops audio. ACIP transports have explicit owned or borrowed semantics; replace a transport only after stopping its workers. Borrowed transports must remain valid until detached. Serialize participant control calls on its owning thread.

session/av_state.c is the shared audio/video run state machine for native participant workers and browser camera/microphone adapters. A startup token covers asynchronous device permission and encoder setup; stopped or superseded tokens cannot activate a stream. Browser adapters call this same C implementation through WASM, keeping DOM/device operations outside the core. A future iOS adapter can use the same begin/complete/stop contract with AVFoundation callbacks; it must stop callbacks before finishing teardown. No iOS device adapter is supplied by this change.

Check every start result before claiming streaming success:

if (error != ASCIICHAT_OK) {
return error;
}