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

📡 Client-side packet processing and data reception thread More...

Files

file  protocol.c
 ðŸ“¡ Client protocol handler: packet reception, parsing, and dispatch with data thread coordination
 
file  protocol.h
 ascii-chat Client Protocol Handler Interface
 

Data Structures

struct  remote_client_info_t
 Remote client information structure for multi-user client tracking. More...
 

Functions

int protocol_start_connection ()
 Start protocol connection handling.
 
void protocol_stop_connection ()
 Stop protocol connection handling.
 
bool protocol_connection_lost ()
 Check if connection has been lost.
 
const acip_client_callbacks_t * protocol_get_acip_callbacks ()
 Get ACIP client callbacks for packet dispatch.
 

Detailed Description

📡 Client-side packet processing and data reception thread

Client Protocol README

Overview

The protocol handler manages the data reception thread, processes incoming packets from the server, and dispatches them to appropriate handlers based on packet type.

Implementation: src/client/protocol.c, src/client/protocol.h

Data Reception Thread

static void *data_reception_thread(void *arg)
{
(void)arg;
void *payload = NULL;
size_t payload_len = 0;
// Receive and decrypt packet
int result = receive_packet(sockfd, crypto_ctx, &header, &payload, &payload_len);
if (result < 0) {
log_debug("receive_packet failed - connection lost");
break;
}
// Dispatch based on packet type
handle_packet(&header, payload, payload_len);
if (payload) {
free(payload);
payload = NULL;
}
}
atomic_store(&g_data_thread_exited, true);
return NULL;
}
bool server_connection_is_active()
Check if server connection is currently active.
socket_t server_connection_get_socket()
Get current socket file descriptor.
void server_connection_lost()
Signal that connection has been lost.
const crypto_context_t * crypto_client_get_context(void)
Get crypto context for encryption/decryption.
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
Definition packet.c:797
int socket_t
bool should_exit(void)
Definition misc.c:131
Cryptographic context structure.
Network packet header structure.
Definition packet.h:598

Packet Handlers

ASCII Frame Handler

static void handle_ascii_frame(const void *payload, size_t payload_len)
{
// Render ASCII frame to terminal
display_render_frame((const char *)payload, opt_snapshot);
// Snapshot mode: exit after displaying frame
if (opt_snapshot) {
}
}
void display_render_frame(const char *frame_data)
Render ASCII frame to display.
void signal_exit(void)
Definition misc.c:129

Audio Batch Handler

static void handle_audio_batch(const void *payload, size_t payload_len)
{
const float *samples = (const float *)payload;
int num_samples = payload_len / sizeof(float);
// Process received audio samples
audio_process_received_samples(samples, num_samples);
}
void audio_process_received_samples(const float *samples, int num_samples)
Process received audio samples from server.

Pong Handler

static void handle_pong(void)
{
// Update last pong time for keepalive timeout tracking
keepalive_record_pong();
}

Clear Console Handler

static void handle_clear_console(void)
{
// Server requests terminal clear
}
void display_full_reset()
Perform full display reset.

Server State Handler

static void handle_server_state(const void *payload, size_t payload_len)
{
// Log server state information
log_debug("Received server state update");
}

Connection Loss Detection

Loss triggers in protocol thread:

  • receive_packet() returns error
  • Socket read error (connection closed by server)
  • Decryption failure (corrupted stream)
  • Invalid packet magic number
if (receive_packet(...) < 0) {
server_connection_lost(); // Signal connection loss
break; // Exit thread
}
See also
src/client/protocol.c
src/client/protocol.h
Client Overview

Function Documentation

◆ protocol_connection_lost()

bool protocol_connection_lost ( )

#include <protocol.c>

Check if connection has been lost.

Check if connection has been lost

Returns
true if protocol detected connection loss, false otherwise

Atomically checks whether the data reception thread has detected connection loss. Connection loss is detected by:

  • Socket read error (recv() returns error)
  • Socket closed by server (recv() returns 0)
  • Decryption failure (corrupted stream)
  • Invalid packet magic number (out of sync)

Once loss is detected, this flag remains true until the next successful connection.

Returns
true if connection lost (detected by protocol thread), false otherwise
Note
This is checked by the main thread to trigger reconnection logic. The flag is set atomically by the protocol thread and checked atomically by main.
See also
server_connection_lost "Signal connection loss (called by protocol thread)"

