58static atomic_bool g_mirror_should_exit =
false;
65static bool mirror_should_exit(
void) {
66 return atomic_load(&g_mirror_should_exit);
72static void mirror_signal_exit(
void) {
73 atomic_store(&g_mirror_should_exit,
true);
88 static _Atomic
int ctrl_c_count = 0;
89 int count = atomic_fetch_add(&ctrl_c_count, 1) + 1;
93 TerminateProcess(GetCurrentProcess(), 1);
108static tty_info_t g_mirror_tty_info = {-1, NULL,
false};
111static bool g_mirror_has_tty =
false;
118static int mirror_display_init(
void) {
124 if (g_mirror_tty_info.
fd >= 0 && stdout_is_tty) {
127 g_mirror_has_tty =
false;
139static void mirror_display_cleanup(
void) {
142 if (g_mirror_tty_info.
owns_fd && g_mirror_tty_info.
fd >= 0) {
144 g_mirror_tty_info.
fd = -1;
145 g_mirror_tty_info.
owns_fd =
false;
148 g_mirror_has_tty =
false;
156static void mirror_write_frame(
const char *frame_data) {
161 size_t frame_len = strnlen(frame_data, 1024 * 1024);
162 if (frame_len == 0) {
166 if (g_mirror_has_tty && g_mirror_tty_info.
fd >= 0) {
173 const char *output_data = expanded ? expanded : frame_data;
174 size_t output_len = expanded ? strlen(expanded) : frame_len;
177 char *stripped = NULL;
181 output_data = stripped;
182 output_len = strlen(stripped);
191 (void)fflush(stdout);
221 if (webcam_result != 0) {
222 log_fatal(
"Failed to initialize webcam: %s", asciichat_error_string(webcam_result));
224 return webcam_result;
228 if (mirror_display_init() != 0) {
229 log_fatal(
"Failed to initialize display");
248 char palette_chars[256] = {0};
249 size_t palette_len = 0;
250 char luminance_palette[256] = {0};
255 log_fatal(
"Failed to initialize palette");
256 mirror_display_cleanup();
262 const long frame_interval_ms = 1000 / 60;
263 struct timespec last_frame_time = {0, 0};
266 struct timespec snapshot_start_time = {0, 0};
267 bool snapshot_done =
false;
269 (void)clock_gettime(CLOCK_MONOTONIC, &snapshot_start_time);
274 struct timespec fps_report_time;
275 (void)clock_gettime(CLOCK_MONOTONIC, &fps_report_time);
277 log_info(
"Mirror mode running - press Ctrl+C to exit");
280 while (!mirror_should_exit()) {
282 struct timespec current_time;
283 (void)clock_gettime(CLOCK_MONOTONIC, ¤t_time);
285 long elapsed_ms = (current_time.tv_sec - last_frame_time.tv_sec) * 1000 +
286 (current_time.tv_nsec - last_frame_time.tv_nsec) / 1000000;
288 if (elapsed_ms < frame_interval_ms) {
294 if (
GET_OPTION(snapshot_mode) && !snapshot_done) {
295 double elapsed_sec = (double)(current_time.tv_sec - snapshot_start_time.tv_sec) +
296 (double)(current_time.tv_nsec - snapshot_start_time.tv_nsec) / 1e9;
298 float snapshot_delay =
GET_OPTION(snapshot_delay);
299 if (elapsed_sec >= snapshot_delay) {
300 snapshot_done =
true;
316 unsigned short int height =
GET_OPTION(height);
317 bool preserve_aspect_ratio = !stretch;
319 palette_chars, luminance_palette);
324 bool snapshot_mode =
GET_OPTION(snapshot_mode);
325 bool should_write = !snapshot_mode || g_mirror_has_tty || snapshot_done;
327 mirror_write_frame(ascii_frame);
331 if (snapshot_mode && snapshot_done) {
342 last_frame_time = current_time;
346 ((
uint64_t)fps_report_time.tv_sec * 1000000 + (
uint64_t)fps_report_time.tv_nsec / 1000);
348 if (fps_elapsed_us >= 5000000) {
349 double fps = (double)frame_count / ((
double)fps_elapsed_us / 1000000.0);
352 fps_report_time = current_time;
358 log_info(
"Mirror mode shutting down");
360 mirror_display_cleanup();
🔌 Cross-platform abstraction layer umbrella header for ascii-chat
char * ansi_strip_escapes(const char *input, size_t input_len)
Strip all ANSI escape sequences from a string.
ANSI escape sequence utilities.
Fast ANSI escape sequence generation.
🖼️ ASCII Art Conversion and Output Interface
unsigned long long uint64_t
#define log_fatal(...)
Log a FATAL message.
#define log_info(...)
Log an INFO message.
#define log_debug(...)
Log a DEBUG message.
void log_set_terminal_output(bool enabled)
Control stderr output to terminal.
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
int initialize_client_palette(palette_type_t palette_type, const char *custom_chars, char client_palette_chars[256], size_t *client_palette_len, char client_luminance_palette[256])
Initialize client palette with full configuration.
palette_type_t
Built-in palette type enumeration.
void ansi_fast_init_256color(void)
Initialize 256-color mode lookup tables.
asciichat_error_t ascii_write_init(int fd, bool reset_terminal)
Initialize ASCII write subsystem.
void ascii_write_destroy(int fd, bool reset_terminal)
Destroy ASCII write subsystem.
void ansi_fast_init(void)
Initialize the decimal lookup table.
#define cursor_reset(fd)
Reset cursor to home position.
void ansi_fast_init_16color(void)
Initialize 16-color mode lookup tables.
void image_destroy(image_t *p)
Destroy an image allocated with image_new()
char * ansi_expand_rle(const char *input, size_t input_len)
Expand RLE escape sequences in a string.
char * ascii_convert_with_capabilities(image_t *original, const ssize_t width, const ssize_t height, const terminal_capabilities_t *caps, const bool use_aspect_ratio, const bool stretch, const char *palette_chars, const char luminance_palette[256])
Convert image to ASCII art with terminal capability awareness.
asciichat_error_t webcam_init(unsigned short int webcam_index)
Initialize global webcam interface.
image_t * webcam_read(void)
Capture a frame from global webcam.
void webcam_print_init_error_help(asciichat_error_t error_code)
Print helpful error diagnostics for webcam initialization failures.
void webcam_cleanup(void)
Clean up global webcam interface.
int mirror_main(void)
Run mirror mode main loop.
⚙️ Command-line options parsing and configuration management for ascii-chat
ASCII Palette Management for Video-to-ASCII Conversion.
ANSI RLE (REP) sequence compression and expansion.
ascii-chat Server Mode Entry Point Header
Complete terminal capabilities structure.
terminal_color_mode_t color_level
Detected color support level (terminal_color_mode_t)
TTY detection and management structure.
bool owns_fd
True if we opened the FD and should close it, false otherwise.
int fd
File descriptor for TTY access.
🖥️ Cross-platform terminal interface for ascii-chat
⏱️ High-precision timing utilities using sokol_time.h and uthash
Image Data Structures and Operations.