Browse Source

Report decoder acceptance separately from keyframe recovery

master
evgeny 5 days ago
parent
commit
d32c8ed6e3
  1. 35
      src/call/call_video_transport.c
  2. 3
      src/call/call_video_transport.h

35
src/call/call_video_transport.c

@ -10,7 +10,7 @@
#include "../../lib/debug_config.h"
#include <string.h>
enum { VIDEO_CAPS = 1, VIDEO_KEY_REQUEST = 2, VIDEO_CAPS_ACK = 3 };
enum { VIDEO_CAPS = 1, VIDEO_KEY_REQUEST = 2, VIDEO_CAPS_ACK = 3, VIDEO_DECODE_OK = 4, VIDEO_DECODE_REJECT = 5 };
struct call_video_transport {
struct call_session *session;
struct call_video_caps local, peer;
@ -29,6 +29,8 @@ struct call_video_transport {
uint64_t rate_request, produced_id, route_local_epoch, route_peer_epoch, rate_requested_us;
uint32_t applied_bps, maximum_bps, range_minimum_bps, range_maximum_bps;
int rate_pending, admit;
uint64_t received_generation, decode_generation;
int decode_result, decode_pending, tx_rejected;
};
static struct call_session *active(struct UTUN_INSTANCE *inst, uint64_t id) {
@ -55,6 +57,7 @@ static int control_send(struct call_video_transport *v, uint8_t type) {
struct call_session *s = v->session;
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;
if (type == VIDEO_DECODE_OK || type == VIDEO_DECODE_REJECT) revision = v->decode_generation;
memcpy(data + 9, &revision, 8);
size_t length = 17;
if (type == VIDEO_CAPS) {
@ -82,7 +85,7 @@ static void update_rate(struct call_video_transport *v) {
if (!v->rate_format.generation || !v->applied_bps) return;
struct call_session *s = v->session;
uint64_t now = get_time_us();
if (v->rate_pending && now - v->rate_requested_us > 2000000) {
if (v->rate_pending && now - v->rate_requested_us > 12000000) {
v->rate_pending = 0; v->applied_bps = 0; v->admit = 0;
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video encoder command timeout call=%llu generation=%llu request=%llu",
(unsigned long long)s->call_id, (unsigned long long)v->rate_format.generation, (unsigned long long)v->rate_request);
@ -173,7 +176,8 @@ static void tick(void *arg) {
// Отдельный control может обогнать ACCEPT: повторяем до подтверждения приложения.
if (v->local_revision && v->acknowledged_revision != v->local_revision && get_time_tb() - v->caps_sent_tb >= 5000)
control_send(v, VIDEO_CAPS);
update_rate(v);
if (v->decode_pending && !control_send(v, v->decode_result ? VIDEO_DECODE_OK : VIDEO_DECODE_REJECT)) v->decode_pending = 0;
if (!v->tx_rejected) update_rate(v);
flush(v);
v->timer = uasync_set_timeout(v->session->ctx->inst->ua, 500, v, tick, "call_video");
if (!v->timer) DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video timer rearm failed call=%llu", (unsigned long long)v->session->call_id);
@ -233,6 +237,7 @@ int call_video_send_frame(struct UTUN_INSTANCE *inst, const struct call_video_fr
f ? f->size : 0, f ? f->offset : 0, f ? f->length : 0, f && call_video_format_valid(&f->format)); return -1;
}
if (!v->have_peer || v->acknowledged_revision != v->local_revision) { v->need_key = 1; return 0; }
if (v->tx_rejected) return 0;
if (!call_video_format_supported(&v->local, &v->peer, &f->format)) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "video TX unsupported format codec=%u level=%u bitrate_cap=%u profile=%u",
f->format.codec, f->format.level, f->format.maximum_bps, f->format.profile); return -1;
@ -284,7 +289,7 @@ int call_video_configure_rate(struct UTUN_INSTANCE *inst, uint64_t id, const str
(unsigned long long)id, range_minimum, maximum); return -1;
}
if (v->rate_format.generation != generation) {
v->rate_format = *format; v->rate_pending = 0; v->admit = 1;
v->rate_format = *format; v->rate_pending = 0; v->admit = 1; v->tx_rejected = 0;
call_video_rate_init(&v->rate, get_time_us()); route_tx_meter_reset(&v->production, get_time_us());
}
v->applied_bps = applied; v->maximum_bps = maximum;
@ -323,6 +328,19 @@ void call_video_request_key(struct UTUN_INSTANCE *inst, uint64_t id) {
if (v->key_request_tb && now - v->key_request_tb < 5000) return;
if (!control_send(v, VIDEO_KEY_REQUEST)) v->key_request_tb = now;
}
int call_video_decode_result(struct UTUN_INSTANCE *inst, uint64_t id, uint64_t generation, int accepted) {
struct call_session *s = active(inst, id);
struct call_video_transport *v = s ? s->video : NULL;
if (!v || !generation || generation != v->received_generation || (accepted != 0 && accepted != 1)) {
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video stale decoder result call=%llu generation=%llu",
(unsigned long long)id, (unsigned long long)generation); return -1;
}
v->decode_generation = generation; v->decode_result = accepted; v->decode_pending = 1;
if (!control_send(v, accepted ? VIDEO_DECODE_OK : VIDEO_DECODE_REJECT)) v->decode_pending = 0;
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video decoder result call=%llu generation=%llu accepted=%d pending=%d",
(unsigned long long)id, (unsigned long long)generation, accepted, v->decode_pending);
return 0;
}
static int ready(struct UTUN_INSTANCE *inst, uint64_t group, uint64_t peer, const uint8_t *data, size_t length) {
struct call_video_frame f;
if (call_video_fragment_parse(data, length, &f)) return 1;
@ -382,12 +400,19 @@ static void receive(struct ETCP_CONN *conn, struct ll_entry *entry) {
} 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 if ((data[0] == VIDEO_DECODE_OK || data[0] == VIDEO_DECODE_REJECT) && length == 17 && revision) {
if (revision != v->rate_format.generation) goto done;
int accepted = data[0] == VIDEO_DECODE_OK;
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video remote decoder result call=%llu generation=%llu accepted=%d",
(unsigned long long)id, (unsigned long long)revision, accepted);
if (!accepted) { v->tx_rejected = 1; v->admit = 0; if (v->data) discard_tx(v, "decoder_rejected"); }
if (v->ops.decoded) v->ops.decoded(v->arg, revision, accepted);
} else goto invalid;
} else if (v->ops.frame) {
if (!v->have_peer || !call_video_format_supported(&v->peer, &v->local, &f.format)) goto invalid;
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);
if (result == 1) { v->received_generation = complete.format.generation; v->ops.frame(v->arg, &complete); }
else if (result < 0 || (!(f.flags & CALL_VIDEO_KEY) && call_video_receiver_needs_key(v->receiver)))
call_video_request_key(conn->instance, id);
}

