ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
send.c File Reference

ACIP protocol packet sending functions (transport-agnostic) More...

Go to the source code of this file.

Functions

asciichat_error_t packet_send_via_transport (acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len)
 Send packet via transport with proper header (exported for generic wrappers)
 
asciichat_error_t acip_send_audio_batch (acip_transport_t *transport, const float *samples, uint32_t num_samples, uint32_t batch_count)
 Send audio batch packet.
 
asciichat_error_t acip_send_audio_opus (acip_transport_t *transport, const void *opus_data, size_t opus_len)
 Send Opus-encoded audio packet.
 
asciichat_error_t acip_send_audio_opus_batch (acip_transport_t *transport, const void *opus_data, size_t opus_len, const uint16_t *frame_sizes, uint32_t frame_count, uint32_t sample_rate, uint32_t frame_duration)
 Send batched Opus-encoded audio frames.
 
asciichat_error_t acip_send_ping (acip_transport_t *transport)
 Send ping packet.
 
asciichat_error_t acip_send_pong (acip_transport_t *transport)
 Send pong packet.
 
asciichat_error_t acip_send_error (acip_transport_t *transport, uint32_t error_code, const char *message)
 Send error message packet.
 
asciichat_error_t acip_send_remote_log (acip_transport_t *transport, uint8_t log_level, uint8_t direction, const char *message)
 Send remote log packet.
 
asciichat_error_t acip_send_session_created (acip_transport_t *transport, const acip_session_created_t *response)
 Send SESSION_CREATED response packet.
 
asciichat_error_t acip_send_session_info (acip_transport_t *transport, const acip_session_info_t *info)
 Send SESSION_INFO response packet.
 
asciichat_error_t acip_send_session_joined (acip_transport_t *transport, const acip_session_joined_t *response)
 Send SESSION_JOINED response packet.
 

Detailed Description

ACIP protocol packet sending functions (transport-agnostic)

Implementation of send functions that work with any transport. Refactored from lib/network/av.c to use transport abstraction.

Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
January 2026

Definition in file send.c.

Function Documentation

◆ acip_send_audio_batch()

asciichat_error_t acip_send_audio_batch ( acip_transport_t transport,
const float *  samples,
uint32_t  num_samples,
uint32_t  batch_count 
)

Send audio batch packet.

Parameters
transportTransport instance
samplesAudio samples (float array)
num_samplesNumber of samples
batch_countNumber of batches aggregated
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 90 of file send.c.

91 {
92 if (!transport || !samples || num_samples == 0) {
93 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
94 }
95
96 // Build batch header
98 header.batch_count = batch_count;
99 header.total_samples = (uint32_t)num_samples;
101 header.channels = 1;
102
103 // Calculate total size (header + float samples)
104 size_t samples_size = num_samples * sizeof(float);
105 size_t total_size = sizeof(header) + samples_size;
106
107 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
108 if (!buffer) {
109 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer");
110 }
111
112 // Copy header and samples
113 memcpy(buffer, &header, sizeof(header));
114 memcpy(buffer + sizeof(header), samples, samples_size);
115
116 asciichat_error_t result = packet_send_via_transport(transport, PACKET_TYPE_AUDIO_BATCH, buffer, total_size);
117
118 buffer_pool_free(NULL, buffer, total_size);
119 return result;
120}
#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)
unsigned int uint32_t
Definition common.h:58
unsigned char uint8_t
Definition common.h:56
#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)
Definition error_codes.h:46
@ ERROR_MEMORY
Definition error_codes.h:53
@ ERROR_INVALID_PARAM
uint32_t channels
Number of audio channels (1=mono, 2=stereo)
Definition packet.h:804
uint32_t batch_count
Number of audio chunks in this batch (usually AUDIO_BATCH_COUNT = 32)
Definition packet.h:798
uint32_t sample_rate
Sample rate in Hz (e.g., 44100, 48000)
Definition packet.h:802
uint32_t total_samples
Total audio samples across all chunks (typically 8192)
Definition packet.h:800
@ PACKET_TYPE_AUDIO_BATCH
Batched audio packets for efficiency.
Definition packet.h:343
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len)
Send packet via transport with proper header (exported for generic wrappers)
Definition send.c:40
Audio batch packet structure (Packet Type 28)
Definition packet.h:796

