ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
runtime.h File Reference

Go to the source code of this file.

Data Structures

struct  stats_view_t

Macros

#define STATS_RUNTIME_MODE_BUFFER_SIZE   32
#define STATS_VIEW_LINE_BUFFER_SIZE   160
#define STATS_VIEW_LINES   128

Typedefs

typedef struct stats_peer stats_peer_t
typedef void(* stats_provider_fn) (stats_view_t *view, void *data)

Functions

asciichat_error_t stats_runtime_start (const char *mode, unsigned interval_seconds)
void stats_runtime_stop (void)
stats_scope_t * stats_runtime_scope (void)
void stats_runtime_set_provider (stats_provider_fn provider, void *data)
void stats_view_add (stats_view_t *view, const char *format,...)
void stats_view_add_header (stats_view_t *view, const char *format,...)
void stats_runtime_toggle (void)
bool stats_runtime_active (void)
stats_peer_t * stats_runtime_peer_open (const char *transport)
void stats_runtime_peer_close (stats_peer_t *peer)
stats_scope_t * stats_runtime_peer_scope (stats_peer_t *peer)
void stats_runtime_packet (stats_peer_t *peer, unsigned type, size_t payload_bytes, bool sent, bool success)
void stats_runtime_connection_state (const char *state)
void stats_runtime_media (unsigned width, unsigned height, double position, double duration)

Macro Definition Documentation

◆ STATS_RUNTIME_MODE_BUFFER_SIZE

#define STATS_RUNTIME_MODE_BUFFER_SIZE   32

Definition at line 4 of file stats/runtime.h.

◆ STATS_VIEW_LINE_BUFFER_SIZE

#define STATS_VIEW_LINE_BUFFER_SIZE   160

Definition at line 7 of file stats/runtime.h.

◆ STATS_VIEW_LINES

#define STATS_VIEW_LINES   128

Definition at line 13 of file stats/runtime.h.

Typedef Documentation

◆ stats_peer_t

typedef struct stats_peer stats_peer_t

Definition at line 12 of file stats/runtime.h.

◆ stats_provider_fn

typedef void(* stats_provider_fn) (stats_view_t *view, void *data)

Provider runs on the stats worker; unregister before destroying its data. Never call stats_runtime_set_provider() from a provider.

Definition at line 30 of file stats/runtime.h.

Function Documentation

◆ stats_runtime_active()

bool stats_runtime_active ( void )

Definition at line 86 of file runtime.c.

86 {
87 return atomic_load_bool_impl(&g_active) && (ui_controller_interactive_screen() == UI_SCREEN_STATS ||
90}
int keyboard_help_previous_interactive(void)
int ui_controller_interactive_screen(void)
@ UI_SCREEN_STATS
@ UI_SCREEN_HELP

References keyboard_help_previous_interactive(), ui_controller_interactive_screen(), UI_SCREEN_HELP, and UI_SCREEN_STATS.

Referenced by stats_runtime_toggle().

◆ stats_runtime_connection_state()

void stats_runtime_connection_state ( const char * state)

Definition at line 135 of file runtime.c.

135 {
136 if (!g_scope)
137 return;
138 mutex_lock(&g_provider_mutex);
139 snprintf(g_state, sizeof(g_state), "%s", state);
140 mutex_unlock(&g_provider_mutex);
141}

◆ stats_runtime_media()

void stats_runtime_media ( unsigned width,
unsigned height,
double position,
double duration )

Definition at line 69 of file runtime.c.

69 {
70 if (!g_scope)
71 return;
72 atomic_store_u64_impl(&g_media_width, width);
73 atomic_store_u64_impl(&g_media_height, height);
74 atomic_store_u64_impl(&g_media_position,
75 isfinite(position) && position >= 0 && position < 1e12 ? (uint64_t)(position * 1000) + 1 : 0);
76 atomic_store_u64_impl(&g_media_duration,
77 isfinite(duration) && duration > 0 && duration < 1e12 ? (uint64_t)(duration * 1000) + 1 : 0);
78}
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
unsigned long long uint64_t
Definition common.h:63

References height, and width.

Referenced by stats_runtime_start().

◆ stats_runtime_packet()

void stats_runtime_packet ( stats_peer_t * peer,
unsigned type,
size_t payload_bytes,
bool sent,
bool success )

Application packet boundary, after decryption on receive. Header bytes are included internally.

Definition at line 196 of file runtime.c.

196 {
197 if (success) {
198 ascii_otel_metric(sent ? ASCII_OTEL_METRIC_NET_TX_SIZE : ASCII_OTEL_METRIC_NET_RX_SIZE, (double)payload_bytes);
199 }
200 if (sent && type == PACKET_TYPE_ERROR_MESSAGE)
202 stats_scope_t *scopes[] = {g_scope, peer ? peer->scope : NULL};
203 for (unsigned i = 0; i < 2; ++i) {
204 if (!success) {
206 continue;
207 }
210 sizeof(packet_header_t) + payload_bytes);
214 }
215}
@ PACKET_TYPE_IMAGE_FRAME
Complete RGB image with dimensions.
Definition packet.h:385
@ PACKET_TYPE_IMAGE_FRAME_H265
H.265-encoded frame from client (HEVC/H.265 codec).
Definition packet.h:387
@ PACKET_TYPE_ASCII_FRAME
Complete ASCII frame with all metadata.
Definition packet.h:383
@ PACKET_TYPE_IMAGE_FRAME_H264
Definition packet.h:389
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:374
struct stats_scope stats_scope_t
void stats_counter_add(stats_scope_t *scope, stats_counter_id_t id, uint64_t amount)
void ascii_otel_metric(ascii_otel_metric_t metric, double value)
Definition otel.c:161
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628
stats_scope_t * scope
Definition runtime.c:49

