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 "../../lib/debug_config.h"
|
||||||
#include <string.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_video_transport {
|
||||||
struct call_session *session;
|
struct call_session *session;
|
||||||
struct call_video_caps local, peer;
|
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;
|
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;
|
uint32_t applied_bps, maximum_bps, range_minimum_bps, range_maximum_bps;
|
||||||
int rate_pending, admit;
|
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) {
|
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;
|
struct call_session *s = v->session;
|
||||||
uint8_t data[17 + CALL_VIDEO_CAPS_BYTES]; data[0] = type; memcpy(data + 1, &s->call_id, 8);
|
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;
|
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);
|
memcpy(data + 9, &revision, 8);
|
||||||
size_t length = 17;
|
size_t length = 17;
|
||||||
if (type == VIDEO_CAPS) {
|
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;
|
if (!v->rate_format.generation || !v->applied_bps) return;
|
||||||
struct call_session *s = v->session;
|
struct call_session *s = v->session;
|
||||||
uint64_t now = get_time_us();
|
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;
|
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",
|
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);
|
(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: повторяем до подтверждения приложения.
|
// Отдельный control может обогнать ACCEPT: повторяем до подтверждения приложения.
|
||||||
if (v->local_revision && v->acknowledged_revision != v->local_revision && get_time_tb() - v->caps_sent_tb >= 5000)
|
if (v->local_revision && v->acknowledged_revision != v->local_revision && get_time_tb() - v->caps_sent_tb >= 5000)
|
||||||
control_send(v, VIDEO_CAPS);
|
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);
|
flush(v);
|
||||||
v->timer = uasync_set_timeout(v->session->ctx->inst->ua, 500, v, tick, "call_video");
|
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);
|
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;
|
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->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)) {
|
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",
|
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;
|
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;
|
(unsigned long long)id, range_minimum, maximum); return -1;
|
||||||
}
|
}
|
||||||
if (v->rate_format.generation != generation) {
|
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());
|
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;
|
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 (v->key_request_tb && now - v->key_request_tb < 5000) return;
|
||||||
if (!control_send(v, VIDEO_KEY_REQUEST)) v->key_request_tb = now;
|
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) {
|
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;
|
struct call_video_frame f;
|
||||||
if (call_video_fragment_parse(data, length, &f)) return 1;
|
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) {
|
} else if (data[0] == VIDEO_KEY_REQUEST && length == 17 && !revision) {
|
||||||
v->need_key = 1;
|
v->need_key = 1;
|
||||||
if (v->ops.need_key) v->ops.need_key(v->arg);
|
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 goto invalid;
|
||||||
} else if (v->ops.frame) {
|
} else if (v->ops.frame) {
|
||||||
if (!v->have_peer || !call_video_format_supported(&v->peer, &v->local, &f.format)) goto invalid;
|
if (!v->have_peer || !call_video_format_supported(&v->peer, &v->local, &f.format)) goto invalid;
|
||||||
struct call_video_frame complete;
|
struct call_video_frame complete;
|
||||||
int result = call_video_receiver_push(v->receiver, &f, get_time_us(), &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)))
|
else if (result < 0 || (!(f.flags & CALL_VIDEO_KEY) && call_video_receiver_needs_key(v->receiver)))
|
||||||
call_video_request_key(conn->instance, id);
|
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 (*frame)(void *arg, const struct call_video_frame *frame);
|
||||||
void (*need_key)(void *arg);
|
void (*need_key)(void *arg);
|
||||||
void (*bitrate)(void *arg, uint64_t generation, uint64_t request, uint32_t bps);
|
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.
|
/* Настройка активного звонка, включая receive-only. NULL ops снимает платформенные callbacks.
|
||||||
* capabilities отражают только реально проверенные профили. 0 — успешно, -1 — ошибка. */
|
* 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);
|
void call_video_resume_receive(struct UTUN_INSTANCE *inst, uint64_t call_id);
|
||||||
/* Decoder потерял references. Запрос идемпотентный, отправляется не чаще раза в 500мс. */
|
/* Decoder потерял references. Запрос идемпотентный, отправляется не чаще раза в 500мс. */
|
||||||
void call_video_request_key(struct UTUN_INSTANCE *inst, uint64_t call_id);
|
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 — согласованный и фактически проверенный режим.
|
/* После открытия encoder; format — согласованный и фактически проверенный режим.
|
||||||
* maximum_bps — дополнительный предел регулятора, не выше format.maximum_bps;
|
* maximum_bps — дополнительный предел регулятора, не выше format.maximum_bps;
|
||||||
* applied_bps может быть выше maximum_bps (нужно снижение), но не выше envelope.
|
* applied_bps может быть выше maximum_bps (нужно снижение), но не выше envelope.
|
||||||
|
|||||||
Reference in new issue
Block a user