References AUDIO_SAMPLE_RATE, audio_batch_packet_t::batch_count, buffer_pool_alloc(), buffer_pool_free(), audio_batch_packet_t::channels, ERROR_INVALID_PARAM, ERROR_MEMORY, packet_send_via_transport(), PACKET_TYPE_AUDIO_BATCH, audio_batch_packet_t::sample_rate, SET_ERRNO, and audio_batch_packet_t::total_samples.

◆ acip_send_audio_opus()

asciichat_error_t acip_send_audio_opus ( acip_transport_t transport,
const void *  opus_data,
size_t  opus_len 
)

Send Opus-encoded audio packet.

Parameters
transportTransport instance
opus_dataOpus-encoded audio data
opus_lenLength of encoded data
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 122 of file send.c.

122 {
123 if (!transport || !opus_data || opus_len == 0) {
124 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
125 }
126
127 return packet_send_via_transport(transport, PACKET_TYPE_AUDIO_OPUS, opus_data, opus_len);
128}
@ PACKET_TYPE_AUDIO_OPUS
Opus-encoded single audio frame.
Definition packet.h:357

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_AUDIO_OPUS, and SET_ERRNO.

Referenced by client_send_thread_func().

◆ acip_send_audio_opus_batch()

asciichat_error_t acip_send_audio_opus_batch ( acip_transport_t transport,
const void *  opus_data,
size_t  opus_len,
const uint16_t frame_sizes,
uint32_t  frame_count,
uint32_t  sample_rate,
uint32_t  frame_duration 
)

Send batched Opus-encoded audio frames.

Parameters
transportTransport instance
opus_dataOpus-encoded data (multiple frames concatenated)
opus_lenTotal length of encoded data
frame_sizesArray of individual frame sizes
frame_countNumber of frames in batch
sample_rateSample rate in Hz
frame_durationDuration per frame in milliseconds
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 130 of file send.c.

132 {
133 if (!transport || !opus_data || !frame_sizes || frame_count == 0) {
134 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
135 }
136
137 // Build batch header (16 bytes)
138 uint8_t header[16];
139 *(uint32_t *)(header + 0) = HOST_TO_NET_U32(sample_rate);
140 *(uint32_t *)(header + 4) = HOST_TO_NET_U32(frame_duration);
141 *(uint32_t *)(header + 8) = HOST_TO_NET_U32(frame_count);
142 *(uint32_t *)(header + 12) = 0; // reserved
143
144 // Calculate sizes array size
145 size_t sizes_len = frame_count * sizeof(uint16_t);
146 size_t total_size = sizeof(header) + sizes_len + opus_len;
147
148 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
149 if (!buffer) {
150 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer");
151 }
152
153 // Build packet: header + sizes + opus_data
154 memcpy(buffer, header, sizeof(header));
155
156 // Convert frame sizes to network byte order before copying
157 // IMPORTANT: Server expects network byte order and will apply NET_TO_HOST_U16()
158 uint16_t *sizes_buf = (uint16_t *)(buffer + sizeof(header));
159 for (uint32_t i = 0; i < frame_count; i++) {
160 sizes_buf[i] = HOST_TO_NET_U16(frame_sizes[i]);
161 }
162
163 memcpy(buffer + sizeof(header) + sizes_len, opus_data, opus_len);
164
165 asciichat_error_t result = packet_send_via_transport(transport, PACKET_TYPE_AUDIO_OPUS_BATCH, buffer, total_size);
166
167 buffer_pool_free(NULL, buffer, total_size);
168 return result;
169}
#define HOST_TO_NET_U16(val)
Definition endian.h:101
#define HOST_TO_NET_U32(val)
Definition endian.h:71
unsigned short uint16_t
Definition common.h:57
@ PACKET_TYPE_AUDIO_OPUS_BATCH
Batched Opus-encoded audio frames.
Definition packet.h:359

