ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches

ascii-chat Client Mode Entry Point Header More...

Go to the source code of this file.

Functions

int client_main (void)
 Client mode entry point for unified binary.
 

Variables

crypto_handshake_context_t g_crypto_ctx
 Global crypto handshake context for this client connection.
 
h265_encoder_t *volatile g_h265_encoder
 Global H.265 encoder context for client video streaming.
 
thread_pool_t * g_client_worker_pool
 Global client worker thread pool.
 
app_client_t * g_client
 Global client application context.
 
struct webrtc_peer_manager * g_peer_manager
 Global WebRTC peer manager for P2P connections.
 

Detailed Description

ascii-chat Client Mode Entry Point Header

This header exposes the client mode entry point for the unified binary architecture. The unified binary dispatches to client_main() when invoked as ascii-chat client.

Unified Binary Architecture

The ascii-chat application uses a single binary with multiple operating modes:

  • ascii-chat server - Run as server (multi-client connection manager)
  • ascii-chat client - Run as client (connects to server, streams video/audio)

This design provides several benefits:

  • Simplified distribution (single binary to install)
  • Reduced disk space (shared library code)
  • Easier testing (one binary to build and deploy)
  • Consistent versioning across modes

Mode Entry Point Contract

Each mode entry point (server_main, client_main) must:

  • Accept no arguments: int mode_main(void)
  • Options are already parsed by main dispatcher (available via global opt_* variables)
  • Return 0 on success, non-zero error code on failure
  • Perform mode-specific initialization and main loop
  • Perform complete cleanup before returning

Implementation Notes

The client_main() function is the original main() from src/client/main.c, adapted to the new dispatcher pattern. Common initialization (options parsing, logging setup, lock debugging, –show-capabilities) now happens in src/main.c before dispatch.

Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
2025
Version
2.0

Definition in file client/main.h.

Function Documentation

◆ client_main()

int client_main ( void  )

Client mode entry point for unified binary.

This function implements the complete client lifecycle including:

  • Client-specific subsystem initialization (display, capture, audio)
  • Server connection establishment with exponential backoff reconnection
  • Main event loop coordinating connection state and thread lifecycle
  • Media streaming (webcam frames and optional audio)
  • Frame display to terminal
  • Graceful shutdown and resource cleanup

Lifecycle Overview

The client follows this high-level state flow:

  1. Initialize: Set up display, capture, audio subsystems
  2. Connect Loop:
    • Establish TCP connection to server
    • Perform cryptographic handshake
    • Spawn worker threads (data reception, capture, keepalive, audio)
    • Monitor connection health
    • Detect connection loss via thread exit or socket errors
  3. Cleanup: Stop threads, close socket, reset terminal
  4. Reconnect: Exponential backoff, retry (unless fatal auth error)
  5. Exit: On user signal (SIGINT) or fatal error

Connection Failure Handling

Transient Errors (retryable):

  • Connection refused, timeout, DNS failure → exponential backoff retry
  • Network temporarily unavailable → wait and retry

Fatal Errors (no retry):

  • Authentication failed (CONNECTION_ERROR_AUTH_FAILED) → exit immediately
  • Host key verification failed (CONNECTION_ERROR_HOST_KEY_FAILED) → exit immediately

Thread Management

The client spawns several worker threads coordinated by the main thread:

  • Data Reception Thread: Receives and processes server packets
  • Webcam Capture Thread: Captures frames, transmits to server
  • Ping/Keepalive Thread: Sends periodic pings, detects timeouts
  • Audio Threads (optional): Captures/plays audio with Opus encoding

All threads check the global g_should_exit flag and exit cleanly on shutdown. Main thread waits for all threads to exit before reconnection or final cleanup.

Options

Options are already parsed by the main dispatcher (src/main.c) before this function is called. They are available via the global options API (GET_OPTION, etc.).

Key options affecting behavior:

  • opt_address: Server address or session string
  • opt_port: Server port (default 27224)
  • opt_audio_enabled: Enable audio capture/playback
  • opt_snapshot: Capture single frame and exit
  • opt_client_key, opt_server_key: SSH keys for authentication
Returns
Exit code:
  • 0: Success (clean exit or snapshot completed)
  • 1: Initialization/configuration error
  • 2: Connection fatal error (auth failed)
  • 130: Signal interrupt (SIGINT/Ctrl+C)
