Browse Source

Separate call audio and video from signaling queues

master
evgeny 5 days ago
parent
commit
609221e384
  1. 38
      src/call/call.c
  2. 6
      src/transport_layer/etcp_api.h

38
src/call/call.c

@ -13,6 +13,7 @@
#include "call.h"
#include "call_priv.h"
#include "call_video_transport.h"
#include "call_proto.h"
#include "../dm/dm_core.h"
#include "../utun_instance.h"
@ -147,7 +148,8 @@ static void call_session_free_cb(void* arg) {
/* Освободить медиа-объекты сессии: отменить waiter на send_q роутера и
* дренировать tx_q (без отправки). Безопасно вызывать из uasync-потока. */
static void call_session_cleanup(struct call_ctx* ctx, struct call_session* s) {
etcp_router_cancel_send_ready(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL, &s->send_waiter);
call_video_transport_stop(s);
etcp_router_cancel_send_ready(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_AUDIO, &s->send_waiter);
if (s->tx_q) {
struct ll_entry* e;
while ((e = queue_data_get(s->tx_q)) != NULL) {
@ -282,6 +284,7 @@ static void call_end(struct call_ctx* ctx, struct call_session* s, uint8_t reaso
if (!ctx || !s || s->state == CALL_ST_ENDED) return;
s->state = CALL_ST_ENDED;
call_video_transport_stop(s);
s->reason = reason;
ctx->c_calls_ended++;
@ -679,6 +682,19 @@ static void call_etcp_recv(struct ETCP_CONN* conn, struct ll_entry* entry) {
const uint8_t* body = d + ROUTER_SVC_PAYLOAD_OFF;
size_t blen = entry->len - ROUTER_SVC_PAYLOAD_OFF;
if ((subcmd == CALL_SUBCMD_MEDIA) != (d[0] == ETCP_RT_ID_CALL_AUDIO)) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "call packet in wrong channel svc=%u subcmd=%u", d[0], subcmd);
queue_dgram_free(entry); queue_entry_free(entry); return;
}
if (subcmd != CALL_SUBCMD_INVITE && blen >= 9) {
uint64_t id; memcpy(&id, body + 1, 8);
struct call_session *s = call_session_find(ctx, id);
if (s && (s->peer_node_id != from || s->group_id != group)) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "call packet peer/group mismatch id=%llu", (unsigned long long)id);
queue_dgram_free(entry); queue_entry_free(entry); return;
}
}
switch (subcmd) {
case CALL_SUBCMD_INVITE: call_handle_invite(ctx, from, group, body, blen); break;
case CALL_SUBCMD_RINGING: call_handle_ringing(ctx, from, body, blen); break;
@ -722,6 +738,10 @@ int call_init(struct UTUN_INSTANCE* inst) {
}
ctx->initialized = 1;
if (etcp_router_bind(inst, ETCP_RT_ID_CALL_AUDIO, call_etcp_recv) || call_video_transport_bind(inst)) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call media channel bind failed");
call_destroy(inst); return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_CALL, "%s: initialized (svc=0x%02x)", CALL_ID, ETCP_RT_ID_CALL);
return 0;
}
@ -746,6 +766,8 @@ void call_destroy(struct UTUN_INSTANCE* inst) {
queue_entry_free(e);
}
queue_free(ctx->sessions);
call_video_transport_unbind(inst);
etcp_router_unbind(inst, ETCP_RT_ID_CALL_AUDIO);
etcp_router_unbind(inst, ETCP_RT_ID_CALL);
inst->call = NULL;
uint32_t started = ctx->c_calls_started, ended = ctx->c_calls_ended;
@ -792,17 +814,19 @@ static void call_tx_flush(struct call_session* s) {
struct call_ctx* ctx = s->ctx;
if (s->state == CALL_ST_ENDED) return;
/* гарантируем router conn — иначе has_room/on_send_ready не видят его */
etcp_router_conn_get(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL);
etcp_router_conn_get(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_AUDIO);
while (s->tx_q && s->tx_q->head) {
if (!etcp_router_send_q_has_room(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL)) {
etcp_router_on_send_ready(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL,
if (!etcp_router_send_q_has_room(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_AUDIO)) {
etcp_router_on_send_ready(ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_AUDIO,
&s->send_waiter, call_tx_drain_cb, s);
return;
}
struct ll_entry* e = queue_data_get(s->tx_q);
if (etcp_route_send(ctx->inst, s->group_id, s->peer_node_id, e, 1, 0) == 0)
struct call_pkt_media packet; memcpy(&packet, e->dgram + 1, sizeof(packet));
if (etcp_route_send(ctx->inst, s->group_id, s->peer_node_id, e, 1, 0) == 0) {
s->c_tx_frames++;
else DEBUG_WARN(DEBUG_CATEGORY_CALL, "%s: media enqueue failed id=%016llx", CALL_ID, (unsigned long long)s->call_id);
if (packet.capture_pts_us != INT64_MIN) call_video_audio_sent(s, packet.capture_pts_us + 20000);
} else DEBUG_WARN(DEBUG_CATEGORY_CALL, "%s: media enqueue failed id=%016llx", CALL_ID, (unsigned long long)s->call_id);
}
}
@ -838,7 +862,7 @@ int call_send_media(struct UTUN_INSTANCE* inst, uint64_t call_id, const uint8_t*
if (!e) return -1;
e->dgram = u_malloc(1 + mlen);
if (!e->dgram) { queue_entry_free(e); return -1; }
e->dgram[0] = ETCP_RT_ID_CALL;
e->dgram[0] = ETCP_RT_ID_CALL_AUDIO;
memcpy(e->dgram + 1, buf, mlen);
e->len = (uint16_t)(1 + mlen);

6
src/transport_layer/etcp_api.h

@ -44,7 +44,8 @@ extern "C" {
// 0x06 ICMP_PROXY, 0x07 MEDIA_DELIVERY, 0x08 TCP_PROXY_CLIENT,
// 0x11 CONN_MGR, 0x32 ADMIN_KEY, 0x33 JOIN, 0x34 DM,
// 0x35 DM_MAILBOX, 0x36 CALL, 0x37 FILE_TRANSFER, 0x38 DM_MEDIA, 0x39 MEMBER_FILES,
// 0x3A GROUP_AVATAR, 0x3B NAT_DETECTION, 0x3C STREAM
// 0x3A GROUP_AVATAR, 0x3B NAT_DETECTION, 0x3C STREAM,
// 0x3D CALL_VIDEO_CONTROL, 0x3E CALL_VIDEO, 0x3F CALL_AUDIO
//
// !!! Новый ID: впиши его в нужный реестр выше и убедись, что значение
// не занято в том же пространстве.
@ -81,6 +82,9 @@ extern "C" {
#define ETCP_RT_ID_DM 0x34 // dm_core — прямой p2p чат
#define ETCP_RT_ID_DM_MAILBOX 0x35 // dm_mailbox — offline-хранение
#define ETCP_RT_ID_CALL 0x36 // call — P2P аудио-звонок
#define ETCP_RT_ID_CALL_VIDEO_CONTROL 0x3D // возможности и восстановление видеотрека
#define ETCP_RT_ID_CALL_VIDEO 0x3E // видео, отдельный ACK/debt/backpressure
#define ETCP_RT_ID_CALL_AUDIO 0x3F // аудио, независимо от сигналинга/видео
#define ETCP_RT_ID_FILE_TRANSFER 0x37 // file_transfer — передача неизменяемых файлов
#define ETCP_RT_ID_DM_MEDIA 0x38 // dm_media — custody, location и подтверждения медиа
#define ETCP_RT_ID_MEMBER_FILES 0x39 // member_files — каталоги и файлы участников группы

Loading…
Cancel
Save