References buffer_pool_alloc(), buffer_pool_free(), ERROR_INVALID_PARAM, ERROR_MEMORY, HOST_TO_NET_U16, HOST_TO_NET_U32, packet_send_via_transport(), PACKET_TYPE_AUDIO_OPUS_BATCH, and SET_ERRNO.

Referenced by threaded_send_audio_opus_batch().

◆ acip_send_error()

asciichat_error_t acip_send_error ( acip_transport_t transport,
uint32_t  error_code,
const char *  message 
)

Send error message packet.

Parameters
transportTransport instance
error_codeError code from asciichat_error_t
messageError message (will be truncated to MAX_ERROR_MESSAGE_LENGTH)
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 205 of file send.c.

205 {
206 if (!transport) {
207 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport");
208 }
209
210 // Calculate message length (max MAX_ERROR_MESSAGE_LENGTH)
211 size_t msg_len = 0;
212 if (message) {
213 msg_len = strlen(message);
214 if (msg_len > MAX_ERROR_MESSAGE_LENGTH) {
215 msg_len = MAX_ERROR_MESSAGE_LENGTH;
216 }
217 }
218
219 error_packet_t header;
221 header.message_length = HOST_TO_NET_U32((uint32_t)msg_len);
222
223 // Allocate buffer for header + message
224 size_t total_size = sizeof(header) + msg_len;
225 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
226 if (!buffer) {
227 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer");
228 }
229
230 // Build packet
231 memcpy(buffer, &header, sizeof(header));
232 if (msg_len > 0) {
233 memcpy(buffer + sizeof(header), message, msg_len);
234 }
235
236 asciichat_error_t result = packet_send_via_transport(transport, PACKET_TYPE_ERROR_MESSAGE, buffer, total_size);
237
238 buffer_pool_free(NULL, buffer, total_size);
239 return result;
240}
asciichat_error_t error_code
uint32_t message_length
Length of message payload in bytes (0-512)
Definition packet.h:623
uint32_t error_code
Error code from asciichat_error_t enumeration.
Definition packet.h:621
#define MAX_ERROR_MESSAGE_LENGTH
Maximum error message length (512 bytes)
Definition packet.h:122
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:352
Error packet structure carrying error code and textual description.
Definition packet.h:619

References buffer_pool_alloc(), buffer_pool_free(), error_code, error_packet_t::error_code, ERROR_INVALID_PARAM, ERROR_MEMORY, HOST_TO_NET_U32, MAX_ERROR_MESSAGE_LENGTH, error_packet_t::message_length, packet_send_via_transport(), PACKET_TYPE_ERROR_MESSAGE, and SET_ERRNO.

◆ acip_send_ping()

asciichat_error_t acip_send_ping ( acip_transport_t transport)

Send ping packet.

Parameters
transportTransport instance
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 175 of file send.c.

175 {
176 if (!transport) {
177 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport");
178 }
179
180 // Ping has no payload
181 return packet_send_via_transport(transport, PACKET_TYPE_PING, NULL, 0);
182}
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_PING, and SET_ERRNO.

◆ acip_send_pong()

asciichat_error_t acip_send_pong ( acip_transport_t transport)

Send pong packet.

Parameters
transportTransport instance
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 184 of file send.c.

184 {
185 if (!transport) {
186 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport");
187 }
188
189 // Pong has no payload
190 return packet_send_via_transport(transport, PACKET_TYPE_PONG, NULL, 0);
191}
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:297

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_PONG, and SET_ERRNO.

Referenced by process_decrypted_packet().

◆ acip_send_remote_log()

