37#include <ascii-chat/session/capture.h>
38#include <ascii-chat/session/display.h>
39#include <ascii-chat/session/host.h>
40#include <ascii-chat/session/render.h>
41#include <ascii-chat/session/keyboard_handler.h>
42#include <ascii-chat/session/client_like.h>
46#include <ascii-chat/log/logging.h>
47#include <ascii-chat/options/options.h>
48#include <ascii-chat/options/common.h>
49#include <ascii-chat/util/time.h>
50#include <ascii-chat/platform/abstraction.h>
51#include <ascii-chat/platform/keyboard.h>
73static void on_discovery_state_change(
discovery_state_t new_state,
void *user_data) {
76 const char *state_names[] = {
"INIT",
"CONNECTING_ACDS",
"CREATING_SESSION",
"JOINING_SESSION",
77 "WAITING_PEER",
"NEGOTIATING",
"STARTING_HOST",
"CONNECTING_HOST",
78 "ACTIVE",
"MIGRATING",
"FAILED",
"ENDED"};
80 if (new_state >= 0 && new_state < (
int)(
sizeof(state_names) /
sizeof(state_names[0]))) {
81 log_info(
"Discovery state: %s", state_names[new_state]);
91static void on_session_ready(
const char *session_string,
void *user_data) {
94 if (session_string && session_string[0]) {
95 log_info(
"Session ready! Share this with your peer: %s", session_string);
106static void on_discovery_error(asciichat_error_t error,
const char *message,
void *user_data) {
109 log_error(
"Discovery error (%d): %s", error, message ? message :
"Unknown");
122static bool discovery_participant_render_should_exit(
void *user_data) {
133 if (result != ASCIICHAT_OK && result != ERROR_NETWORK_TIMEOUT) {
134 log_error(
"Discovery session process failed: %d", result);
155static bool discovery_capture_should_exit_adapter(
void *user_data) {
167static bool discovery_display_should_exit_adapter(
void *user_data) {
182static void discovery_keyboard_handler(session_capture_ctx_t *capture,
int key,
void *user_data) {
204static asciichat_error_t discovery_run(session_capture_ctx_t *capture,
session_display_ctx_t *display,
208 asciichat_error_t result = ASCIICHAT_OK;
214 if (result != ASCIICHAT_OK && result != ERROR_NETWORK_TIMEOUT) {
215 log_error(
"Discovery session process failed: %d", result);
225 log_info(
"Shutdown requested during discovery negotiation");
234 log_info(
"Hosting session - capturing and broadcasting");
237 session_host_config_t host_config = {
238 .port = (int)GET_OPTION(port),
239 .ipv4_address = NULL,
240 .ipv6_address = NULL,
242 .encryption_enabled =
false,
251 log_fatal(
"Failed to create session host");
257 if (result != ASCIICHAT_OK) {
258 log_error(
"Failed to start session host: %d", result);
265 if (host_participant_id == 0) {
266 log_error(
"Failed to add memory participant for host");
269 return ERROR_INVALID_STATE;
272 log_info(
"Host participating with ID %u", host_participant_id);
285 if (result != ASCIICHAT_OK && result != ERROR_NETWORK_TIMEOUT) {
286 log_error(
"Discovery session process failed: %d", result);
305 log_info(
"Session ended or role changed");
310 log_info(
"Participant in session - displaying host's frames");
316 discovery_keyboard_handler,
319 if (result != ASCIICHAT_OK) {
320 log_error(
"Render loop failed with error code: %d", result);
339 log_debug(
"discovery_main() starting");
346 const char *session_string = GET_OPTION(session_string);
347 bool is_initiator = (session_string == NULL || session_string[0] ==
'\0');
349 int port_int = GET_OPTION(port);
351 log_debug(
"Discovery: is_initiator=%d, port=%d", is_initiator, port_int);
356 .acds_port = (uint16_t)GET_OPTION(discovery_port),
357 .session_string = is_initiator ? NULL : session_string,
358 .local_port = (uint16_t)port_int,
359 .on_state_change = on_discovery_state_change,
360 .on_session_ready = on_session_ready,
361 .on_error = on_discovery_error,
362 .callback_user_data = NULL,
363 .should_exit_callback = discovery_capture_should_exit_adapter,
364 .exit_callback_data = NULL,
370 log_fatal(
"Failed to create discovery session");
375 log_debug(
"Discovery: starting discovery session");
377 if (result != ASCIICHAT_OK) {
378 log_fatal(
"Failed to start discovery session: %d", result);
405 session_client_like_config_t config = {
406 .run_fn = discovery_run,
407 .run_user_data = NULL,
409 .websocket_client = NULL,
410 .discovery = (
void *)g_discovery,
411 .custom_should_exit = NULL,
412 .exit_user_data = NULL,
413 .keyboard_handler = discovery_keyboard_handler,
414 .max_reconnect_attempts = 0,
415 .should_reconnect_callback = NULL,
416 .reconnect_user_data = NULL,
417 .reconnect_delay_ms = 0,
418 .print_newline_on_tty_exit =
false,
421 log_debug(
"Discovery: calling session_client_like_run()");
423 log_debug(
"Discovery: session_client_like_run() returned %d", session_result);
426 log_debug(
"Discovery: cleaning up");
434 return (session_result == ASCIICHAT_OK) ? 0 : (int)session_result;
asciichat_error_t session_client_like_run(const session_client_like_config_t *config)
int discovery_main(void)
Run discovery mode main loop.
asciichat_error_t session_host_inject_frame(session_host_t *host, uint32_t participant_id, const image_t *frame)
uint32_t session_host_add_memory_participant(session_host_t *host)
void session_host_stop(session_host_t *host)
asciichat_error_t session_host_start(session_host_t *host)
void session_host_destroy(session_host_t *host)
session_host_t * session_host_create(const session_host_config_t *config)
void session_handle_keyboard_input(session_capture_ctx_t *capture, session_display_ctx_t *display, keyboard_key_t key)
image_t * session_capture_read_frame(session_capture_ctx_t *ctx)
void session_capture_sleep_for_fps(session_capture_ctx_t *ctx)
asciichat_error_t session_render_loop(session_capture_ctx_t *capture, session_display_ctx_t *display, session_should_exit_fn should_exit, session_capture_fn capture_cb, session_sleep_for_frame_fn sleep_cb, session_keyboard_handler_fn keyboard_handler, void *user_data)
void set_interrupt_callback(void(*cb)(void))
ascii-chat Server Mode Entry Point Header
Discovery session flow management.
discovery_state_t
Discovery session state.
bool discovery_session_is_active(const discovery_session_t *session)
Check if session is active (call in progress)
void discovery_session_stop(discovery_session_t *session)
Stop the discovery session.
bool discovery_session_is_host(const discovery_session_t *session)
Check if we are the host.
discovery_session_t * discovery_session_create(const discovery_config_t *config)
Create a new discovery session.
asciichat_error_t discovery_session_start(discovery_session_t *session)
Start the discovery session.
asciichat_error_t discovery_session_process(discovery_session_t *session, int64_t timeout_ns)
Process session events (call in main loop)
void discovery_session_destroy(discovery_session_t *session)
Destroy discovery session and free resources.
Configuration for discovery session.
const char * acds_address
ACDS address (default: "127.0.0.1")
Discovery session context.
Internal session display context structure.
Internal session host structure.