Protocol: - Add PROTO_CMD_START_DISPLAY (0x000A) and PROTO_CMD_STOP_DISPLAY (0x000B) with write/read functions; Proto_Start_Display carries stream_id, window position/size, scale and anchor; PROTO_DISPLAY_SCALE_*/ANCHOR_* constants Node display sink: - Display_Slot struct with wanted_state/current_state (DISP_CLOSED/DISP_OPEN); handlers set wanted state, display_loop_tick on main thread reconciles - Up to MAX_DISPLAYS (4) simultaneous viewer windows - on_frame routes incoming VIDEO_FRAME messages to matching display slot; transport thread deposits payload, main thread consumes without holding lock during JPEG decode/upload - Main thread runs GL event loop when xorg is available; headless fallback joins reconciler timer thread as before Xorg multi-window: - Ref-count glfwInit/glfwTerminate via glfw_acquire/glfw_release so closing one viewer does not terminate GLFW for remaining windows - Add glfwMakeContextCurrent before GL calls in push_yuv420, push_bgra, push_mjpeg and poll so each viewer uses its own GL context correctly Transport random port: - Bind port 0 lets the OS assign a free port; getsockname reads it back into server->bound_port after bind - Add transport_server_get_port() accessor - Default tcp_port changed from 8000 to 0 (random); node prints actual port after server start so it is always visible in output - Add --port PORT CLI override (before config-file argument) controller_cli: - Add start-display and stop-display commands Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
514 lines
17 KiB
C
514 lines
17 KiB
C
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include "error.h"
|
|
#include "transport.h"
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Message type constants
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_MSG_VIDEO_FRAME 0x0001u
|
|
#define PROTO_MSG_CONTROL_REQUEST 0x0002u
|
|
#define PROTO_MSG_CONTROL_RESPONSE 0x0003u
|
|
#define PROTO_MSG_STREAM_EVENT 0x0004u
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Command codes (carried in CONTROL_REQUEST payload offset 2)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_CMD_STREAM_OPEN 0x0001u
|
|
#define PROTO_CMD_STREAM_CLOSE 0x0002u
|
|
#define PROTO_CMD_ENUM_DEVICES 0x0003u
|
|
#define PROTO_CMD_ENUM_CONTROLS 0x0004u
|
|
#define PROTO_CMD_GET_CONTROL 0x0005u
|
|
#define PROTO_CMD_SET_CONTROL 0x0006u
|
|
#define PROTO_CMD_ENUM_MONITORS 0x0007u
|
|
#define PROTO_CMD_START_INGEST 0x0008u
|
|
#define PROTO_CMD_STOP_INGEST 0x0009u
|
|
#define PROTO_CMD_START_DISPLAY 0x000Au
|
|
#define PROTO_CMD_STOP_DISPLAY 0x000Bu
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Response status codes (carried in CONTROL_RESPONSE payload offset 2)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_STATUS_OK 0x0000u
|
|
#define PROTO_STATUS_ERROR 0x0001u
|
|
#define PROTO_STATUS_UNKNOWN_CMD 0x0002u
|
|
#define PROTO_STATUS_INVALID_PARAMS 0x0003u
|
|
#define PROTO_STATUS_NOT_FOUND 0x0004u
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Stream event codes (carried in STREAM_EVENT payload offset 2)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_EVENT_INTERRUPTED 0x01u
|
|
#define PROTO_EVENT_RESUMED 0x02u
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Codec format codes (STREAM_OPEN format field)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_FORMAT_MJPEG 0x0001u
|
|
#define PROTO_FORMAT_H264 0x0002u
|
|
#define PROTO_FORMAT_H265 0x0003u
|
|
#define PROTO_FORMAT_AV1 0x0004u
|
|
#define PROTO_FORMAT_FFV1 0x0005u
|
|
#define PROTO_FORMAT_PRORES 0x0006u
|
|
#define PROTO_FORMAT_QOI 0x0007u
|
|
#define PROTO_FORMAT_RAW 0x0008u
|
|
#define PROTO_FORMAT_RAW_ZSTD 0x0009u
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Pixel format codes (STREAM_OPEN pixel_format field; 0 for compressed)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_PIXEL_BGRA8888 0x0001u
|
|
#define PROTO_PIXEL_RGBA8888 0x0002u
|
|
#define PROTO_PIXEL_BGR888 0x0003u
|
|
#define PROTO_PIXEL_YUV420P 0x0004u
|
|
#define PROTO_PIXEL_YUV422 0x0005u
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Transport mode codes (START_INGEST transport_mode field)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_TRANSPORT_ENCAPSULATED 0x0001u /* framed: message_type + payload_length header */
|
|
#define PROTO_TRANSPORT_OPAQUE 0x0002u /* raw byte stream, no frame boundaries */
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Origin codes (STREAM_OPEN origin field; informational only)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define PROTO_ORIGIN_DEVICE_NATIVE 0x0001u
|
|
#define PROTO_ORIGIN_LIBJPEG_TURBO 0x0002u
|
|
#define PROTO_ORIGIN_FFMPEG_LIBAV 0x0003u
|
|
#define PROTO_ORIGIN_FFMPEG_PROC 0x0004u
|
|
#define PROTO_ORIGIN_VAAPI 0x0005u
|
|
#define PROTO_ORIGIN_NVENC 0x0006u
|
|
#define PROTO_ORIGIN_SOFTWARE 0x0007u
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Structs used by write functions (variable-length response payloads)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
struct Proto_Menu_Item {
|
|
uint32_t index;
|
|
const char *name;
|
|
int64_t int_value;
|
|
};
|
|
|
|
struct Proto_Control_Info {
|
|
uint32_t id;
|
|
uint8_t type;
|
|
uint32_t flags;
|
|
const char *name;
|
|
int32_t min, max, step, default_val, current_val;
|
|
uint8_t menu_count;
|
|
const struct Proto_Menu_Item *menu_items;
|
|
};
|
|
|
|
/*
|
|
* A video node associated with a media controller device.
|
|
* entity_type and entity_flags are MEDIA_ENT_F_* / MEDIA_ENT_FL_* values.
|
|
* pad_flags uses MEDIA_PAD_FLAG_SOURCE / MEDIA_PAD_FLAG_SINK.
|
|
* is_capture: 1 if this node is the primary video capture output.
|
|
*/
|
|
struct Proto_Video_Node_Info {
|
|
const char *path;
|
|
const char *entity_name;
|
|
uint32_t entity_type;
|
|
uint32_t entity_flags;
|
|
uint32_t device_caps; /* V4L2_CAP_* bits from VIDIOC_QUERYCAP */
|
|
uint8_t pad_flags;
|
|
uint8_t is_capture;
|
|
};
|
|
|
|
/*
|
|
* A media controller device and its associated video nodes.
|
|
* video_node_count must be <= 255.
|
|
*/
|
|
struct Proto_Media_Device_Info {
|
|
const char *path;
|
|
const char *driver;
|
|
const char *model;
|
|
const char *bus_info;
|
|
uint8_t video_node_count;
|
|
const struct Proto_Video_Node_Info *video_nodes;
|
|
};
|
|
|
|
/*
|
|
* A standalone V4L2 device with no associated media controller.
|
|
* name is the card name from VIDIOC_QUERYCAP.
|
|
*/
|
|
struct Proto_Standalone_Device_Info {
|
|
const char *path;
|
|
const char *name;
|
|
};
|
|
|
|
struct Proto_Monitor_Info {
|
|
int32_t x, y;
|
|
uint32_t width, height;
|
|
const char *name;
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Structs used by read functions
|
|
* Fields with pointer types point INTO the caller's payload buffer.
|
|
* The caller must keep the payload alive while using those pointers.
|
|
* Strings are NOT NUL-terminated.
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
struct Proto_Video_Frame {
|
|
uint16_t stream_id;
|
|
const uint8_t *data;
|
|
uint32_t data_len;
|
|
};
|
|
|
|
struct Proto_Stream_Event {
|
|
uint16_t stream_id;
|
|
uint8_t event_code;
|
|
};
|
|
|
|
struct Proto_Request_Header {
|
|
uint16_t request_id;
|
|
uint16_t command;
|
|
};
|
|
|
|
struct Proto_Stream_Open {
|
|
uint16_t request_id;
|
|
uint16_t stream_id;
|
|
uint16_t format;
|
|
uint16_t pixel_format;
|
|
uint16_t origin;
|
|
};
|
|
|
|
struct Proto_Stream_Close {
|
|
uint16_t request_id;
|
|
uint16_t stream_id;
|
|
};
|
|
|
|
struct Proto_Enum_Controls_Req {
|
|
uint16_t request_id;
|
|
uint16_t device_index;
|
|
};
|
|
|
|
struct Proto_Get_Control_Req {
|
|
uint16_t request_id;
|
|
uint16_t device_index;
|
|
uint32_t control_id;
|
|
};
|
|
|
|
struct Proto_Set_Control_Req {
|
|
uint16_t request_id;
|
|
uint16_t device_index;
|
|
uint32_t control_id;
|
|
int32_t value;
|
|
};
|
|
|
|
/*
|
|
* START_INGEST: controller tells a source node to open a V4L2 device and
|
|
* connect outbound to a sink at dest_host:dest_port.
|
|
* format/width/height/fps_n/fps_d of 0 mean auto-select.
|
|
* Strings point into the caller's payload buffer; not NUL-terminated.
|
|
*/
|
|
struct Proto_Start_Ingest {
|
|
uint16_t request_id;
|
|
uint16_t stream_id;
|
|
uint16_t format; /* PROTO_FORMAT_* code; 0 = auto (best MJPEG) */
|
|
uint16_t width; /* 0 = auto */
|
|
uint16_t height; /* 0 = auto */
|
|
uint16_t fps_n; /* 0 = auto */
|
|
uint16_t fps_d;
|
|
uint16_t dest_port;
|
|
uint16_t transport_mode; /* PROTO_TRANSPORT_ENCAPSULATED or PROTO_TRANSPORT_OPAQUE */
|
|
const char *device_path;
|
|
uint8_t device_path_len;
|
|
const char *dest_host;
|
|
uint8_t dest_host_len;
|
|
};
|
|
|
|
struct Proto_Stop_Ingest {
|
|
uint16_t request_id;
|
|
uint16_t stream_id;
|
|
};
|
|
|
|
/*
|
|
* START_DISPLAY: controller tells a sink node to open a viewer window and
|
|
* display incoming VIDEO_FRAME messages for the given stream_id.
|
|
* win_x/win_y are screen-space window position (signed: multi-monitor).
|
|
* win_w/win_h of 0 mean use a default size.
|
|
* scale: 0=stretch 1=fit 2=fill 3=1:1 (PROTO_DISPLAY_SCALE_*)
|
|
* anchor: 0=center 1=topleft (PROTO_DISPLAY_ANCHOR_*)
|
|
*/
|
|
struct Proto_Start_Display {
|
|
uint16_t request_id;
|
|
uint16_t stream_id;
|
|
int16_t win_x;
|
|
int16_t win_y;
|
|
uint16_t win_w;
|
|
uint16_t win_h;
|
|
uint8_t scale;
|
|
uint8_t anchor;
|
|
};
|
|
|
|
struct Proto_Stop_Display {
|
|
uint16_t request_id;
|
|
uint16_t stream_id;
|
|
};
|
|
|
|
/* Scale/anchor constants for Proto_Start_Display */
|
|
#define PROTO_DISPLAY_SCALE_STRETCH 0u
|
|
#define PROTO_DISPLAY_SCALE_FIT 1u
|
|
#define PROTO_DISPLAY_SCALE_FILL 2u
|
|
#define PROTO_DISPLAY_SCALE_1_1 3u
|
|
|
|
#define PROTO_DISPLAY_ANCHOR_CENTER 0u
|
|
#define PROTO_DISPLAY_ANCHOR_TOPLEFT 1u
|
|
|
|
struct Proto_Response_Header {
|
|
uint16_t request_id;
|
|
uint16_t status;
|
|
};
|
|
|
|
struct Proto_Get_Control_Resp {
|
|
uint16_t request_id;
|
|
uint16_t status;
|
|
int32_t value;
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Write functions — serialize and send via transport_send_frame.
|
|
* All return APP_OK or an error from the transport layer.
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* VIDEO_FRAME: prepends stream_id (2 bytes) to data and sends.
|
|
* data/data_len is the compressed frame; the stream must already be open.
|
|
*/
|
|
struct App_Error proto_write_video_frame(struct Transport_Conn *conn,
|
|
uint16_t stream_id, const uint8_t *data, uint32_t data_len);
|
|
|
|
/* STREAM_EVENT (3 bytes) */
|
|
struct App_Error proto_write_stream_event(struct Transport_Conn *conn,
|
|
uint16_t stream_id, uint8_t event_code);
|
|
|
|
/* CONTROL_REQUEST: STREAM_OPEN (12 bytes) */
|
|
struct App_Error proto_write_stream_open(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t stream_id,
|
|
uint16_t format, uint16_t pixel_format, uint16_t origin);
|
|
|
|
/* CONTROL_REQUEST: STREAM_CLOSE (6 bytes) */
|
|
struct App_Error proto_write_stream_close(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t stream_id);
|
|
|
|
/* CONTROL_REQUEST: ENUM_DEVICES (4 bytes, no extra fields) */
|
|
struct App_Error proto_write_enum_devices(struct Transport_Conn *conn,
|
|
uint16_t request_id);
|
|
|
|
/* CONTROL_REQUEST: ENUM_CONTROLS (6 bytes) */
|
|
struct App_Error proto_write_enum_controls(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t device_index);
|
|
|
|
/* CONTROL_REQUEST: GET_CONTROL (10 bytes) */
|
|
struct App_Error proto_write_get_control(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t device_index, uint32_t control_id);
|
|
|
|
/* CONTROL_REQUEST: SET_CONTROL (14 bytes) */
|
|
struct App_Error proto_write_set_control(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t device_index,
|
|
uint32_t control_id, int32_t value);
|
|
|
|
/* CONTROL_REQUEST: ENUM_MONITORS (4 bytes, no extra fields) */
|
|
struct App_Error proto_write_enum_monitors(struct Transport_Conn *conn,
|
|
uint16_t request_id);
|
|
|
|
/* CONTROL_REQUEST: START_INGEST */
|
|
struct App_Error proto_write_start_ingest(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t stream_id,
|
|
uint16_t format, uint16_t width, uint16_t height,
|
|
uint16_t fps_n, uint16_t fps_d,
|
|
uint16_t transport_mode,
|
|
const char *device_path, const char *dest_host, uint16_t dest_port);
|
|
|
|
/* CONTROL_REQUEST: STOP_INGEST */
|
|
struct App_Error proto_write_stop_ingest(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t stream_id);
|
|
|
|
/* CONTROL_REQUEST: START_DISPLAY */
|
|
struct App_Error proto_write_start_display(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t stream_id,
|
|
int16_t win_x, int16_t win_y, uint16_t win_w, uint16_t win_h,
|
|
uint8_t scale, uint8_t anchor);
|
|
|
|
/* CONTROL_REQUEST: STOP_DISPLAY */
|
|
struct App_Error proto_write_stop_display(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t stream_id);
|
|
|
|
/*
|
|
* CONTROL_RESPONSE: generic.
|
|
* payload/payload_len are the command-specific bytes after request_id+status.
|
|
* Pass payload=NULL, payload_len=0 for responses with no extra fields
|
|
* (e.g. STREAM_OPEN ok, STREAM_CLOSE, SET_CONTROL).
|
|
*/
|
|
struct App_Error proto_write_control_response(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t status,
|
|
const uint8_t *payload, uint32_t payload_len);
|
|
|
|
/* CONTROL_RESPONSE: ENUM_DEVICES */
|
|
struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t status,
|
|
const struct Proto_Media_Device_Info *media_devices, uint16_t media_count,
|
|
const struct Proto_Standalone_Device_Info *standalone, uint16_t standalone_count);
|
|
|
|
/* CONTROL_RESPONSE: ENUM_CONTROLS */
|
|
struct App_Error proto_write_enum_controls_response(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t status,
|
|
const struct Proto_Control_Info *controls, uint16_t count);
|
|
|
|
/* CONTROL_RESPONSE: GET_CONTROL */
|
|
struct App_Error proto_write_get_control_response(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t status, int32_t value);
|
|
|
|
/* CONTROL_RESPONSE: ENUM_MONITORS */
|
|
struct App_Error proto_write_enum_monitors_response(struct Transport_Conn *conn,
|
|
uint16_t request_id, uint16_t status,
|
|
const struct Proto_Monitor_Info *monitors, uint16_t count);
|
|
|
|
/* -------------------------------------------------------------------------
|
|
* Read functions — parse raw payload bytes into typed structs.
|
|
* All return APP_INVALID_ERROR_MSG(0, ...) on malformed payloads.
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
struct App_Error proto_read_video_frame(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Video_Frame *out);
|
|
|
|
struct App_Error proto_read_stream_event(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Stream_Event *out);
|
|
|
|
/*
|
|
* Read the common 4-byte request header (request_id + command).
|
|
* Dispatch on header.command, then call the appropriate specific reader.
|
|
* ENUM_DEVICES and ENUM_MONITORS have no extra fields beyond the header.
|
|
*/
|
|
struct App_Error proto_read_request_header(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Request_Header *out);
|
|
|
|
struct App_Error proto_read_stream_open(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Stream_Open *out);
|
|
|
|
struct App_Error proto_read_stream_close(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Stream_Close *out);
|
|
|
|
struct App_Error proto_read_enum_controls_req(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Enum_Controls_Req *out);
|
|
|
|
struct App_Error proto_read_get_control_req(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Get_Control_Req *out);
|
|
|
|
struct App_Error proto_read_set_control_req(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Set_Control_Req *out);
|
|
|
|
struct App_Error proto_read_start_ingest(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Start_Ingest *out);
|
|
|
|
struct App_Error proto_read_stop_ingest(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Stop_Ingest *out);
|
|
|
|
struct App_Error proto_read_start_display(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Start_Display *out);
|
|
|
|
struct App_Error proto_read_stop_display(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Stop_Display *out);
|
|
|
|
/*
|
|
* Read the common 4-byte response header (request_id + status).
|
|
* For responses with no extra fields (STREAM_OPEN, STREAM_CLOSE, SET_CONTROL),
|
|
* this is the complete parse.
|
|
*/
|
|
struct App_Error proto_read_response_header(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Response_Header *out);
|
|
|
|
struct App_Error proto_read_get_control_response(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Get_Control_Resp *out);
|
|
|
|
/*
|
|
* Variable-length response readers use callbacks to avoid heap allocation.
|
|
* Strings point into the payload and are NOT NUL-terminated; use *_len.
|
|
*/
|
|
/*
|
|
* on_media_device is called once per media controller device.
|
|
* on_video_node is called video_node_count times immediately after,
|
|
* once per video node belonging to that media device.
|
|
* on_standalone is called once per V4L2 device with no media controller.
|
|
* Any callback may be NULL.
|
|
*/
|
|
struct App_Error proto_read_enum_devices_response(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Response_Header *header_out,
|
|
void (*on_media_device)(
|
|
const char *path, uint8_t path_len,
|
|
const char *driver, uint8_t driver_len,
|
|
const char *model, uint8_t model_len,
|
|
const char *bus_info, uint8_t bus_info_len,
|
|
uint8_t video_node_count,
|
|
void *userdata),
|
|
void (*on_video_node)(
|
|
const char *path, uint8_t path_len,
|
|
const char *entity_name, uint8_t entity_name_len,
|
|
uint32_t entity_type, uint32_t entity_flags,
|
|
uint32_t device_caps,
|
|
uint8_t pad_flags, uint8_t is_capture,
|
|
void *userdata),
|
|
void (*on_standalone)(
|
|
const char *path, uint8_t path_len,
|
|
const char *name, uint8_t name_len,
|
|
void *userdata),
|
|
void *userdata);
|
|
|
|
/*
|
|
* on_control is called once per control.
|
|
* on_menu_item is called once per menu item immediately after its on_control
|
|
* call; menu_count in on_control says how many to expect.
|
|
* on_menu_item may be NULL if the caller does not need menu items.
|
|
*/
|
|
struct App_Error proto_read_enum_controls_response(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Response_Header *header_out,
|
|
void (*on_control)(
|
|
uint32_t id, uint8_t type, uint32_t flags,
|
|
const char *name, uint8_t name_len,
|
|
int32_t min, int32_t max, int32_t step,
|
|
int32_t default_val, int32_t current_val,
|
|
uint8_t menu_count, void *userdata),
|
|
void (*on_menu_item)(
|
|
uint32_t index,
|
|
const char *name, uint8_t name_len,
|
|
int64_t int_value,
|
|
void *userdata),
|
|
void *userdata);
|
|
|
|
struct App_Error proto_read_enum_monitors_response(
|
|
const uint8_t *payload, uint32_t length,
|
|
struct Proto_Response_Header *header_out,
|
|
void (*on_monitor)(
|
|
int32_t x, int32_t y, uint32_t width, uint32_t height,
|
|
const char *name, uint8_t name_len,
|
|
void *userdata),
|
|
void *userdata);
|