Example
# Invoked by dispatcher after options are parsed:
ascii-chat client --address localhost --audio
# Dispatcher (src/main.c) handles:
# - Option parsing
# - Log initialization
# - Signal handler setup
# Then calls client_main() which handles:
# - Subsystem init (display, capture, audio)
# - Connection loop with reconnection logic
# - Thread coordination
# - Graceful shutdown
See also
topic_client "Client Architecture Overview"
topic_client_main "Client Lifecycle Details"
topic_client_connection "Connection Management"
topic_client_protocol "Packet Processing"

Definition at line 630 of file client/main.c.

630 {
631 log_debug("client_main() starting");
632
633 // Register client crypto callbacks for TCP connection path
634 // The TCP path in lib/network/connection_attempt.c relies on these callbacks
635 // to handle cryptographic operations and key exchange
636 static const app_callbacks_t client_crypto_callbacks = {
638 .signal_exit = signal_exit,
639 .platform_get_monotonic_time_us = platform_get_monotonic_time_us,
640 .platform_sleep_ms = platform_sleep_ms,
641 .server_connection_set_ip = server_connection_set_ip,
642 .server_connection_set_port = server_connection_set_port,
643 .client_crypto_set_mode = client_crypto_set_mode,
644 .client_crypto_init = client_crypto_init,
645 .client_crypto_handshake = client_crypto_handshake,
646 .crypto_client_is_ready = crypto_client_is_ready,
647 .crypto_client_get_context = crypto_client_get_context,
648 };
649 app_callbacks_register(&client_crypto_callbacks);
650
651 // Initialize client-specific systems (NOT shared with session_client_like)
652 // This includes: thread pool, display layer, app client context, server connection
653 int init_result = initialize_client_systems();
654 if (init_result != 0) {
655#ifndef NDEBUG
656 // Debug builds: automatically fall back to test pattern if webcam is in use
657 if (init_result == ERROR_WEBCAM_IN_USE && !GET_OPTION(test_pattern)) {
658 log_warn("Webcam is in use - automatically falling back to test pattern mode (debug build only)");
659
660 // Enable test pattern mode via RCU update
661 asciichat_error_t update_result = options_set_bool("test_pattern", true);
662 if (update_result != ASCIICHAT_OK) {
663 log_error("Failed to update options for test pattern fallback");
664 FATAL(init_result, "%s", asciichat_error_string(init_result));
665 }
666
667 // Retry initialization with test pattern enabled
668 init_result = initialize_client_systems();
669 if (init_result != 0) {
670 log_error("Failed to initialize even with test pattern fallback");
671 webcam_print_init_error_help(init_result);
672 FATAL(init_result, "%s", asciichat_error_string(init_result));
673 }
674 log_debug("Successfully initialized with test pattern fallback");
675
676 // Clear the error state since we successfully recovered
677 CLEAR_ERRNO();
678 } else
679#endif
680 {
681 // Release builds or other errors: print help and exit
682 if (init_result == ERROR_WEBCAM || init_result == ERROR_WEBCAM_IN_USE || init_result == ERROR_WEBCAM_PERMISSION) {
683 webcam_print_init_error_help(init_result);
684 FATAL(init_result, "%s", asciichat_error_string(init_result));
685 }
686 // For other errors, just exit with the error code
687 return init_result;
688 }
689 }
690
691 // Register cleanup function for graceful shutdown
692 (void)atexit(shutdown_client);
693
694 // Register client interrupt callback (socket shutdown on SIGTERM/Ctrl+C)
695 // Global signal handlers (SIGTERM, SIGPIPE, Ctrl+C) are set up in setup_signal_handlers() in src/main.c
697
698#ifndef _WIN32
699 // Register SIGWINCH for terminal resize handling (client-specific, not in framework)
700 platform_signal(SIGWINCH, client_handle_sigwinch);
701#endif
702
703 /* ========================================================================
704 * Client-Specific: LAN/Session Discovery
705 * ========================================================================
706 * This phase discovers the server to connect to via:
707 * - LAN discovery (mDNS)
708 * - Session string lookup (ACDS)
709 * - Direct address/port
710 */
711
712 // LAN Discovery: If --scan flag is set, discover servers on local network
713 const options_t *opts = options_get();
714 if (opts && opts->lan_discovery &&
715 (opts->address[0] == '\0' || is_localhost_ipv4(opts->address) || strcmp(opts->address, "localhost") == 0)) {
716 log_debug("LAN discovery: --scan flag set, querying for available servers");
717
718 ui_mdns_config_t lan_config;
719 memset(&lan_config, 0, sizeof(lan_config));
720 lan_config.timeout_ms = 2 * MS_PER_SEC_INT; // Wait up to 2 seconds for responses
721 lan_config.max_servers = 20; // Support up to 20 servers on LAN
722 lan_config.quiet = true; // Quiet during discovery, TUI will show status
723
724 int discovered_count = 0;
725 ui_mdns_server_t *discovered_servers = ui_mdns_query(&lan_config, &discovered_count);
726
727 // Use TUI for server selection
728 int selected_index = ui_mdns_select(discovered_servers, discovered_count);
729
730 if (selected_index < 0) {
731 // User cancelled or no servers found
732 if (discovered_count == 0) {
733 // No servers found - log message and prevent any further output
734 // Lock the terminal so other threads can't write and our error
735 // will be the last message
737
738 // Log single message with embedded newlines to prevent multiple log entries
739 log_error("No ascii-chat servers found on the local network.\nUse 'ascii-chat client <address>' to connect "
740 "manually.");
741
742 // Exit without cleanup
744 }
745 // User cancelled (had servers to choose from but pressed cancel)
746 log_debug("LAN discovery: User cancelled server selection");
747 if (discovered_servers) {
748 ui_mdns_free_results(discovered_servers);
749 }
750 return 1; // User cancelled
751 }
752
753 // Update options with discovered server's address and port
754 ui_mdns_server_t *selected = &discovered_servers[selected_index];
755 const char *selected_address = ui_mdns_get_best_address(selected);
756
757 // We need to modify options, but they're immutable via RCU
758 // Create a new options copy with updated address/port
759 options_t *opts_new = SAFE_MALLOC(sizeof(options_t), options_t *);
760 if (opts_new) {
761 memcpy(opts_new, opts, sizeof(options_t));
762 SAFE_STRNCPY(opts_new->address, selected_address, sizeof(opts_new->address));
763
764 opts_new->port = (int)selected->port;
765
766 log_debug("LAN discovery: Selected server '%s' at %s:%d", selected->name, opts_new->address, opts_new->port);
767
768 // Note: In a real scenario, we'd update the global options via RCU
769 // For now, we'll use the updated values directly for connection
770 // This is a known limitation - proper RCU update requires more infrastructure
771 }
772
773 ui_mdns_free_results(discovered_servers);
774 }
775
776 // =========================================================================
777 // Client-Specific: Server Address Resolution
778 // =========================================================================
779 // Client mode supports:
780 // 1. Direct address/port (--address HOST --port PORT) - handled by options
781 // 2. LAN discovery (--scan) - handled above
782 // 3. WebSocket URL (direct ws:// or wss:// connection string)
783 //
784 // Note: Session string discovery via ACDS is handled by discovery mode only.
785 // Client mode does NOT use ACDS or session strings.
786
787 const char *discovered_address = NULL;
788 int discovered_port = 0;
789
790 // Check if user provided a WebSocket URL as the server address
791 const options_t *opts_websocket = options_get();
792 const char *provided_address = opts_websocket && opts_websocket->address[0] != '\0' ? opts_websocket->address : NULL;
793
794 if (provided_address && url_is_websocket(provided_address)) {
795 // Direct WebSocket connection
796 log_debug("Client: Direct WebSocket URL: %s", provided_address);
797 discovered_address = provided_address;
798 discovered_port = 0; // Port is embedded in the URL
799 }
800
801 if (discovered_port > 0) {
802 log_debug("Client: discovered_address=%s, discovered_port=%d", discovered_address ? discovered_address : "NULL",
803 discovered_port);
804 } else {
805 log_debug("Client: discovered_address=%s", discovered_address ? discovered_address : "NULL");
806 }
807
808 // Store discovered address/port in session state for client_run() callback
809 static char address_storage[BUFFER_SIZE_SMALL];
810 if (discovered_address) {
811 SAFE_STRNCPY(address_storage, discovered_address, sizeof(address_storage));
812 g_client_session.discovered_address = address_storage;
813 g_client_session.discovered_port = discovered_port;
814 } else {
815 const options_t *opts_fallback = options_get();
816 if (opts_fallback && opts_fallback->address[0] != '\0') {
817 SAFE_STRNCPY(address_storage, opts_fallback->address, sizeof(address_storage));
818 g_client_session.discovered_address = address_storage;
819 g_client_session.discovered_port = opts_fallback->port;
820 } else {
821 g_client_session.discovered_address = "localhost";
822 g_client_session.discovered_port = 27224;
823 }
824 }
825
826 // Initialize connection context for first attempt
827 asciichat_error_t ctx_init_result = connection_context_init(&g_client_session.connection_ctx);
828 if (ctx_init_result != ASCIICHAT_OK) {
829 log_error("Failed to initialize connection context");
830 return 1;
831 }
832
833 /* ========================================================================
834 * Configure and Run Shared Client-Like Session Framework
835 * ========================================================================
836 * session_client_like_run() handles all shared initialization:
837 * - Terminal output management (force stderr if piped)
838 * - Keepawake system (platform sleep prevention)
839 * - Splash screen lifecycle
840 * - Media source selection (webcam, file, URL, test pattern)
841 * - FPS probing for media files
842 * - Audio initialization and lifecycle
843 * - Display context creation
844 * - Proper cleanup ordering (critical for PortAudio)
845 *
846 * Client mode provides:
847 * - client_run() callback: connection loop, protocol startup, monitoring
848 * - client_should_reconnect() callback: reconnection policy
849 * - Reconnection configuration: attempts, delay, callbacks
850 */
851
852 // Get reconnect attempts setting (-1 = unlimited, 0 = no retry, >0 = retry N times)
853 int reconnect_attempts = GET_OPTION(reconnect_attempts);
854
855 // Configure session_client_like with client-specific settings
857 .run_fn = client_run,
858 .run_user_data = NULL,
860 .discovery = NULL,
861 .custom_should_exit = NULL,
862 .exit_user_data = NULL,
863 .keyboard_handler = NULL, // Client mode: server drives display
864 .max_reconnect_attempts = reconnect_attempts,
865 .should_reconnect_callback = client_should_reconnect,
866 .reconnect_user_data = NULL,
867 .reconnect_delay_ms = 1000, // 1 second delay between reconnection attempts
868 .print_newline_on_tty_exit = false, // Server/client manages cursor
869 };
870
871 log_debug("[CLIENT_MAIN] About to call session_client_like_run() with %d attempts", reconnect_attempts);
872 asciichat_error_t session_result = session_client_like_run(&config);
873 log_debug("[CLIENT_MAIN] session_client_like_run() returned %d", session_result);
874
875 // Network client lifecycle is owned by connection_context_cleanup() after the session returns.
876
877 // Cleanup connection context
878 log_debug("[CLIENT_MAIN] About to call connection_context_cleanup()");
880 log_debug("[CLIENT_MAIN] connection_context_cleanup() returned");
881
882 // Cleanup session log buffer (used by splash screen in session_client_like)
883 // NOTE: session_log_buffer_destroy() is already called in session_client_like_run()
884 // during its cleanup phase, so we don't call it here to avoid double-destroy of mutex
885
886 log_debug("[CLIENT_MAIN] ascii-chat client shutting down");
887
888 // IMPORTANT: Stop worker threads and join them BEFORE memory report
889 // atexit(shutdown_client) won't run if interrupted by SIGTERM, so call explicitly
890 log_debug("[CLIENT_MAIN] About to call shutdown_client()");
891 fflush(stderr);
892 shutdown_client();
893 log_debug("[CLIENT_MAIN] shutdown_client() returned");
894 fflush(stderr);
895
896 // Cleanup remaining shared subsystems (buffer pool, platform, etc.)
897 log_debug("[CLIENT_MAIN] About to call asciichat_shared_destroy()");
899
900 // Log final session statistics before exit
901 // Note: Frame count is logged in protocol_stop_connection() if connection was established
902 // This is a fallback in case the connection never started
903 return (session_result == ASCIICHAT_OK) ? 0 : 1;
904}
void app_callbacks_register(const app_callbacks_t *callbacks)
asciichat_error_t session_client_like_run(const session_client_like_config_t *config)
@ SESSION_CLIENT_LIKE_KIND_CLIENT
Definition client_like.h:65
asciichat_error_t connection_context_init(connection_attempt_context_t *ctx)
Initialize connection attempt context.
void connection_context_cleanup(connection_attempt_context_t *ctx)
Cleanup connection attempt context.
#define BUFFER_SIZE_SMALL
Small buffer size (256 bytes)
void server_connection_shutdown()
Emergency connection shutdown for signal handlers.
void server_connection_set_ip(const char *ip)
Set the server IP address.
void server_connection_set_port(int port)
Set the server port.
const crypto_context_t * crypto_client_get_context(void)
Get crypto context for encryption/decryption.
int client_crypto_handshake(acip_transport_t *transport)
Perform crypto handshake with server.
void client_crypto_set_mode(uint8_t mode)
Set crypto mode for handshake (encryption + authentication)
int client_crypto_init(void)
Initialize client crypto handshake.
bool crypto_client_is_ready(void)
Check if crypto handshake is ready.
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:414
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define FATAL(code,...)
Exit with error code and custom message, with stack trace in debug builds.
Definition common.h:158
void asciichat_shared_destroy(void)
Clean up all shared library subsystems.
Definition common.c:195
#define CLEAR_ERRNO()
Clear the current error state.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ERROR_WEBCAM_IN_USE
Definition error_codes.h:65
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_WEBCAM_PERMISSION
Definition error_codes.h:66
@ ERROR_WEBCAM
Definition error_codes.h:64
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
bool log_lock_terminal(void)
Lock terminal output for exclusive access by the calling thread.
Definition log/log.c:787
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
#define MS_PER_SEC_INT
Definition time.h:164
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
const options_t * options_get(void)
Get current options (lock-free read)
Definition rcu.c:496
asciichat_error_t options_set_bool(const char *field_name, bool value)
Definition rcu.c:969
signal_handler_t platform_signal(int sig, signal_handler_t handler)
Set a signal handler.
Definition misc.c:115
void platform_force_exit(int exit_code)
Forcefully terminate the process immediately without cleanup.
Definition misc.c:121
uint64_t platform_get_monotonic_time_us(void)
Get monotonic time in microseconds.
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
bool url_is_websocket(const char *url)
Check if a URL string is a valid WebSocket URL.
Definition url.c:307
int is_localhost_ipv4(const char *ip)
Check if IPv4 address is localhost.
Definition ip.c:1299
void webcam_print_init_error_help(asciichat_error_t error_code)
Print helpful error diagnostics for webcam initialization failures.
void signal_exit(void)
Definition misc.c:129
void set_interrupt_callback(void(*callback)(void))
Definition misc.c:125
mdns_result_t * ui_mdns_get_best_address(mdns_query_t *query)
Definition misc.c:144
void ui_mdns_free_results(mdns_result_t *results)
Definition misc.c:155
mdns_query_t * ui_mdns_query(const char *service)
Definition misc.c:139
bool should_exit(void)
Definition misc.c:131
int ui_mdns_select(const ui_mdns_server_t *servers, int count)
TUI-based server selection with formatted display.
Definition misc.c:149
bool(* should_exit)(void)
const char * discovered_address
connection_attempt_context_t connection_ctx
Consolidated options structure.
bool lan_discovery
Enable LAN service discovery via mDNS (client only)
char address[256]
Server address (client) or bind address (server)
session_client_like_run_fn run_fn
Configuration for TUI discovery.
Definition ui/mdns.h:69
int max_servers
Maximum servers to collect (default: 20)
Definition ui/mdns.h:71
int timeout_ms
Maximum time to wait for responses (default: 2000)
Definition ui/mdns.h:70
bool quiet
Suppress discovery messages (default: false)
Definition ui/mdns.h:72
Discovered server information from mDNS.
Definition ui/mdns.h:57
char name[256]
Service instance name (e.g., "swift-river-canyon")
Definition ui/mdns.h:58
uint16_t port
Server port number.
Definition ui/mdns.h:60