asciichat_error_t acip_send_remote_log ( acip_transport_t transport,
uint8_t  log_level,
uint8_t  direction,
const char *  message 
)

Send remote log packet.

Parameters
transportTransport instance
log_levelLog level (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR)
directionDirection hint (0=client->server, 1=server->client)
messageLog message
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 242 of file send.c.

243 {
244 if (!transport || !message) {
245 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport or message");
246 }
247
248 size_t msg_len = strlen(message);
249
250 remote_log_packet_t header;
251 header.log_level = log_level;
252 header.direction = direction;
253 header.flags = 0;
254 header.message_length = HOST_TO_NET_U32((uint32_t)msg_len);
255
256 size_t total_size = sizeof(header) + msg_len;
257
258 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
259 if (!buffer) {
260 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer");
261 }
262
263 // Build packet
264 memcpy(buffer, &header, sizeof(header));
265 memcpy(buffer + sizeof(header), message, msg_len);
266
267 asciichat_error_t result = packet_send_via_transport(transport, PACKET_TYPE_REMOTE_LOG, buffer, total_size);
268
269 buffer_pool_free(NULL, buffer, total_size);
270 return result;
271}
uint16_t flags
Additional flags (REMOTE_LOG_FLAG_*)
Definition packet.h:639
uint32_t message_length
Message payload length in bytes (0-512)
Definition packet.h:641
uint8_t log_level
Log level associated with the message (log_level_t cast to uint8_t)
Definition packet.h:635
uint8_t direction
Direction hint so receivers can annotate origin.
Definition packet.h:637
@ PACKET_TYPE_REMOTE_LOG
Bidirectional remote logging packet.
Definition packet.h:354
Remote log packet structure carrying log level and message text.
Definition packet.h:633

References buffer_pool_alloc(), buffer_pool_free(), remote_log_packet_t::direction, ERROR_INVALID_PARAM, ERROR_MEMORY, remote_log_packet_t::flags, HOST_TO_NET_U32, remote_log_packet_t::log_level, remote_log_packet_t::message_length, packet_send_via_transport(), PACKET_TYPE_REMOTE_LOG, and SET_ERRNO.

◆ acip_send_session_created()

asciichat_error_t acip_send_session_created ( acip_transport_t transport,
const acip_session_created_t response 
)

Send SESSION_CREATED response packet.

Parameters
transportTransport instance
responseSession created response structure
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 277 of file send.c.

277 {
278 if (!transport || !response) {
279 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport or response");
280 }
281
282 return packet_send_via_transport(transport, PACKET_TYPE_ACIP_SESSION_CREATED, response, sizeof(*response));
283}
@ PACKET_TYPE_ACIP_SESSION_CREATED
Session created response (Discovery Server -> Client)
Definition packet.h:371

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_ACIP_SESSION_CREATED, and SET_ERRNO.

◆ acip_send_session_info()

asciichat_error_t acip_send_session_info ( acip_transport_t transport,
const acip_session_info_t info 
)

Send SESSION_INFO response packet.

Parameters
transportTransport instance
infoSession info structure
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 285 of file send.c.

285 {
286 if (!transport || !info) {
287 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport or info");
288 }
289
290 return packet_send_via_transport(transport, PACKET_TYPE_ACIP_SESSION_INFO, info, sizeof(*info));
291}
@ PACKET_TYPE_ACIP_SESSION_INFO
Session info response (Discovery Server -> Client)
Definition packet.h:375

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_ACIP_SESSION_INFO, and SET_ERRNO.

◆ acip_send_session_joined()

asciichat_error_t acip_send_session_joined ( acip_transport_t transport,
const acip_session_joined_t response 
)

Send SESSION_JOINED response packet.

Parameters
transportTransport instance
responseSession joined response structure
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 293 of file send.c.

