Browse Source

Acknowledge video capabilities before sending frame data

master
evgeny 5 days ago
parent
commit
b466ec30e3
  1. 6
      src/Makefile.am
  2. 42
      src/call/call_video_transport.c

6
src/Makefile.am

@ -187,6 +187,9 @@ utun_CORE_SOURCES = \
call/call_video_rate.h \
call/call_video.c \
call/call_video.h \
call/call_video_transport.c \
call/call_video_transport.h \
call/call_priv.h \
call/call_headless.c \
radio/radio.c \
radio/radio_headless.c \
@ -342,6 +345,9 @@ libutun_a_SOURCES = \
call/call_video_rate.h \
call/call_video.c \
call/call_video.h \
call/call_video_transport.c \
call/call_video_transport.h \
call/call_priv.h \
call/call_headless.c \
radio/radio.c \
radio/radio_headless.c \

42
src/call/call_video_transport.c

@ -8,7 +8,7 @@
#include "../../lib/debug_config.h"
#include <string.h>
enum { VIDEO_CAPS = 1, VIDEO_KEY_REQUEST = 2 };
enum { VIDEO_CAPS = 1, VIDEO_KEY_REQUEST = 2, VIDEO_CAPS_ACK = 3 };
struct call_video_transport {
struct call_session *session;
struct call_video_caps local, peer;
@ -18,6 +18,7 @@ struct call_video_transport {
struct call_video_frame tx;
uint8_t *data;
uint64_t tx_started_tb, tx_last_id, key_request_tb;
uint64_t local_revision, peer_revision, acknowledged_revision;
int64_t audio_end_pts, tx_last_pts;
int have_peer, need_key;
};
@ -43,10 +44,12 @@ static struct call_video_transport *ensure(struct call_session *s) {
}
static int control_send(struct call_video_transport *v, uint8_t type) {
struct call_session *s = v->session;
uint8_t data[9 + CALL_VIDEO_CAPS_BYTES]; data[0] = type; memcpy(data + 1, &s->call_id, 8);
size_t length = 9;
uint8_t data[17 + CALL_VIDEO_CAPS_BYTES]; data[0] = type; memcpy(data + 1, &s->call_id, 8);
uint64_t revision = type == VIDEO_CAPS ? v->local_revision : type == VIDEO_CAPS_ACK ? v->peer_revision : 0;
memcpy(data + 9, &revision, 8);
size_t length = 17;
if (type == VIDEO_CAPS) {
if (call_video_caps_encode(&v->local, data + 9)) return -1;
if (call_video_caps_encode(&v->local, data + 17)) return -1;
length += CALL_VIDEO_CAPS_BYTES;
}
struct ETCP_ROUTER_CONN *conn = etcp_router_conn_get(s->ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_VIDEO_CONTROL);
@ -65,6 +68,7 @@ static void flush(struct call_video_transport *v) {
if (!v->data) return;
struct call_session *s = v->session;
if (get_time_tb() - v->tx_started_tb > 20000) { discard_tx(v, "deadline"); return; }
if (v->acknowledged_revision != v->local_revision) return;
// Видео не обгоняет соответствующий аудиокадр. Отказ камеры не задерживает звук.
if (v->tx.pts_us > v->audio_end_pts) return;
struct ETCP_ROUTER_CONN *conn = etcp_router_conn_get(s->ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_VIDEO);
@ -113,6 +117,9 @@ int call_video_configure(struct UTUN_INSTANCE *inst, uint64_t id, const struct c
struct call_video_transport *v = ensure(s);
if (!v) return -1;
v->local = *caps; v->ops = ops ? *ops : (struct call_video_ops){0}; v->arg = arg;
if (++v->local_revision == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video capabilities revision exhausted"); return -1;
}
if (!ops) {
memset(&v->local, 0, sizeof(v->local));
if (v->data) discard_tx(v, "platform_detached");
@ -132,7 +139,8 @@ int call_video_send_frame(struct UTUN_INSTANCE *inst, const struct call_video_fr
|| (f->flags & ~CALL_VIDEO_KEY) || f->frame_id <= v->tx_last_id || f->pts_us <= v->tx_last_pts) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "video TX invalid frame/session"); return -1;
}
if (!v->have_peer || call_video_choose(&v->local, &v->peer, f->format.codec, f->format.width, f->format.height, f->format.fps)
if (!v->have_peer || v->acknowledged_revision != v->local_revision) { v->need_key = 1; return 0; }
if (call_video_choose(&v->local, &v->peer, f->format.codec, f->format.width, f->format.height, f->format.fps)
!= f->format.codec) { DEBUG_WARN(DEBUG_CATEGORY_CALL, "video TX unsupported peer format"); return -1; }
if (v->data) { v->need_key = 1; return 0; }
int changed = !call_video_same_format(&f->format, &v->tx.format);
@ -165,6 +173,8 @@ static int ready(struct UTUN_INSTANCE *inst, uint64_t group, uint64_t peer, cons
struct call_session *s = active(inst, f.call_id);
struct call_video_transport *v = s ? s->video : NULL;
if (!v || s->group_id != group || s->peer_node_id != peer || !v->ops.frame || f.offset) return 1;
if (!v->have_peer || call_video_choose(&v->peer, &v->local, f.format.codec, f.format.width, f.format.height, f.format.fps)
!= f.format.codec) return 1;
return v->ops.receive_ready(v->arg, f.size);
}
static void receive(struct ETCP_CONN *conn, struct ll_entry *entry) {
@ -179,7 +189,7 @@ static void receive(struct ETCP_CONN *conn, struct ll_entry *entry) {
int control = entry->dgram[0] == ETCP_RT_ID_CALL_VIDEO_CONTROL;
struct call_video_frame f;
if (control) {
if (length != 9 && length != 9 + CALL_VIDEO_CAPS_BYTES) goto invalid;
if (length != 17 && length != 17 + CALL_VIDEO_CAPS_BYTES) goto invalid;
memcpy(&id, data + 1, 8);
} else {
if (call_video_fragment_parse(data, length, &f)) goto done;
@ -191,14 +201,25 @@ static void receive(struct ETCP_CONN *conn, struct ll_entry *entry) {
struct call_video_transport *v = ensure(s);
if (!v) goto done;
if (control) {
if (data[0] == VIDEO_CAPS && length == 9 + CALL_VIDEO_CAPS_BYTES) {
uint64_t revision; memcpy(&revision, data + 9, 8);
if (data[0] == VIDEO_CAPS && length == 17 + CALL_VIDEO_CAPS_BYTES && revision) {
struct call_video_caps caps;
if (call_video_caps_parse(data + 9, CALL_VIDEO_CAPS_BYTES, &caps)) goto done;
if (call_video_caps_parse(data + 17, CALL_VIDEO_CAPS_BYTES, &caps)) goto done;
if (revision <= v->peer_revision) {
if (revision == v->peer_revision) control_send(v, VIDEO_CAPS_ACK);
goto done;
}
v->peer_revision = revision;
v->peer = caps; v->have_peer = 1;
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video peer capabilities call=%llu encode=%u/%u decode=%u/%u", (unsigned long long)id,
caps.encode[0].width, caps.encode[1].width, caps.decode[0].width, caps.decode[1].width);
if (v->ops.capabilities) v->ops.capabilities(v->arg, &v->peer);
} else if (data[0] == VIDEO_KEY_REQUEST && length == 9) {
control_send(v, VIDEO_CAPS_ACK);
} else if (data[0] == VIDEO_CAPS_ACK && length == 17 && revision && revision == v->local_revision) {
v->acknowledged_revision = revision;
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video capabilities acknowledged call=%llu revision=%llu",
(unsigned long long)id, (unsigned long long)revision);
} else if (data[0] == VIDEO_KEY_REQUEST && length == 17 && !revision) {
v->need_key = 1;
if (v->ops.need_key) v->ops.need_key(v->arg);
} else goto invalid;
@ -208,7 +229,8 @@ static void receive(struct ETCP_CONN *conn, struct ll_entry *entry) {
struct call_video_frame complete;
int result = call_video_receiver_push(v->receiver, &f, get_time_us(), &complete);
if (result == 1) v->ops.frame(v->arg, &complete);
else if (call_video_receiver_needs_key(v->receiver)) call_video_request_key(conn->instance, id);
else if (result < 0 || (!(f.flags & CALL_VIDEO_KEY) && call_video_receiver_needs_key(v->receiver)))
call_video_request_key(conn->instance, id);
}
goto done;
invalid:

Loading…
Cancel
Save