References ascii_otel_metric(), PACKET_TYPE_ASCII_FRAME, PACKET_TYPE_ERROR_MESSAGE, PACKET_TYPE_IMAGE_FRAME, PACKET_TYPE_IMAGE_FRAME_H264, PACKET_TYPE_IMAGE_FRAME_H265, stats_peer::scope, stats_counter_add(), STATS_COUNTER_BYTES_RECEIVED, STATS_COUNTER_BYTES_SENT, STATS_COUNTER_FRAMES_RECEIVED, STATS_COUNTER_FRAMES_SENT, STATS_COUNTER_PACKETS_RECEIVED, STATS_COUNTER_PACKETS_SENT, STATS_COUNTER_RECEIVE_ERRORS, STATS_COUNTER_REQUEST_FAILURES, and STATS_COUNTER_SEND_ERRORS.

Referenced by acip_handle_acds_packet(), acip_handle_client_packet(), acip_handle_server_packet(), packet_receive_via_transport(), and packet_send_via_transportv().

◆ stats_runtime_peer_close()

void stats_runtime_peer_close ( stats_peer_t * peer)

Definition at line 181 of file runtime.c.

181 {
182 if (!peer)
183 return;
184 mutex_lock(&g_peers_mutex);
185 for (unsigned i = 0; i < STATS_PEER_CAPACITY; ++i)
186 if (g_peers[i] == peer)
187 g_peers[i] = NULL;
188 --g_peer_count;
189 stats_gauge_set(g_scope, STATS_GAUGE_CONNECTIONS_ACTIVE, g_peer_count);
190 mutex_unlock(&g_peers_mutex);
193 SAFE_FREE(peer);
194}
#define SAFE_FREE(ptr)
Definition common.h:377
void stats_scope_destroy(stats_scope_t *scope)
void stats_sampler_destroy(stats_sampler_t *sampler)
void stats_gauge_set(stats_scope_t *scope, stats_gauge_id_t id, uint64_t value)
#define STATS_PEER_CAPACITY
Definition runtime.c:10
stats_sampler_t * sampler
Definition runtime.c:50

References SAFE_FREE, stats_peer::sampler, stats_peer::scope, STATS_GAUGE_CONNECTIONS_ACTIVE, stats_gauge_set(), STATS_PEER_CAPACITY, stats_sampler_destroy(), and stats_scope_destroy().

Referenced by acip_transport_destroy(), and acip_websocket_client_transport_create().

◆ stats_runtime_peer_open()

stats_peer_t * stats_runtime_peer_open ( const char * transport)

Definition at line 152 of file runtime.c.