Definition at line 1429 of file client/protocol.c.

1429 {
1430 return atomic_load_bool(&g_data_thread_exited) || server_connection_is_lost();
1431}
bool atomic_load_bool(atomic_t *a)
Atomically load a boolean value.
Definition atomic.c:169
bool server_connection_is_lost()
Check if connection loss has been detected.

References atomic_load_bool(), and server_connection_is_lost().

◆ protocol_get_acip_callbacks()

const acip_client_callbacks_t * protocol_get_acip_callbacks ( )

#include <protocol.h>

Get ACIP client callbacks for packet dispatch.

Returns the packet dispatch callbacks structure used to route received packets to appropriate handlers. This is primarily used for ACDS signaling packet dispatch and WebRTC peer negotiation.

The callbacks structure includes handlers for:

  • ASCII frame rendering
  • Audio batch processing
  • Server state updates
  • Connection control commands (clear, reset, etc.)
Returns
Pointer to client callbacks structure (never NULL)

Used by WebRTC sessions to receive and dispatch ACDS signaling packets.

Returns pointer to the global callback structure for use by WebRTC sessions that need to receive ACDS signaling packets.

Returns
Pointer to client callbacks (never NULL)

Definition at line 957 of file client/protocol.c.

957 {
958 return &g_acip_client_callbacks;
959}

◆ protocol_start_connection()

int protocol_start_connection ( )

#include <protocol.c>

Start protocol connection handling.

Start protocol connection handling

Initializes protocol state and starts the data reception thread. Must be called after successful server connection establishment.

Returns
0 on success, negative on error

Spawns the data reception thread in the global client worker thread pool. The thread begins receiving and processing packets from the server. Must be called after the server connection is established and the cryptographic handshake is complete.

The thread will:

  1. Continuously receive packets from the server socket
  2. Decrypt packets using the negotiated session key
  3. Dispatch packets to appropriate handlers based on type
  4. Detect connection loss and signal the main thread
Returns
0 on success, negative on error (thread pool full or other resources exhausted)
Note
Must be paired with protocol_stop_connection() to properly shut down the thread before reconnection or exit.
See also
protocol_stop_connection "Stop data reception thread"
protocol_connection_lost "Check if connection was lost"

Definition at line 1156 of file client/protocol.c.

