Report decoder acceptance separately from keyframe recovery
This commit is contained in:
1 parent
31a0c4f1a3
commit
d32c8ed6e3
2 files changed
+33
-5
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user