152 {
153 if (!g_scope)
154 return NULL;
155 stats_peer_t *peer = SAFE_CALLOC(1, sizeof(*peer), stats_peer_t *);
156 if (!peer)
157 return NULL;
158 stats_capabilities_t caps = network_capabilities();
160 if (stats_scope_create(&caps, &peer->scope) != ASCIICHAT_OK ||
161 stats_sampler_create(&config, &peer->sampler) != ASCIICHAT_OK) {
163 SAFE_FREE(peer);
164 return NULL;
165 }
166 snprintf(peer->transport, sizeof(peer->transport), "%s", transport);
167 mutex_lock(&g_peers_mutex);
168 peer->id = ++g_peer_id;
169 ++g_peer_count;
170 stats_gauge_set(g_scope, STATS_GAUGE_CONNECTIONS_ACTIVE, g_peer_count);
171 for (unsigned i = 0; i < STATS_PEER_CAPACITY; ++i) {
172 if (!g_peers[i]) {
173 g_peers[i] = peer;
174 break;
175 }
176 }
177 mutex_unlock(&g_peers_mutex);
178 return peer;
179}
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
@ ASCIICHAT_OK
Definition error_codes.h:46
#define NS_PER_SEC_INT
Definition time.h:169
#define NS_PER_MS_INT
Definition time.h:168
asciichat_error_t stats_scope_create(const stats_capabilities_t *capabilities, stats_scope_t **out_scope)
asciichat_error_t stats_sampler_create(const stats_sampler_config_t *config, stats_sampler_t **out_sampler)
struct stats_peer stats_peer_t
stats descriptor is intentionally a small, concrete record. Fields such as name, unit,...
uint64_t id
Definition runtime.c:52
char transport[16]
Definition runtime.c:51

References ASCIICHAT_OK, stats_peer::id, NS_PER_MS_INT, NS_PER_SEC_INT, SAFE_CALLOC, SAFE_FREE, stats_peer::sampler, stats_peer::scope, STATS_GAUGE_CONNECTIONS_ACTIVE, stats_gauge_set(), STATS_PEER_CAPACITY, stats_sampler_create(), stats_scope_create(), stats_scope_destroy(), and stats_peer::transport.

Referenced by acip_async_tcp_transport_create(), acip_tcp_transport_create(), acip_websocket_client_transport_create(), and acip_websocket_server_transport_create().

◆ stats_runtime_peer_scope()

stats_scope_t * stats_runtime_peer_scope ( stats_peer_t * peer)

Definition at line 83 of file runtime.c.

83 {
84 return peer ? peer->scope : NULL;
85}

References stats_peer::scope.

◆ stats_runtime_scope()

◆ stats_runtime_set_provider()

void stats_runtime_set_provider ( stats_provider_fn provider,
void * data )

Definition at line 126 of file runtime.c.

126 {
127 if (!g_scope)
128 return;
129 mutex_lock(&g_provider_mutex);
130 g_provider = provider;
131 g_provider_data = data;
132 mutex_unlock(&g_provider_mutex);
133}

Referenced by mcp_server_main().

◆ stats_runtime_start()

asciichat_error_t stats_runtime_start ( const char * mode,
unsigned interval_seconds )

Definition at line 520 of file runtime.c.