1156 {
1157 log_warn("[FRAME_RECV_INIT] 🟢 PROTOCOL_START: Starting client protocol initialization");
1158
1159 // Register protocol atomics with named debug registry
1160 static bool protocol_atomics_registered = false;
1161 if (!protocol_atomics_registered) {
1162 NAMED_REGISTER_ATOMIC(&g_data_thread_exited, "protocol_data_reception_thread_exit_confirmation", NULL);
1163 NAMED_REGISTER_ATOMIC(&g_frames_rendered, "protocol_frames_successfully_rendered", NULL);
1164 protocol_atomics_registered = true;
1165 }
1166
1167 // Reset protocol state for new connection
1168 g_server_state_initialized = false;
1169 g_last_active_count = 0;
1170 g_should_clear_before_next_frame = false;
1171
1172 log_info("[FRAME_RECV_INIT] ✅ STATE_RESET: server_initialized=false, active_count=0, clear_flag=false");
1173
1174 // Reset display state for new connection
1176
1177 // Check if we're on a WebSocket transport (crypto handshake is async via ACIP callbacks)
1178 // For WS/WSS, we must start data_reception FIRST so it can handle the crypto handshake,
1179 // then wait for crypto to complete before sending CAPABILITIES/STREAM_START.
1180 // For TCP, crypto is already done synchronously before this function is called.
1182 bool is_websocket = init_transport && acip_transport_get_type(init_transport) == ACIP_TRANSPORT_WEBSOCKET;
1183
1184 if (is_websocket) {
1185 // WebSocket: start data reception thread FIRST to handle async crypto handshake.
1186 // TCP does crypto synchronously in connection_attempt.c, but WS crypto flows
1187 // asynchronously via ACIP callbacks in the data_reception thread.
1188 log_debug("[FRAME_RECV_INIT] WS: Starting data_reception for async crypto handshake");
1189 atomic_store_bool(&g_data_thread_exited, false);
1190 if (thread_pool_spawn(g_client_worker_pool, data_reception_thread_func, NULL, 1, "data_reception") !=
1191 ASCIICHAT_OK) {
1192 log_error("[FRAME_RECV_INIT] Failed to start data reception thread");
1193 LOG_ERRNO_IF_SET("Data reception thread creation failed");
1194 return -1;
1195 }
1196 log_debug("[FRAME_RECV_INIT] WS: Data thread spawned, waiting for crypto handshake");
1197
1198 // Wait for crypto handshake to complete (CRYPTO_PARAMETERS → KEY_EXCHANGE → HANDSHAKE_COMPLETE)
1199 // Skip waiting if encryption is disabled (no_encrypt mode)
1200 if (!GET_OPTION(no_encrypt)) {
1201 const int MAX_CRYPTO_WAIT_MS = 10000; // 10 seconds
1202 const int POLL_INTERVAL_MS = 10;
1203 int waited_ms = 0;
1205 waited_ms < MAX_CRYPTO_WAIT_MS) {
1206 platform_sleep_us(POLL_INTERVAL_MS * 1000);
1207 waited_ms += POLL_INTERVAL_MS;
1208 if (waited_ms % 1000 == 0) {
1209 log_info("[FRAME_RECV_INIT] WS_CRYPTO: Waiting for handshake... (%d ms elapsed)", waited_ms);
1210 }
1211 }
1212
1213 if (!crypto_client_is_ready()) {
1215 log_error("[FRAME_RECV_INIT] WS: Connection lost during crypto handshake");
1216 } else {
1217 log_error("[FRAME_RECV_INIT] WS: Crypto handshake timed out after %d ms", MAX_CRYPTO_WAIT_MS);
1218 }
1219 return -1;
1220 }
1221 log_info("[FRAME_RECV_INIT] WS: Crypto handshake completed after %d ms", waited_ms);
1222 } else {
1223 log_info("[FRAME_RECV_INIT] WS: Encryption disabled, skipping handshake wait");
1224 }
1225 }
1226
1227 // Send CLIENT_CAPABILITIES packet (after crypto is ready for both TCP and WS)
1228 // Server expects this as the first packet after crypto handshake
1229 log_debug("[FRAME_RECV_INIT] Sending CLIENT_CAPABILITIES (terminal size)");
1232 if (cap_result != ASCIICHAT_OK) {
1233 log_error("[FRAME_RECV_INIT] Failed to send terminal size capabilities");
1234 return -1;
1235 }
1236
1237 // Send STREAM_START packet with combined stream types
1238 uint32_t stream_types = STREAM_TYPE_VIDEO; // Always have video
1239 if (GET_OPTION(audio_enabled)) {
1240 stream_types |= STREAM_TYPE_AUDIO; // Add audio if enabled
1241 }
1242 log_debug("[FRAME_RECV_INIT] Sending STREAM_START: types=0x%x (video%s)", stream_types,
1243 (stream_types & STREAM_TYPE_AUDIO) ? "+audio" : "");
1244 asciichat_error_t stream_result = threaded_send_stream_start_packet(stream_types);
1245 if (stream_result != ASCIICHAT_OK) {
1246 log_error("[FRAME_RECV_INIT] Failed to send stream start");
1247 return -1;
1248 }
1249
1250 // Start data reception thread (TCP only - WS already started it above for crypto)
1251 if (!is_websocket) {
1252 log_debug("[FRAME_RECV_INIT] TCP: Starting data reception thread");
1253 atomic_store_bool(&g_data_thread_exited, false);
1254 if (thread_pool_spawn(g_client_worker_pool, data_reception_thread_func, NULL, 1, "data_reception") !=
1255 ASCIICHAT_OK) {
1256 log_error("[FRAME_RECV_INIT] Failed to start data reception thread");
1257 LOG_ERRNO_IF_SET("Data reception thread creation failed");
1258 return -1;
1259 }
1260 }
1261
1262 // Start webcam capture thread
1263 log_debug("Starting webcam capture thread...");
1264 if (capture_start_thread() != 0) {
1265 log_error("Failed to start webcam capture thread");
1266 return -1;
1267 }
1268 log_debug("Webcam capture thread started successfully");
1269
1270 // Start local media audio only after the connection succeeds. Starting the
1271 // worker during client initialization would consume file audio while dialing.
1272 audio_context_t *audio_context = audio_get_context();
1273 if (audio_context && audio_context->initialized) {
1275 if (audio_start_duplex(audio_context) != ASCIICHAT_OK) {
1276 log_error("Failed to start full-duplex audio");
1277 return -1;
1278 }
1279 }
1280
1281 // Initialize audio sender thread BEFORE starting audio capture
1282 // This ensures sender is ready when capture thread starts queueing packets
1283 // Must happen after connection succeeds to prevent deadlock if connection fails
1285
1286 // Start audio capture thread if audio is enabled
1287 log_debug("Starting audio capture thread...");
1288 if (audio_start_thread() != 0) {
1289 log_error("Failed to start audio capture thread");
1290 return -1;
1291 }
1292 log_debug("Audio capture thread started successfully (or skipped if audio disabled)");
1293
1294 // Start keepalive/ping thread to prevent server timeout
1295 log_debug("Starting keepalive/ping thread...");
1296 if (keepalive_start_thread() != 0) {
1297 log_error("Failed to start keepalive/ping thread");
1298 return -1;
1299 }
1300 log_debug("Keepalive/ping thread started successfully");
1301
1302 g_data_thread_created = true;
1303 return 0;
1304}
#define LOG_ERRNO_IF_SET(message)
Check if any error occurred and log it if so.
void atomic_store_bool(atomic_t *a, bool value)
Atomically store a boolean value.
Definition atomic.c:177
void * capture_get_media_source(void)
thread_pool_t * g_client_worker_pool
Global client worker thread pool.
asciichat_error_t thread_pool_spawn(void *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id, const char *name)
Spawn a worker thread in the pool.
asciichat_error_t audio_start_duplex(audio_context_t *ctx)
Start full-duplex audio (simultaneous capture and playback)
void audio_sender_init(void)
Initialize async audio sender queue and thread.
audio_context_t * audio_get_context(void)
Get the global audio context for use by other subsystems.
int audio_start_thread()
Start audio capture thread.
int capture_start_thread()
Start capture thread.
asciichat_error_t threaded_send_terminal_size_with_auto_detect(unsigned short width, unsigned short height)
Thread-safe terminal size packet transmission with auto-detection.
acip_transport_t * server_connection_get_transport(void)
Get ACIP transport instance.
asciichat_error_t threaded_send_stream_start_packet(uint32_t stream_type)
Thread-safe stream start packet transmission.
bool crypto_client_is_ready(void)
Check if crypto handshake is ready.
void display_reset_for_new_connection()
Reset display state for new connection.
int keepalive_start_thread()
Start keepalive/ping thread.
Definition keepalive.c:236
unsigned int uint32_t
Definition common.h:58
#define NAMED_REGISTER_ATOMIC(a, name, parent_ptr)
Register an atomic_t with automatic format specifier.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ASCIICHAT_OK
Definition error_codes.h:51
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define STREAM_TYPE_VIDEO
Video stream.
Definition packet.h:937
#define STREAM_TYPE_AUDIO
Audio stream.
Definition packet.h:938
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
void platform_sleep_us(unsigned int us)
High-precision sleep function with microsecond precision.
unsigned short int terminal_get_effective_width(void)
Get effective terminal width with fallback priority.
unsigned short int terminal_get_effective_height(void)
Get effective terminal height with fallback priority.
Transport instance structure.
Definition transport.h:214
Audio context for full-duplex capture and playback.
bool initialized
True if context has been initialized.
void * capture_media_source
Borrowed local media audio; configure before starting duplex.
@ ACIP_TRANSPORT_WEBSOCKET
WebSocket over TCP.
Definition transport.h:95

