43static int calculate_packet_timeout(
size_t packet_size) {
51 int total_timeout = base_timeout + extra_timeout;
56 if (total_timeout < min_timeout) {
57 total_timeout = min_timeout;
77 if (!header || !pkt_type || !pkt_len || !expected_crc) {
79 header, pkt_type, pkt_len, expected_crc);
85 if (pkt_len_network == 0xFFFFFFFF) {
92 uint32_t len = endian_unpack_u32(pkt_len_network);
172 if (len == 0 || len > 32) {
178 if (len == 0 || len > 32) {
262 if (!data && len > 0) {
268 if (expected_crc != 0) {
275 if (calculated_crc != expected_crc) {
307 int timeout = calculate_packet_timeout(len);
315 if ((
size_t)sent !=
sizeof(header)) {
316 return SET_ERRNO(
ERROR_NETWORK,
"Failed to fully send packet header. Sent %zd/%zu bytes", sent,
sizeof(header));
320 if (len > 0 && data) {
331 if ((
size_t)sent != len) {
355 if (!type || !data || !len) {
367 if ((
size_t)received !=
sizeof(header)) {
369 log_warn(
"Connection closed while reading packet header");
373 return SET_ERRNO(
ERROR_NETWORK,
"Partial packet header received: %zd/%zu bytes", received,
sizeof(header));
386 void *payload = NULL;
397 if (received != (ssize_t)pkt_len) {
440 if (packet_is_handshake_type(type)) {
445 const void *final_data = data;
446 size_t final_len = len;
447 void *compressed_data = NULL;
450 bool should_skip_compression = packet_is_precompressed(type) ||
GET_OPTION(no_compress);
452 void *temp_compressed = NULL;
453 size_t compressed_size = 0;
456 int compression_level = (
GET_OPTION(compression_level) > 0) ?
GET_OPTION(compression_level) : 1;
459 double ratio = (double)compressed_size / (
double)len;
461 final_data = temp_compressed;
462 final_len = compressed_size;
463 compressed_data = temp_compressed;
464 log_debug(
"Compressed packet: %zu -> %zu bytes (%.1f%%)", len, compressed_size, ratio * 100.0);
473 if (!crypto_ctx || !ready) {
475 (
void *)crypto_ctx, ready);
477 if (compressed_data) {
495 if (final_len > SIZE_MAX -
sizeof(header)) {
496 if (compressed_data) {
501 size_t plaintext_len =
sizeof(header) + final_len;
504 if (compressed_data) {
510 memcpy(plaintext, &header,
sizeof(header));
511 if (final_len > 0 && final_data) {
512 memcpy(plaintext +
sizeof(header), final_data, final_len);
519 if (compressed_data) {
528 if (compressed_data) {
534 size_t ciphertext_len;
536 crypto_encrypt(crypto_ctx, plaintext, plaintext_len, ciphertext, ciphertext_size, &ciphertext_len);
541 if (compressed_data) {
553 if (compressed_data) {
577 memset(envelope, 0,
sizeof(*envelope));
594 if ((
size_t)received !=
sizeof(header)) {
633 if (received != (ssize_t)pkt_len) {
641 size_t plaintext_size = (size_t)pkt_len + 1024;
649 size_t plaintext_len;
673 if (payload_len != pkt_len) {
682 if (actual_crc != expected_crc) {
692 envelope->
len = pkt_len;
700 if (enforce_encryption && !packet_is_handshake_type(pkt_type)) {
715 if (received != (ssize_t)pkt_len) {
723 if (actual_crc != expected_crc) {
729 envelope->
data = payload;
735 envelope->
len = pkt_len;
808 const char *message) {
832 if (message_len > 0) {
839 if (encryption_ready) {
855 char *message_buffer,
size_t message_buffer_size,
856 size_t *out_message_length) {
857 if (!data || len <
sizeof(
error_packet_t) || !out_error_code || !message_buffer || message_buffer_size == 0) {
859 "Invalid parameters: data=%p len=%zu out_error_code=%p message_buffer=%p buffer_size=%zu", data,
860 len, out_error_code, message_buffer, message_buffer_size);
871 size_t total_required =
sizeof(
error_packet_t) + (
size_t)raw_message_length;
872 if (total_required > len) {
878 size_t copy_len = raw_message_length;
879 if (copy_len >= message_buffer_size) {
880 copy_len = message_buffer_size - 1;
884 memcpy(message_buffer, message_bytes, copy_len);
886 message_buffer[copy_len] =
'\0';
888 if (out_message_length) {
889 *out_message_length = raw_message_length;
902 if (level < LOG_DEV || level >
LOG_FATAL) {
906 const char *safe_message = message ? message :
"";
907 bool truncated =
false;
929 if (message_len > 0) {
936 if (encryption_ready) {
955 char *message_buffer,
size_t message_buffer_size,
956 size_t *out_message_length) {
957 if (!data || len <
sizeof(
remote_log_packet_t) || !out_level || !out_direction || !out_flags || !message_buffer ||
958 message_buffer_size == 0) {
961 "Invalid parameters: data=%p len=%zu out_level=%p out_direction=%p out_flags=%p buffer=%p size=%zu", data, len,
962 out_level, out_direction, out_flags, message_buffer, message_buffer_size);
979 *out_flags = raw_flags;
987 if (total_required > len) {
989 total_required, len);
993 size_t copy_len = raw_message_length;
994 if (copy_len >= message_buffer_size) {
995 copy_len = message_buffer_size - 1;
999 memcpy(message_buffer, message_bytes, copy_len);
1001 message_buffer[copy_len] =
'\0';
1003 if (out_message_length) {
1004 *out_message_length = raw_message_length;
1074 if (!samples || num_samples <= 0 || batch_count <= 0) {
1076 num_samples, batch_count);
1087 size_t data_size = (size_t)num_samples *
sizeof(
uint32_t);
1088 size_t total_size =
sizeof(header) + data_size;
1097 memcpy(buffer, &header,
sizeof(header));
1102 uint8_t *sample_data_ptr = buffer +
sizeof(header);
1103 for (
int i = 0; i < num_samples; i++) {
1105 float clamped_sample = samples[i];
1106 if (clamped_sample > 1.0f)
1107 clamped_sample = 1.0f;
1108 if (clamped_sample < -1.0f)
1109 clamped_sample = -1.0f;
1112 int32_t scaled = (int32_t)(clamped_sample * 2147483647.0f);
1114 memcpy(sample_data_ptr + (
size_t)i *
sizeof(
uint32_t), &network_value,
sizeof(
uint32_t));
1119 static int send_count = 0;
1121 if (send_count % 100 == 0) {
1122 log_info(
"SEND: samples[0]=%.6f, samples[1]=%.6f, samples[2]=%.6f", (
double)samples[0], (
double)samples[1],
1123 (
double)samples[2]);
1124 log_info(
"SEND: scaled[0]=%d, scaled[1]=%d, scaled[2]=%d", (int32_t)(samples[0] * 2147483647.0f),
1125 (int32_t)(samples[1] * 2147483647.0f), (int32_t)(samples[2] * 2147483647.0f));
1137 const uint16_t *frame_sizes,
int sample_rate,
int frame_duration,
1139 if (!opus_data || opus_size == 0 || !frame_sizes || sample_rate <= 0 || frame_duration <= 0 || frame_count <= 0) {
1141 "Invalid Opus batch parameters: opus_data=%p, opus_size=%zu, frame_sizes=%p, sample_rate=%d, "
1142 "frame_duration=%d, frame_count=%d",
1143 (
const void *)opus_data, opus_size, (
const void *)frame_sizes, sample_rate, frame_duration,
1149 if (frame_count > 1000) {
1154 size_t header_size = 16;
1155 size_t frame_sizes_bytes = (size_t)frame_count *
sizeof(
uint16_t);
1156 size_t total_size = header_size + frame_sizes_bytes + opus_size;
1159 return SET_ERRNO(
ERROR_MEMORY,
"Failed to allocate buffer for Opus batch packet: %zu bytes", total_size);
1167 memcpy(buf, &sr, 4);
1168 memcpy(buf + 4, &fd, 4);
1169 memcpy(buf + 8, &fc, 4);
1170 memset(buf + 12, 0, 4);
1174 for (
int i = 0; i < frame_count; i++) {
1179 memcpy(buf + header_size + frame_sizes_bytes, opus_data, opus_size);
1192 if (!frame_data || frame_size == 0) {
1214 return SET_ERRNO(
ERROR_MEMORY,
"Failed to allocate buffer for ASCII frame packet: %zu bytes", total_size);
1232 if (!image_data || width == 0 || height == 0) {
1239 if (width > 4096 || height > 4096) {
1245 packet.
width = width;
1255 size_t width_times_height;
1256 if (checked_size_mul((
size_t)width, (
size_t)height, &width_times_height) !=
ASCIICHAT_OK) {
1261 if (checked_size_mul(width_times_height, 3u, &frame_size) !=
ASCIICHAT_OK) {
1273 return SET_ERRNO(
ERROR_MEMORY,
"Failed to allocate buffer for image frame packet: %zu bytes", total_size);
asciichat_error_t error_code
⚠️‼️ Error and/or exit() when things go bad.
🗃️ Lock-Free Unified Memory Buffer Pool with Lazy Allocation
📦 Network Packet Compression Utilities
Hardware-Accelerated CRC32 Checksum Computation.
🔄 Network byte order conversion helpers
#define HOST_TO_NET_U16(val)
#define HOST_TO_NET_U32(val)
#define NET_TO_HOST_U16(val)
#define NET_TO_HOST_U32(val)
#define AUDIO_SAMPLE_RATE
Audio sample rate (48kHz professional quality, Opus-compatible)
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
Free a buffer back to the pool (lock-free)
void * buffer_pool_alloc(buffer_pool_t *pool, size_t size)
Allocate a buffer from the pool (lock-free fast path)
#define SAFE_MALLOC(size, cast)
#define SAFE_STRERROR(errnum)
#define COMPRESSION_MIN_SIZE
Minimum packet size to attempt compression (1KB)
bool should_compress(size_t original_size, size_t compressed_size)
Determine if compression should be used for given data sizes.
asciichat_error_t compress_data(const void *input, size_t input_size, void **output, size_t *output_size, int compression_level)
Compress data using zstd with configurable compression level.
#define COMPRESSION_RATIO_THRESHOLD
Compression ratio threshold - only use if <80% original size.
crypto_result_t crypto_encrypt(crypto_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext_out, size_t ciphertext_out_size, size_t *ciphertext_len_out)
Encrypt data using XSalsa20-Poly1305.
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20)
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
#define CRYPTO_MAC_SIZE
MAC size (Poly1305)
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
crypto_result_t crypto_decrypt(crypto_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext_out, size_t plaintext_out_size, size_t *plaintext_len_out)
Decrypt data using XSalsa20-Poly1305.
#define SET_ERRNO_SYS(code, context_msg,...)
Set error code with custom message and system error context.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
#define LOG_RATE_FAST
Log rate limit: 1 second (1,000,000 microseconds)
#define LOG_RATE_SLOW
Log rate limit: 10 seconds (10,000,000 microseconds)
#define log_warn(...)
Log a WARN message.
enum remote_log_direction remote_log_direction_t
Remote log packet direction enumeration.
#define log_debug_every(interval_us, fmt,...)
Rate-limited DEBUG logging.
log_level_t
Logging levels enumeration.
#define log_info(...)
Log an INFO message.
#define log_debug(...)
Log a DEBUG message.
#define log_warn_every(interval_us, fmt,...)
Rate-limited WARN logging.
@ REMOTE_LOG_DIRECTION_UNKNOWN
@ REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER
uint32_t pixel_format
Pixel format enum (0=RGB24, 1=RGBA32, 2=BGR24, etc.)
asciichat_error_t send_packet_secure(socket_t sockfd, packet_type_t type, const void *data, size_t len, crypto_context_t *crypto_ctx)
Send a packet with encryption and compression support.
uint32_t timestamp
Timestamp when frame was captured (milliseconds since epoch)
uint32_t magic
Magic number (PACKET_MAGIC) for packet validation.
uint16_t flags
Additional flags (REMOTE_LOG_FLAG_*)
asciichat_error_t packet_parse_remote_log(const void *data, size_t len, log_level_t *out_level, remote_log_direction_t *out_direction, uint16_t *out_flags, char *message_buffer, size_t message_buffer_size, size_t *out_message_length)
Parse a remote log packet payload into components.
uint32_t message_length
Message payload length in bytes (0-512)
uint8_t log_level
Log level associated with the message (log_level_t cast to uint8_t)
uint32_t width
Terminal width in characters.
asciichat_error_t packet_send_error(socket_t sockfd, const crypto_context_t *crypto_ctx, asciichat_error_t error_code, const char *message)
Send an error packet with optional encryption context.
asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc)
Validate packet CRC32.
asciichat_error_t packet_send_remote_log(socket_t sockfd, const crypto_context_t *crypto_ctx, log_level_t level, remote_log_direction_t direction, uint16_t flags, const char *message)
Send a remote log packet with optional encryption context.
uint32_t message_length
Length of message payload in bytes (0-512)
asciichat_error_t send_image_frame_packet(socket_t sockfd, const void *image_data, uint16_t width, uint16_t height, uint8_t format)
Send image frame packet.
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
uint32_t length
Payload data length in bytes (0 for header-only packets)
uint32_t error_code
Error code from asciichat_error_t enumeration.
void * allocated_buffer
Buffer that needs to be freed by caller (may be NULL if not allocated)
uint32_t checksum
CRC32 checksum of original ASCII data.
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
int send_pong_packet(socket_t sockfd)
Send a pong packet.
uint32_t original_size
Size of original uncompressed ASCII data in bytes.
uint32_t height
Terminal height in characters.
asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count, crypto_context_t *crypto_ctx)
Send a batched audio packet with encryption support.
asciichat_error_t packet_receive(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a packet with proper header validation and CRC32 checking.
uint32_t compressed_size
Size of compressed data (0 = not compressed)
ssize_t send_with_timeout(socket_t sockfd, const void *data, size_t len, int timeout_seconds)
Send data with timeout using chunked transmission.
asciichat_error_t packet_parse_error_message(const void *data, size_t len, asciichat_error_t *out_error_code, char *message_buffer, size_t message_buffer_size, size_t *out_message_length)
Parse an error packet payload into components.
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
asciichat_error_t send_ascii_frame_packet(socket_t sockfd, const char *frame_data, size_t frame_size)
Send ASCII frame packet.
asciichat_error_t av_send_audio_opus_batch(socket_t sockfd, const uint8_t *opus_data, size_t opus_size, const uint16_t *frame_sizes, int sample_rate, int frame_duration, int frame_count, crypto_context_t *crypto_ctx)
Send Opus-encoded audio batch packet with encryption support.
#define network_is_test_environment()
Check if we're in a test environment.
size_t allocated_size
Size of allocated buffer in bytes.
size_t len
Length of payload data in bytes.
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
asciichat_error_t packet_validate_header(const packet_header_t *header, uint16_t *pkt_type, uint32_t *pkt_len, uint32_t *expected_crc)
Validate packet header and return parsed information.
void * data
Packet payload data (decrypted and decompressed if applicable)
asciichat_error_t packet_send(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a packet with proper header and CRC32.
uint32_t compressed_size
Compressed data size (0 = not compressed, >0 = compressed)
packet_recv_result_t receive_packet_secure(socket_t sockfd, void *crypto_ctx, bool enforce_encryption, packet_envelope_t *envelope)
Receive a packet with decryption and decompression support.
uint16_t type
Packet type (packet_type_t enumeration)
#define RECV_TIMEOUT
Receive timeout in seconds (15 seconds)
int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps)
Send crypto capabilities packet.
uint32_t checksum
CRC32 checksum of pixel data.
uint32_t channels
Number of audio channels (1=mono, 2=stereo)
int send_clear_console_packet(socket_t sockfd)
Send a clear console packet.
uint8_t direction
Direction hint so receivers can annotate origin.
int send_ping_packet(socket_t sockfd)
Send a ping packet.
uint32_t height
Image height in pixels.
packet_type_t type
Packet type (from packet_types.h)
uint32_t batch_count
Number of audio chunks in this batch (usually AUDIO_BATCH_COUNT = 32)
uint32_t width
Image width in pixels.
uint32_t flags
Frame flags bitmask (HAS_COLOR, IS_COMPRESSED, etc.)
uint32_t sample_rate
Sample rate in Hz (e.g., 44100, 48000)
uint32_t total_samples
Total audio samples across all chunks (typically 8192)
ssize_t recv_with_timeout(socket_t sockfd, void *buf, size_t len, int timeout_seconds)
Receive data with timeout.
#define REMOTE_LOG_FLAG_TRUNCATED
Remote log packet flag definitions.
int send_crypto_parameters_packet(socket_t sockfd, const crypto_parameters_packet_t *params)
Send crypto parameters packet.
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
uint32_t crc32
CRC32 checksum of payload data (0 if length == 0)
packet_recv_result_t
Packet reception result codes.
#define SEND_TIMEOUT
Send timeout in seconds (5 seconds)
@ PACKET_RECV_ERROR
Network error occurred.
@ PACKET_RECV_EOF
Connection closed (EOF)
@ PACKET_RECV_SUCCESS
Packet received successfully.
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
#define AUDIO_SAMPLES_PER_PACKET
Samples per audio packet (256 samples)
#define LARGE_PACKET_THRESHOLD
Large packet size threshold (100KB)
#define MAX_CLIENT_TIMEOUT
Maximum client timeout in seconds (60 seconds)
#define LARGE_PACKET_EXTRA_TIMEOUT_PER_MB
Extra timeout per MB for large packets (0.8 seconds per MB)
packet_type_t
Network protocol packet type enumeration.
#define MAX_PACKET_SIZE
Maximum packet size (5MB)
#define MAX_REMOTE_LOG_MESSAGE_LENGTH
Maximum remote log message length (512 bytes)
#define PACKET_MAGIC
Packet magic number (0xDEADBEEF)
#define MAX_ERROR_MESSAGE_LENGTH
Maximum error message length (512 bytes)
#define MIN_CLIENT_TIMEOUT
Minimum client timeout in seconds (10 seconds)
@ PACKET_TYPE_ACIP_WEBRTC_ICE
WebRTC ICE candidate (bidirectional)
@ PACKET_TYPE_AUDIO_OPUS_BATCH
Batched Opus-encoded audio frames.
@ PACKET_TYPE_CLIENT_LEAVE
Clean disconnect notification.
@ PACKET_TYPE_ACIP_SESSION_INFO
Session info response (Discovery Server -> Client)
@ PACKET_TYPE_IMAGE_FRAME
Complete RGB image with dimensions.
@ PACKET_TYPE_CRYPTO_AUTH_RESPONSE
Client -> Server: {HMAC[32]} (UNENCRYPTED)
@ PACKET_TYPE_TEXT_MESSAGE
Text message.
@ PACKET_TYPE_AUDIO_MESSAGE
Audio message.
@ PACKET_TYPE_PONG
Keepalive pong response.
@ PACKET_TYPE_ACIP_SESSION_RECONNECT
Reconnect to session (Client -> Discovery Server)
@ PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE
Server -> Client: "encryption ready" (UNENCRYPTED)
@ PACKET_TYPE_STREAM_START
Client requests to start sending video/audio.
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT
Server -> Client: {server_pubkey[32]} (UNENCRYPTED)
@ PACKET_TYPE_ACIP_ERROR
Generic error response (Discovery Server -> Client)
@ PACKET_TYPE_AUDIO
Single audio packet (legacy)
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP
Client -> Server: {client_pubkey[32]} (UNENCRYPTED)
@ PACKET_TYPE_ACIP_STRING_RESERVE
Reserve session string (Client -> Discovery Server)
@ PACKET_TYPE_CRYPTO_AUTH_FAILED
Server -> Client: "authentication failed" (UNENCRYPTED)
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion)
@ PACKET_TYPE_SIZE_MESSAGE
Terminal size message.
@ PACKET_TYPE_REMOTE_LOG
Bidirectional remote logging packet.
@ PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP
Server -> Client: {HMAC[32]} server proves knowledge (UNENCRYPTED)
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
@ PACKET_TYPE_CLEAR_CONSOLE
Server tells client to clear console.
@ PACKET_TYPE_CRYPTO_NO_ENCRYPTION
Client -> Server: "I want to proceed without encryption" (UNENCRYPTED)
@ PACKET_TYPE_ACIP_SESSION_CREATE
Create new session (Client -> Discovery Server)
@ PACKET_TYPE_ACIP_STRING_RESERVED
String reserved response (Discovery Server -> Client)
@ PACKET_TYPE_ACIP_DISCOVERY_PING
Discovery server ping (keepalive)
@ PACKET_TYPE_CRYPTO_AUTH_CHALLENGE
Server -> Client: {nonce[32]} (UNENCRYPTED)
@ PACKET_TYPE_ASCII_FRAME
Complete ASCII frame with all metadata.
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED)
@ PACKET_TYPE_ACIP_SESSION_LOOKUP
Lookup session by string (Client -> Discovery Server)
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED)
@ PACKET_TYPE_ACIP_SESSION_LEAVE
Leave session (Client -> Discovery Server)
@ PACKET_TYPE_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
@ PACKET_TYPE_ACIP_SESSION_JOIN
Join existing session (Client -> Discovery Server)
@ PACKET_TYPE_ACIP_SESSION_CREATED
Session created response (Discovery Server -> Client)
@ PACKET_TYPE_ACIP_STRING_RELEASE
Release string reservation (Client -> Discovery Server)
@ PACKET_TYPE_CLIENT_JOIN
Client announces capability to send media.
@ PACKET_TYPE_CLIENT_CAPABILITIES
Client reports terminal capabilities.
@ PACKET_TYPE_ACIP_STRING_RENEW
Renew string reservation (Client -> Discovery Server)
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
@ PACKET_TYPE_PING
Keepalive ping packet.
@ PACKET_TYPE_AUDIO_BATCH
Batched audio packets for efficiency.
@ PACKET_TYPE_ACIP_SESSION_JOINED
Session joined response (Discovery Server -> Client)
@ PACKET_TYPE_STREAM_STOP
Client stops sending media.
@ PACKET_TYPE_ACIP_SESSION_END
End session (Host -> Discovery Server)
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
🔊 Audio Capture and Playback Interface for ascii-chat
🌐 Core network I/O operations with timeout support
⚙️ Command-line options parsing and configuration management for ascii-chat
✅ Safe Integer Arithmetic and Overflow Detection
Packet protocol implementation with encryption and compression support.
Cross-platform socket interface for ascii-chat.
ASCII frame packet structure (Packet Type 2)
Audio batch packet structure (Packet Type 28)
Client information packet structure.
Crypto capabilities packet structure (Packet Type 14)
Cryptographic context structure.
Crypto parameters packet structure (Packet Type 15)
Error packet structure carrying error code and textual description.
Image frame packet structure (Packet Type 3)
Packet envelope containing received packet data.
Protocol version negotiation packet structure (Packet Type 1)
Remote log packet structure carrying log level and message text.