References options_state::address, app_callbacks_register(), ASCIICHAT_OK, asciichat_shared_destroy(), BUFFER_SIZE_SMALL, CLEAR_ERRNO, client_crypto_handshake(), client_crypto_init(), client_crypto_set_mode(), connection_context_cleanup(), connection_context_init(), client_session_state_t::connection_ctx, crypto_client_get_context(), crypto_client_is_ready(), client_session_state_t::discovered_address, client_session_state_t::discovered_port, ERROR_WEBCAM, ERROR_WEBCAM_IN_USE, ERROR_WEBCAM_PERMISSION, FATAL, GET_OPTION, is_localhost_ipv4(), options_state::lan_discovery, log_debug, log_error, log_lock_terminal(), log_warn, ui_mdns_config_t::max_servers, MS_PER_SEC_INT, ui_mdns_server_t::name, options_get(), options_set_bool(), platform_force_exit(), platform_get_monotonic_time_us(), platform_signal(), platform_sleep_ms(), options_state::port, ui_mdns_server_t::port, ui_mdns_config_t::quiet, session_client_like_config::run_fn, SAFE_MALLOC, SAFE_STRNCPY, server_connection_set_ip(), server_connection_set_port(), server_connection_shutdown(), SESSION_CLIENT_LIKE_KIND_CLIENT, session_client_like_run(), set_interrupt_callback(), should_exit(), app_callbacks_t::should_exit, signal_exit(), ui_mdns_config_t::timeout_ms, ui_mdns_free_results(), ui_mdns_get_best_address(), ui_mdns_query(), ui_mdns_select(), url_is_websocket(), and webcam_print_init_error_help().