References ACIP_TRANSPORT_WEBSOCKET, ASCIICHAT_OK, atomic_store_bool(), audio_get_context(), audio_sender_init(), audio_start_duplex(), audio_start_thread(), capture_get_media_source(), audio_context_t::capture_media_source, capture_start_thread(), crypto_client_is_ready(), display_reset_for_new_connection(), g_client_worker_pool, GET_OPTION, audio_context_t::initialized, keepalive_start_thread(), log_debug, LOG_ERRNO_IF_SET, log_error, log_info, log_warn, NAMED_REGISTER_ATOMIC, platform_sleep_us(), server_connection_get_transport(), server_connection_is_active(), should_exit(), STREAM_TYPE_AUDIO, STREAM_TYPE_VIDEO, terminal_get_effective_height(), terminal_get_effective_width(), thread_pool_spawn(), threaded_send_stream_start_packet(), and threaded_send_terminal_size_with_auto_detect().

◆ protocol_stop_connection()

void protocol_stop_connection ( )

#include <protocol.c>

Stop protocol connection handling.

Stop protocol connection handling

Gracefully shuts down the data reception thread and cleans up protocol state. Safe to call multiple times.

Signals the data reception thread to exit and waits for it to join. Performs proper cleanup to prevent resource leaks and race conditions during reconnection or shutdown.