520 {
521 if (!mode)
522 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing statistics mode");
523 if (g_started)
524 return ASCIICHAT_OK;
525 bool mcp = strcmp(mode, "mcp-server") == 0;
526 stats_capabilities_t caps = network_capabilities();
527 bool mirror = strcmp(mode, "mirror") == 0, acds = strcmp(mode, "discovery-service") == 0;
528 if (mirror)
529 memset(&caps, 0, sizeof(caps));
530 if (!acds) {
531 for (int i = 0; i <= STATS_COUNTER_FRAMES_DROPPED; ++i)
532 caps.counters[i] = true;
535 GET_OPTION(audio_enabled);
536 for (int i = 0; i <= STATS_DURATION_TERMINAL_WRITE; ++i)
537 caps.durations[i] = true;
539 caps.durations[STATS_DURATION_AUDIO_MIX] = GET_OPTION(audio_enabled) && !mirror;
540 if (mirror) {
543 }
544 } else {
547 caps.counters[i] = true;
551 }
552 if (strcmp(mode, "discovery") == 0)
554 caps.gauges[STATS_GAUGE_VIDEO_QUEUE_DEPTH] = strcmp(mode, "server") == 0;
555 if (GET_OPTION(render_file)[0]) {
558 }
559 if (!mirror) {
561 caps.durations[STATS_DURATION_RTT] = !acds;
566 }
567 if (mcp) {
568 memset(&caps, 0, sizeof(caps));
570 caps.counters[i] = true;
572 caps.counters[i] = true;
577 }
578 asciichat_error_t result = stats_scope_create(&caps, &g_scope);
579 if (result != ASCIICHAT_OK)
580 return result;
583 result = stats_sampler_create(&config, &g_sampler);
584 if (result != ASCIICHAT_OK)
585 goto fail_scope;
586 if (mutex_init(&g_peers_mutex, "stats_peers") != 0) {
587 result = SET_ERRNO(ERROR_THREAD, "Cannot initialize stats peer mutex");
588 goto fail_sampler;
589 }
590 if (mutex_init(&g_provider_mutex, "stats_provider") != 0) {
591 result = SET_ERRNO(ERROR_THREAD, "Cannot initialize stats provider mutex");
592 goto fail_peers;
593 }
594 g_peer_count = g_peer_id = 0;
595 memset(g_peers, 0, sizeof(g_peers));
596 g_state[0] = 0;
597 stats_runtime_media(0, 0, -1, -1);
598 snprintf(g_mode, sizeof(g_mode), "%s", mode);
599 g_interval = interval_seconds;
600 g_fd = platform_isatty(STDOUT_FILENO) ? STDOUT_FILENO : STDERR_FILENO;
601 g_keyboard = (!mcp || !strcmp(GET_OPTION(mcp_transport), "http")) && platform_isatty(STDIN_FILENO) &&
602 platform_isatty(g_fd) && keyboard_init() == ASCIICHAT_OK;
603 atomic_store_bool_impl(&g_stop, false);
604 atomic_store_bool_impl(&g_active, false);
605 atomic_store_bool_impl(&g_onboarding_wait, false);
606 g_started = true;
607 bool server_like = strcmp(mode, "server") == 0 || strcmp(mode, "discovery-service") == 0 ||
608 (mcp && !strcmp(GET_OPTION(mcp_transport), "http"));
609 if (g_keyboard && server_like && ui_controller_start_terminal(g_fd) != ASCIICHAT_OK)
610 LOG_ERRNO_IF_SET("Cannot start terminal presentation");
611 if (platform_thread_create(&g_worker, "stats", stats_worker, NULL) == 0) {
612 atomic_store_bool_impl(&g_onboarding_wait, true);
613 bool shown = show_first_use_instructions();
616 if (state.screen == UI_SCREEN_NOTICE && state.covered)
617 break;
619 }
620 atomic_store_bool_impl(&g_onboarding_wait, false);
621 return ASCIICHAT_OK;
622 }
623 result = SET_ERRNO(ERROR_THREAD, "Cannot start stats worker");
624 g_started = false;
625 if (g_keyboard)
627 mutex_destroy(&g_provider_mutex);
628fail_peers:
629 mutex_destroy(&g_peers_mutex);
630fail_sampler:
631 stats_sampler_destroy(g_sampler);
632 g_sampler = NULL;
633fail_scope:
634 stats_scope_destroy(g_scope);
635 g_scope = NULL;
636 return result;
637}
#define SET_ERRNO(code,...)
#define LOG_ERRNO_IF_SET(message)
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_PARAM
@ ERROR_THREAD
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
asciichat_error_t keyboard_init(void)
Initialize keyboard input system.
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
void keyboard_destroy(void)
Cleanup keyboard input system and restore terminal.
bool shutdown_is_requested(void)
Check if shutdown has been requested.
Definition common.c:86
@ STATS_COUNTER_RATE_LIMIT_REJECTIONS
@ STATS_COUNTER_MIGRATION_FAILURES
@ STATS_COUNTER_MCP_HTTP_RESPONSES
@ STATS_GAUGE_PARTICIPANTS_ACTIVE
@ STATS_GAUGE_HTTP_CONNECTIONS_ACTIVE
@ STATS_GAUGE_HTTP_STREAMS_ACTIVE
@ STATS_GAUGE_AUDIO_BUFFERED_SAMPLES
@ STATS_DURATION_CONNECTION_SETUP
void ascii_otel_stats_attach(stats_scope_t *scope)
Definition otel.c:218
void stats_runtime_media(unsigned width, unsigned height, double position, double duration)
Definition runtime.c:69
bool counters[STATS_COUNTER_COUNT]
bool durations[STATS_DURATION_COUNT]
asciichat_error_t ui_controller_start_terminal(int fd)
ui_presentation_state_t ui_controller_state(void)
bool ui_controller_screen_live(ui_screen_t screen)
@ UI_SCREEN_NOTICE