3
src/call/call_video_transport.h

@ -16,6 +16,7 @@ struct call_video_ops {
void (*frame)(void *arg, const struct call_video_frame *frame);
void (*need_key)(void *arg);
void (*bitrate)(void *arg, uint64_t generation, uint64_t request, uint32_t bps);
void (*decoded)(void *arg, uint64_t generation, int accepted);
};
/* Настройка активного звонка, включая receive-only. NULL ops снимает платформенные callbacks.
* capabilities отражают только реально проверенные профили. 0 — успешно, -1 — ошибка. */
@ -28,6 +29,8 @@ int call_video_send_frame(struct UTUN_INSTANCE *inst, const struct call_video_fr
void call_video_resume_receive(struct UTUN_INSTANCE *inst, uint64_t call_id);
/* Decoder потерял references. Запрос идемпотентный, отправляется не чаще раза в 500мс. */
void call_video_request_key(struct UTUN_INSTANCE *inst, uint64_t call_id);
/* Результат запуска decoder конкретного поколения, отдельно от потери references. */
int call_video_decode_result(struct UTUN_INSTANCE *inst, uint64_t call_id, uint64_t generation, int accepted);
/* После открытия encoder; format — согласованный и фактически проверенный режим.
* maximum_bps — дополнительный предел регулятора, не выше format.maximum_bps;
* applied_bps может быть выше maximum_bps (нужно снижение), но не выше envelope.

Loading…
Cancel
Save