293 {
294 if (!transport || !response) {
295 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport or response");
296 }
297
298 return packet_send_via_transport(transport, PACKET_TYPE_ACIP_SESSION_JOINED, response, sizeof(*response));
299}
@ PACKET_TYPE_ACIP_SESSION_JOINED
Session joined response (Discovery Server -> Client)
Definition packet.h:379

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_ACIP_SESSION_JOINED, and SET_ERRNO.

◆ packet_send_via_transport()

asciichat_error_t packet_send_via_transport ( acip_transport_t transport,
packet_type_t  type,
const void *  payload,
size_t  payload_len 
)

Send packet via transport with proper header (exported for generic wrappers)

Send arbitrary packet via transport (generic packet sender)

Wraps payload in ACIP packet header and sends via transport. Handles CRC32 calculation and network byte order conversion.

Parameters
transportTransport instance
typePacket type
payloadPayload data (may be NULL if payload_len is 0)
payload_lenPayload length
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 40 of file send.c.

41 {
42 if (!transport) {
43 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport");
44 }
45
46 // Build packet header
47 packet_header_t header;
49 header.type = HOST_TO_NET_U16(type);
50 header.length = HOST_TO_NET_U32((uint32_t)payload_len);
51 header.client_id = 0; // Set by caller if needed
52
53 // Calculate CRC32 if we have payload
54 if (payload && payload_len > 0) {
55 header.crc32 = HOST_TO_NET_U32(asciichat_crc32((const uint8_t *)payload, payload_len));
56 } else {
57 header.crc32 = 0;
58 }
59
60 // Calculate total packet size
61 size_t total_size = sizeof(header) + payload_len;
62
63 // Allocate buffer for complete packet
64 uint8_t *packet = buffer_pool_alloc(NULL, total_size);
65 if (!packet) {
66 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate packet buffer");
67 }
68
69 // Build complete packet: header + payload
70 memcpy(packet, &header, sizeof(header));
71 if (payload && payload_len > 0) {
72 memcpy(packet + sizeof(header), payload, payload_len);
73 }
74
75 // Send via transport (transport handles encryption if crypto_ctx present)
76 asciichat_error_t result = acip_transport_send(transport, packet, total_size);
77
78 buffer_pool_free(NULL, packet, total_size);
79 return result;
80}
uint32_t magic
Magic number (PACKET_MAGIC) for packet validation.
Definition packet.h:492
uint32_t client_id
Client ID (0 = server, >0 = client identifier)
Definition packet.h:500
uint32_t length
Payload data length in bytes (0 for header-only packets)
Definition packet.h:496
uint16_t type
Packet type (packet_type_t enumeration)
Definition packet.h:494
uint32_t crc32
CRC32 checksum of payload data (0 if length == 0)
Definition packet.h:498
#define PACKET_MAGIC
Packet magic number (0xDEADBEEF)
Definition packet.h:251
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
Definition crc32.h:144
Network packet header structure.
Definition packet.h:490

References asciichat_crc32, buffer_pool_alloc(), buffer_pool_free(), packet_header_t::client_id, packet_header_t::crc32, ERROR_INVALID_PARAM, ERROR_MEMORY, HOST_TO_NET_U16, HOST_TO_NET_U32, packet_header_t::length, packet_header_t::magic, PACKET_MAGIC, SET_ERRNO, and packet_header_t::type.

Referenced by acip_send_ascii_frame(), acip_send_audio_batch(), acip_send_audio_opus(), acip_send_audio_opus_batch(), acip_send_capabilities(), acip_send_clear_console(), acip_send_client_join(), acip_send_client_leave(), acip_send_error(), acip_send_image_frame(), acip_send_ping(), acip_send_pong(), acip_send_protocol_version(), acip_send_remote_log(), acip_send_server_state(), acip_send_session_created(), acip_send_session_info(), acip_send_session_joined(), acip_send_stream_start(), acip_send_stream_stop(), client_send_thread_func(), threaded_send_audio_opus(), and threaded_send_packet().