References ascii_otel_stats_attach(), ASCIICHAT_OK, stats_capabilities_t::counters, stats_capabilities_t::durations, ERROR_INVALID_PARAM, ERROR_THREAD, stats_capabilities_t::gauges, GET_OPTION, keyboard_destroy(), keyboard_init(), LOG_ERRNO_IF_SET, NS_PER_MS_INT, NS_PER_SEC_INT, platform_sleep_ms(), SET_ERRNO, shutdown_is_requested(), STATS_COUNTER_AUDIO_OVERRUNS, STATS_COUNTER_AUDIO_UNDERRUNS, STATS_COUNTER_FRAMES_DECODED, STATS_COUNTER_FRAMES_DROPPED, STATS_COUNTER_FRAMES_ENCODED, STATS_COUNTER_FRAMES_ENQUEUED, STATS_COUNTER_FRAMES_RECEIVED, STATS_COUNTER_FRAMES_SENT, STATS_COUNTER_HOST_MIGRATIONS, STATS_COUNTER_HTTP_BYTES_SENT, STATS_COUNTER_HTTP_REQUESTS, STATS_COUNTER_MCP_HTTP_RESPONSES, STATS_COUNTER_MCP_REQUESTS, STATS_COUNTER_MIGRATION_FAILURES, STATS_COUNTER_QUEUE_DROPS, STATS_COUNTER_RATE_LIMIT_REJECTIONS, STATS_COUNTER_RECONNECTS, STATS_COUNTER_RECORDING_FRAMES, STATS_COUNTER_SESSION_CREATES, STATS_DURATION_AUDIO_MIX, STATS_DURATION_CONNECTION_SETUP, STATS_DURATION_DECODE, STATS_DURATION_ENCODE, STATS_DURATION_HTTP_REQUEST, STATS_DURATION_MCP_RENDER, STATS_DURATION_RECORDING, STATS_DURATION_REQUEST, STATS_DURATION_RTT, STATS_DURATION_TERMINAL_WRITE, STATS_GAUGE_AUDIO_BUFFERED_SAMPLES, STATS_GAUGE_CONNECTIONS_ACTIVE, STATS_GAUGE_HTTP_CONNECTIONS_ACTIVE, STATS_GAUGE_HTTP_STREAMS_ACTIVE, STATS_GAUGE_PARTICIPANTS_ACTIVE, STATS_GAUGE_SESSIONS_ACTIVE, STATS_GAUGE_VIDEO_QUEUE_DEPTH, stats_runtime_media(), stats_sampler_create(), stats_sampler_destroy(), stats_scope_create(), stats_scope_destroy(), ui_controller_screen_live(), ui_controller_start_terminal(), ui_controller_state(), and UI_SCREEN_NOTICE.

Referenced by main().

◆ stats_runtime_stop()

void stats_runtime_stop ( void )

Definition at line 639 of file runtime.c.

639 {
640 if (!g_started)
641 return;
642 atomic_store_bool_impl(&g_stop, true);
643 thread_join(&g_worker, NULL);
645 if (g_keyboard)
647 g_provider = NULL;
648 g_provider_data = NULL;
649 stats_sampler_destroy(g_sampler);
650 stats_scope_destroy(g_scope);
651 g_sampler = NULL;
652 g_scope = NULL;
653 mutex_destroy(&g_provider_mutex);
654 mutex_destroy(&g_peers_mutex);
655 g_started = false;
656}
void ui_controller_shutdown(void)

References keyboard_destroy(), stats_sampler_destroy(), stats_scope_destroy(), and ui_controller_shutdown().

Referenced by asciichat_shared_destroy(), and main().

◆ stats_runtime_toggle()

void stats_runtime_toggle ( void )

Definition at line 92 of file runtime.c.

92 {
93 if (g_started && g_keyboard) {
94 bool active = !stats_runtime_active();
95 atomic_store_bool_impl(&g_active, active);
97 log_debug("Statistics TUI requested: %s", active ? "open" : "closed");
98 }
99}
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
bool stats_runtime_active(void)
Definition runtime.c:86
void ui_controller_select_interactive(int screen)

References log_debug, stats_runtime_active(), ui_controller_select_interactive(), and UI_SCREEN_STATS.

◆ stats_view_add()

void stats_view_add ( stats_view_t * view,
const char * format,
... )

Definition at line 112 of file runtime.c.

112 {
113 va_list args;
114 va_start(args, format);
115 stats_view_vadd(view, false, format, args);
116 va_end(args);
117}
action_args_t args
Definition actions.c:78

References args.

◆ stats_view_add_header()

void stats_view_add_header ( stats_view_t * view,
const char * format,
... )

Definition at line 119 of file runtime.c.

119 {
120 va_list args;
121 va_start(args, format);
122 stats_view_vadd(view, true, format, args);
123 va_end(args);
124}

References args.