Fix connect accumulation; add display sinks to enum-devices
- controller_cli: drain semaphore and reset pending_cmd in do_connect so stale posts from old connection don't unblock the next command - protocol: add Proto_Display_Device_Info; extend proto_write_enum_devices_response and proto_read_enum_devices_response with display section; backward-compatible (absent in older messages) - node: handle_enum_devices snapshots active Display_Slots under mutex and includes them in the response - controller_cli: on_display callback prints display window info in enum-devices output - query_cli: updated to pass NULL on_display (no display interest) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,31 @@ static void on_standalone(
|
|||||||
(int)name_len, name);
|
(int)name_len, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *scale_name(uint8_t s)
|
||||||
|
{
|
||||||
|
switch (s) {
|
||||||
|
case 0: return "stretch";
|
||||||
|
case 1: return "fit";
|
||||||
|
case 2: return "fill";
|
||||||
|
case 3: return "1:1";
|
||||||
|
default: return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_display(
|
||||||
|
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,
|
||||||
|
void *ud)
|
||||||
|
{
|
||||||
|
(void)ud;
|
||||||
|
printf(" display stream=%u pos=%d,%d size=%ux%u scale=%s anchor=%s\n",
|
||||||
|
stream_id, win_x, win_y, win_w, win_h,
|
||||||
|
scale_name(scale),
|
||||||
|
anchor == 0 ? "center" : "topleft");
|
||||||
|
}
|
||||||
|
|
||||||
static void on_control(
|
static void on_control(
|
||||||
uint32_t id, uint8_t type, uint32_t flags,
|
uint32_t id, uint8_t type, uint32_t flags,
|
||||||
const char *name, uint8_t name_len,
|
const char *name, uint8_t name_len,
|
||||||
@@ -208,7 +233,7 @@ static void on_frame(struct Transport_Conn *conn,
|
|||||||
struct Proto_Response_Header hdr;
|
struct Proto_Response_Header hdr;
|
||||||
struct App_Error e = proto_read_enum_devices_response(
|
struct App_Error e = proto_read_enum_devices_response(
|
||||||
frame->payload, frame->payload_length, &hdr,
|
frame->payload, frame->payload_length, &hdr,
|
||||||
on_media_device, on_video_node, on_standalone, NULL);
|
on_media_device, on_video_node, on_standalone, on_display, NULL);
|
||||||
if (!APP_IS_OK(e)) { app_error_print(&e); }
|
if (!APP_IS_OK(e)) { app_error_print(&e); }
|
||||||
else if (hdr.status != PROTO_STATUS_OK) {
|
else if (hdr.status != PROTO_STATUS_OK) {
|
||||||
fprintf(stderr, "ENUM_DEVICES: status=%u\n", hdr.status);
|
fprintf(stderr, "ENUM_DEVICES: status=%u\n", hdr.status);
|
||||||
@@ -452,6 +477,9 @@ static struct Transport_Conn *do_connect(struct Ctrl_State *cs,
|
|||||||
struct Transport_Conn *old_conn)
|
struct Transport_Conn *old_conn)
|
||||||
{
|
{
|
||||||
if (old_conn) { transport_conn_close(old_conn); }
|
if (old_conn) { transport_conn_close(old_conn); }
|
||||||
|
/* Reset state — drain stale semaphore posts from the old connection */
|
||||||
|
cs->pending_cmd = 0;
|
||||||
|
while (sem_trywait(&cs->sem) == 0) { /* drain */ }
|
||||||
struct Transport_Conn *conn;
|
struct Transport_Conn *conn;
|
||||||
struct App_Error e = transport_connect(&conn, host, port,
|
struct App_Error e = transport_connect(&conn, host, port,
|
||||||
TRANSPORT_DEFAULT_MAX_PAYLOAD, on_frame, on_disconnect, cs);
|
TRANSPORT_DEFAULT_MAX_PAYLOAD, on_frame, on_disconnect, cs);
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ static void on_frame(struct Transport_Conn *conn,
|
|||||||
struct Proto_Response_Header hdr;
|
struct Proto_Response_Header hdr;
|
||||||
struct App_Error e = proto_read_enum_devices_response(
|
struct App_Error e = proto_read_enum_devices_response(
|
||||||
frame->payload, frame->payload_length, &hdr,
|
frame->payload, frame->payload_length, &hdr,
|
||||||
on_media_device, on_video_node, on_standalone, NULL);
|
on_media_device, on_video_node, on_standalone, NULL, NULL);
|
||||||
if (!APP_IS_OK(e)) { app_error_print(&e); }
|
if (!APP_IS_OK(e)) { app_error_print(&e); }
|
||||||
else if (hdr.status != PROTO_STATUS_OK) {
|
else if (hdr.status != PROTO_STATUS_OK) {
|
||||||
fprintf(stderr, "ENUM_DEVICES failed: status=%u\n", hdr.status);
|
fprintf(stderr, "ENUM_DEVICES failed: status=%u\n", hdr.status);
|
||||||
|
|||||||
@@ -147,6 +147,18 @@ struct Proto_Standalone_Device_Info {
|
|||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An active display window (video sink role).
|
||||||
|
* stream_id is the stream being displayed; win_* are current geometry.
|
||||||
|
*/
|
||||||
|
struct Proto_Display_Device_Info {
|
||||||
|
uint16_t stream_id;
|
||||||
|
int16_t win_x, win_y;
|
||||||
|
uint16_t win_w, win_h;
|
||||||
|
uint8_t scale;
|
||||||
|
uint8_t anchor;
|
||||||
|
};
|
||||||
|
|
||||||
struct Proto_Monitor_Info {
|
struct Proto_Monitor_Info {
|
||||||
int32_t x, y;
|
int32_t x, y;
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
@@ -362,7 +374,8 @@ struct App_Error proto_write_control_response(struct Transport_Conn *conn,
|
|||||||
struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn,
|
struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn,
|
||||||
uint16_t request_id, uint16_t status,
|
uint16_t request_id, uint16_t status,
|
||||||
const struct Proto_Media_Device_Info *media_devices, uint16_t media_count,
|
const struct Proto_Media_Device_Info *media_devices, uint16_t media_count,
|
||||||
const struct Proto_Standalone_Device_Info *standalone, uint16_t standalone_count);
|
const struct Proto_Standalone_Device_Info *standalone, uint16_t standalone_count,
|
||||||
|
const struct Proto_Display_Device_Info *displays, uint16_t display_count);
|
||||||
|
|
||||||
/* CONTROL_RESPONSE: ENUM_CONTROLS */
|
/* CONTROL_RESPONSE: ENUM_CONTROLS */
|
||||||
struct App_Error proto_write_enum_controls_response(struct Transport_Conn *conn,
|
struct App_Error proto_write_enum_controls_response(struct Transport_Conn *conn,
|
||||||
@@ -481,6 +494,12 @@ struct App_Error proto_read_enum_devices_response(
|
|||||||
const char *path, uint8_t path_len,
|
const char *path, uint8_t path_len,
|
||||||
const char *name, uint8_t name_len,
|
const char *name, uint8_t name_len,
|
||||||
void *userdata),
|
void *userdata),
|
||||||
|
void (*on_display)(
|
||||||
|
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,
|
||||||
|
void *userdata),
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -51,6 +51,14 @@ static struct App_Error wbuf_u16(struct Wbuf *b, uint16_t v) {
|
|||||||
return APP_OK;
|
return APP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct App_Error wbuf_i16(struct Wbuf *b, int16_t v) {
|
||||||
|
struct App_Error e = wbuf_grow(b, 2);
|
||||||
|
if (!APP_IS_OK(e)) { return e; }
|
||||||
|
put_i16(b->data, b->len, v);
|
||||||
|
b->len += 2;
|
||||||
|
return APP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static struct App_Error wbuf_u32(struct Wbuf *b, uint32_t v) {
|
static struct App_Error wbuf_u32(struct Wbuf *b, uint32_t v) {
|
||||||
struct App_Error e = wbuf_grow(b, 4);
|
struct App_Error e = wbuf_grow(b, 4);
|
||||||
if (!APP_IS_OK(e)) { return e; }
|
if (!APP_IS_OK(e)) { return e; }
|
||||||
@@ -366,7 +374,8 @@ struct App_Error proto_write_get_control_response(struct Transport_Conn *conn,
|
|||||||
struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn,
|
struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn,
|
||||||
uint16_t request_id, uint16_t status,
|
uint16_t request_id, uint16_t status,
|
||||||
const struct Proto_Media_Device_Info *media_devices, uint16_t media_count,
|
const struct Proto_Media_Device_Info *media_devices, uint16_t media_count,
|
||||||
const struct Proto_Standalone_Device_Info *standalone, uint16_t standalone_count)
|
const struct Proto_Standalone_Device_Info *standalone, uint16_t standalone_count,
|
||||||
|
const struct Proto_Display_Device_Info *displays, uint16_t display_count)
|
||||||
{
|
{
|
||||||
struct Wbuf b;
|
struct Wbuf b;
|
||||||
struct App_Error e = wbuf_init(&b, 128);
|
struct App_Error e = wbuf_init(&b, 128);
|
||||||
@@ -402,6 +411,18 @@ struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn,
|
|||||||
e = wbuf_str8(&b, standalone[i].name); if (!APP_IS_OK(e)) { goto fail; }
|
e = wbuf_str8(&b, standalone[i].name); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e = wbuf_u16(&b, display_count); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
for (uint16_t i = 0; i < display_count; i++) {
|
||||||
|
const struct Proto_Display_Device_Info *d = &displays[i];
|
||||||
|
e = wbuf_u16(&b, d->stream_id); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
e = wbuf_i16(&b, d->win_x); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
e = wbuf_i16(&b, d->win_y); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
e = wbuf_u16(&b, d->win_w); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
e = wbuf_u16(&b, d->win_h); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
e = wbuf_u8 (&b, d->scale); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
e = wbuf_u8 (&b, d->anchor); if (!APP_IS_OK(e)) { goto fail; }
|
||||||
|
}
|
||||||
|
|
||||||
e = transport_send_frame(conn, PROTO_MSG_CONTROL_RESPONSE, b.data, b.len);
|
e = transport_send_frame(conn, PROTO_MSG_CONTROL_RESPONSE, b.data, b.len);
|
||||||
fail:
|
fail:
|
||||||
wbuf_free(&b);
|
wbuf_free(&b);
|
||||||
@@ -705,6 +726,12 @@ struct App_Error proto_read_enum_devices_response(
|
|||||||
const char *path, uint8_t path_len,
|
const char *path, uint8_t path_len,
|
||||||
const char *name, uint8_t name_len,
|
const char *name, uint8_t name_len,
|
||||||
void *userdata),
|
void *userdata),
|
||||||
|
void (*on_display)(
|
||||||
|
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,
|
||||||
|
void *userdata),
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct Cursor c;
|
struct Cursor c;
|
||||||
@@ -759,6 +786,26 @@ struct App_Error proto_read_enum_devices_response(
|
|||||||
if (on_standalone) { on_standalone(path, path_len, name, name_len, userdata); }
|
if (on_standalone) { on_standalone(path, path_len, name, name_len, userdata); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Display section — optional; absent in messages from older nodes */
|
||||||
|
if (c.ok && c.pos + 2 <= c.len) {
|
||||||
|
uint16_t display_count = cur_u16(&c);
|
||||||
|
CUR_CHECK(c);
|
||||||
|
for (uint16_t i = 0; i < display_count; i++) {
|
||||||
|
uint16_t stream_id = cur_u16(&c);
|
||||||
|
int16_t win_x = (int16_t)cur_u16(&c);
|
||||||
|
int16_t win_y = (int16_t)cur_u16(&c);
|
||||||
|
uint16_t win_w = cur_u16(&c);
|
||||||
|
uint16_t win_h = cur_u16(&c);
|
||||||
|
uint8_t scale = cur_u8(&c);
|
||||||
|
uint8_t anchor = cur_u8(&c);
|
||||||
|
CUR_CHECK(c);
|
||||||
|
if (on_display) {
|
||||||
|
on_display(stream_id, win_x, win_y,
|
||||||
|
win_w, win_h, scale, anchor, userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return APP_OK;
|
return APP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -829,10 +829,31 @@ static void handle_enum_devices(struct Node *node,
|
|||||||
standalone_count++;
|
standalone_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Proto_Display_Device_Info disp_infos[MAX_DISPLAYS];
|
||||||
|
int disp_count = 0;
|
||||||
|
for (int i = 0; i < MAX_DISPLAYS; i++) {
|
||||||
|
struct Display_Slot *d = &node->displays[i];
|
||||||
|
pthread_mutex_lock(&d->mutex);
|
||||||
|
int snap = d->allocated && d->wanted_state == DISP_OPEN;
|
||||||
|
struct Proto_Display_Device_Info info = {
|
||||||
|
.stream_id = d->stream_id,
|
||||||
|
.win_x = (int16_t)d->win_x,
|
||||||
|
.win_y = (int16_t)d->win_y,
|
||||||
|
.win_w = (uint16_t)d->win_w,
|
||||||
|
.win_h = (uint16_t)d->win_h,
|
||||||
|
.scale = (uint8_t)d->scale,
|
||||||
|
.anchor = (uint8_t)d->anchor,
|
||||||
|
};
|
||||||
|
pthread_mutex_unlock(&d->mutex);
|
||||||
|
if (!snap) { continue; }
|
||||||
|
disp_infos[disp_count++] = info;
|
||||||
|
}
|
||||||
|
|
||||||
struct App_Error e = proto_write_enum_devices_response(conn,
|
struct App_Error e = proto_write_enum_devices_response(conn,
|
||||||
request_id, PROTO_STATUS_OK,
|
request_id, PROTO_STATUS_OK,
|
||||||
mdevs, (uint16_t)node->devices.media_count,
|
mdevs, (uint16_t)node->devices.media_count,
|
||||||
standalone, (uint16_t)standalone_count);
|
standalone, (uint16_t)standalone_count,
|
||||||
|
disp_infos, (uint16_t)disp_count);
|
||||||
if (!APP_IS_OK(e)) { app_error_print(&e); }
|
if (!APP_IS_OK(e)) { app_error_print(&e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user