Variable Documentation

◆ g_client

app_client_t* g_client
extern

Global client application context.

Central state management structure for the client, containing both network and application-layer state.

This instance provides:

  • Connection state management via active_transport (TCP or WebSocket)
  • Audio queue management for async audio streaming
  • Thread handles for worker threads (data reception, capture, ping, audio)
  • Display state and terminal capability tracking
  • Crypto handshake context for encrypted connections
  • Protocol state (client ID, server initialization status)

Initialized by app_client_create() in client_main(). Destroyed by app_client_destroy() at cleanup.

All client modules (protocol.c, audio.c, capture.c, display.c) should use this instance instead of accessing global connection state.

Global application client context

Central connection and application state for the client. Contains transport-agnostic state: audio, threads, display, crypto. Network-specific state (socket, connection flags) is in the active transport client.

Initialized by app_client_create() in client_main(). Destroyed by app_client_destroy() at cleanup.

Definition at line 152 of file client/main.c.

◆ g_client_worker_pool

thread_pool_t* g_client_worker_pool
extern

Global client worker thread pool.

Manages all client worker threads including:

  • Data reception thread (protocol.c)
  • Webcam capture thread (capture.c)
  • Ping/keepalive thread (keepalive.c)
  • Audio capture thread (audio.c)
  • Audio sender thread (audio.c)