The function:

  1. Closes the server socket (interrupts blocking recv() in data thread)
  2. Sets the global shutdown flag (signals thread to exit)
  3. Waits for the data reception thread to join (polls for thread exit)

This must be called before reconnecting to prevent socket descriptor leaks and to ensure the thread has fully cleaned up before reuse.

Note
This function blocks until the data reception thread exits. Typical wait time: <100ms (socket closure immediately interrupts recv()).
See also
protocol_start_connection "Start data reception thread"

Definition at line 1314 of file client/protocol.c.

1314 {
1315 // Log final frame count before shutting down (always log for diagnostic purposes)
1316 int final_frame_count = atomic_load_u64(&g_frames_rendered);
1317 log_info("📊 CLIENT SESSION STATS: %d unique frames rendered during connection", final_frame_count);
1318
1319 log_debug("[PROTOCOL_STOP] 1. Starting protocol_stop_connection");
1320
1321 // Stop snapshot capture before flushing, then use the shared connection shutdown
1322 // to wake and join the audio sender and reception threads.
1323 if (GET_OPTION(snapshot_mode)) {
1324 log_debug("[PROTOCOL_STOP] Snapshot mode: stopping capture thread before flushing H.265 encoder");
1325 // The capture thread owns the encoder while it is producing frames. Join it
1326 // before flushing so shutdown cannot destroy encoder state underneath an
1327 // in-flight encode operation.
1329
1330 // Flush the encoder to output any buffered frames before exiting
1331 if (g_h265_encoder) {
1332 // Allocate buffer large enough for worst-case H.265 encoded frame
1333 // Using 320x240 (typical test resolution) * 2x multiplier + header
1334 size_t flush_buf_size = 5 + (320 * 240 * 2);
1335 uint8_t *flush_buf = SAFE_MALLOC(flush_buf_size, uint8_t *);
1336 size_t flush_size = flush_buf_size;
1337 asciichat_error_t flush_result = h265_encoder_flush(g_h265_encoder, flush_buf, &flush_size);
1338 if (flush_result == ASCIICHAT_OK && flush_size > 0) {
1339 log_info("[PROTOCOL_STOP] Flushed H.265 encoder: got %zu bytes of buffered frames", flush_size);
1340 // Send the flushed frame if we got one
1342 if (transport && server_connection_is_active()) {
1343 uint32_t width = 320, height = 240; // TODO: track actual dimensions
1344 log_debug("[PROTOCOL_STOP] Sending flushed frame: %ux%u, %zu bytes", width, height, flush_size);
1345 }
1346 }
1347 SAFE_FREE(flush_buf);
1348 }
1349 }
1350
1351 // Don't call signal_exit() here - that's for global shutdown only!
1352 // We just want to stop threads for this connection, not exit the entire client
1353
1354 // Shutdown the socket FIRST to interrupt any blocking network operations in worker threads
1355 // This must happen BEFORE audio_stop_thread() so audio sender thread unblocks from network send
1356 log_debug("[PROTOCOL_STOP] 2. About to call server_connection_shutdown");
1358 log_debug("[PROTOCOL_STOP] 3. server_connection_shutdown() returned");
1359
1360 // Signal audio sender thread to exit
1361 // Must happen after socket shutdown so any blocked network calls fail
1362 // Snapshot recordings also transmit audio and must stop the sender.
1363 log_debug("[PROTOCOL_STOP] 4. About to call audio_stop_thread");
1365 log_debug("[PROTOCOL_STOP] 5. audio_stop_thread() returned");
1366
1367 // Early return if data thread was never created (e.g., mirror mode)
1368 // In mirror mode, we only need to stop the audio sender (done above)
1369 if (!g_data_thread_created) {
1370 log_debug("[PROTOCOL_STOP] 6. Data thread not created, returning");
1371 return;
1372 }
1373
1374 // Stop keepalive/ping thread - it checks connection status and will exit
1375 log_debug("[PROTOCOL_STOP] 7. About to call keepalive_stop_thread");
1377 log_debug("[PROTOCOL_STOP] 8. keepalive_stop_thread() returned");
1378
1379 // Stop webcam capture thread
1380 log_debug("[PROTOCOL_STOP] 9. About to call capture_stop_thread");
1382 log_debug("[PROTOCOL_STOP] 10. capture_stop_thread() returned");
1383
1384 // Signal the audio sender while its queue synchronization objects are still valid.
1386
1387 // Wait for data reception thread to exit gracefully
1388 log_debug("[PROTOCOL_STOP] 11. Waiting for data thread to exit");
1389 // Thread checks should_exit() every read cycle (typically <1-5ms), so timeout can be much shorter
1390 int wait_count = 0;
1391 while (wait_count < 5 && !atomic_load_bool(&g_data_thread_exited)) {
1392 platform_sleep_us(10 * US_PER_MS_INT); // 10ms * 5 = 50ms max wait
1393 wait_count++;
1394 }
1395
1396 if (!atomic_load_bool(&g_data_thread_exited)) {
1397 log_warn("Data thread not responding after 50ms - will be joined by thread pool");
1398 }
1399 log_debug("[PROTOCOL_STOP] 12. Data thread wait complete");
1400
1401 // Join all threads in the client worker pool (in stop_id order)
1402 // This handles the data reception thread and (eventually) all other worker threads
1403 log_debug("[PROTOCOL_STOP] 13. About to call thread_pool_stop_all");
1406 if (result != ASCIICHAT_OK) {
1407 log_error("Failed to stop client worker threads");
1408 LOG_ERRNO_IF_SET("Thread pool stop failed");
1409 }
1410 }
1412 log_debug("[PROTOCOL_STOP] 14. thread_pool_stop_all() returned");
1413
1414 g_data_thread_created = false;
1415
1416#ifdef DEBUG_THREADS
1417 log_debug("Data reception thread stopped and joined by thread pool");
1418#endif
1419 log_debug("[PROTOCOL_STOP] 15. protocol_stop_connection complete");
1420}
uint64_t atomic_load_u64(atomic_t *a)
Atomically load a uint64_t value.
Definition atomic.c:233
h265_encoder_t *volatile g_h265_encoder
Global H.265 encoder context for client video streaming.
asciichat_error_t h265_encoder_flush(h265_encoder_t *encoder, uint8_t *out_data, size_t *out_len)
asciichat_error_t thread_pool_stop_all(void *pool)
Stop all threads in the pool in stop_id order.
void audio_stop_thread()
Stop audio capture thread.
void capture_stop_thread()
Stop capture thread.
void server_connection_shutdown()
Emergency connection shutdown for signal handlers.
void keepalive_stop_thread()
Stop keepalive/ping thread.
Definition keepalive.c:269
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
unsigned char uint8_t
Definition common.h:56
#define US_PER_MS_INT
Definition time.h:160
void audio_sender_cleanup(void)
Cleanup async audio sender.
void audio_sender_finalize(void)

References ASCIICHAT_OK, atomic_load_bool(), atomic_load_u64(), audio_sender_cleanup(), audio_sender_finalize(), audio_stop_thread(), capture_stop_thread(), g_client_worker_pool, g_h265_encoder, GET_OPTION, h265_encoder_flush(), keepalive_stop_thread(), log_debug, LOG_ERRNO_IF_SET, log_error, log_info, log_warn, platform_sleep_us(), SAFE_FREE, SAFE_MALLOC, server_connection_get_transport(), server_connection_is_active(), server_connection_shutdown(), thread_pool_stop_all(), and US_PER_MS_INT.