This pool is initialized in client_main() and accessible from all client modules for spawning and managing worker threads.

Global client worker thread pool

Manages all client worker threads including:

  • Data reception thread (protocol.c)
  • Webcam capture thread (capture.c)
  • Ping/keepalive thread (keepalive.c)
  • Audio capture thread (audio.c)
  • Audio sender thread (audio.c)

Definition at line 140 of file client/main.c.

Referenced by audio_sender_init(), audio_start_thread(), capture_start_thread(), keepalive_start_thread(), protocol_start_connection(), and protocol_stop_connection().

◆ g_h265_encoder

h265_encoder_t* volatile g_h265_encoder
extern

Global H.265 encoder context for client video streaming.

Encodes captured RGB frames to H.265/HEVC format before transmission. Initialized in client_main() and used by capture thread. Set to NULL during shutdown to prevent use-after-free.

Definition at line 222 of file src/client/server.c.

Referenced by protocol_stop_connection(), and threaded_send_image_frame_h265().

◆ g_peer_manager

struct webrtc_peer_manager* g_peer_manager
extern

Global WebRTC peer manager for P2P connections.

Manages WebRTC peer connections for ACDS session participants. Handles SDP/ICE exchange and DataChannel lifecycle for P2P ACIP transport.

NULL if WebRTC not initialized (TCP-only mode). Initialized when joining/creating ACDS sessions with WebRTC transport.

Global WebRTC peer manager for P2P connections.

Client mode no longer uses WebRTC, but protocol.c still references this. Always NULL in client mode.

Definition at line 160 of file client/main.c.