|
|
|
|
@ -668,13 +668,24 @@ static void call_handle_hangup(struct call_ctx* ctx, uint64_t from, const uint8_
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void call_handle_media(struct call_ctx* ctx, uint64_t from, const uint8_t* b, size_t n) { |
|
|
|
|
if (n < CALL_MEDIA_HDR_SIZE) return; |
|
|
|
|
if (n <= CALL_MEDIA_HDR_SIZE) { DEBUG_WARN(DEBUG_CATEGORY_CALL, "call media truncated bytes=%zu", n); return; } |
|
|
|
|
uint64_t call_id; memcpy(&call_id, b + 1, 8); |
|
|
|
|
struct call_session* s = call_session_find(ctx, call_id); |
|
|
|
|
if (!s || s->state != CALL_ST_ACTIVE) { |
|
|
|
|
/* медиа вне ACTIVE — игнорируем (гонка с завершением) */ |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
struct call_pkt_media packet; |
|
|
|
|
memcpy(&packet, b, sizeof(packet)); |
|
|
|
|
if (from != s->peer_node_id || packet.track_id != CALL_TRACK_AUDIO || packet.codec_delay_samples > CALL_OPUS_SAMPLE_RATE |
|
|
|
|
|| (packet.capture_pts_us != INT64_MIN && (packet.capture_pts_us < 0 || packet.capture_pts_us > INT64_MAX / 2 |
|
|
|
|
|| !packet.capture_epoch))) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CALL, "call media invalid peer=%016llx expected=%016llx track=%u pts=%lld epoch=%llu delay=%u", |
|
|
|
|
(unsigned long long)from, (unsigned long long)s->peer_node_id, packet.track_id, |
|
|
|
|
(long long)packet.capture_pts_us, (unsigned long long)packet.capture_epoch, packet.codec_delay_samples); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
struct call_capture_time timing = {packet.capture_pts_us, packet.capture_epoch, packet.codec_delay_samples}; |
|
|
|
|
s->c_rx_frames++; |
|
|
|
|
s->last_media_tb = get_time_tb(); |
|
|
|
|
|
|
|
|
|
@ -686,7 +697,7 @@ static void call_handle_media(struct call_ctx* ctx, uint64_t from, const uint8_t
|
|
|
|
|
/* аудио-движок (декод + джиттер-буфер) — если зарегистрирован */ |
|
|
|
|
if (ctx->audio_ops && ctx->audio_ops->on_media) |
|
|
|
|
ctx->audio_ops->on_media(ctx->inst, call_id, seq, ts_ms, |
|
|
|
|
b + CALL_MEDIA_HDR_SIZE, (int)(n - CALL_MEDIA_HDR_SIZE)); |
|
|
|
|
b + CALL_MEDIA_HDR_SIZE, (int)(n - CALL_MEDIA_HDR_SIZE), &timing); |
|
|
|
|
|
|
|
|
|
/* релей Opus-кадра потребителю (headless-аудио-сокет) */ |
|
|
|
|
if (ctx->media_recv_fn) |
|
|
|
|
@ -843,12 +854,19 @@ static void call_tx_flush(struct call_session* s) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int call_send_media(struct UTUN_INSTANCE* inst, uint64_t call_id, const uint8_t* opus, int len) { |
|
|
|
|
int call_send_media(struct UTUN_INSTANCE* inst, uint64_t call_id, const uint8_t* opus, int len, |
|
|
|
|
const struct call_capture_time* timing) { |
|
|
|
|
struct call_ctx* ctx = call_of(inst); |
|
|
|
|
if (!ctx || !ctx->initialized || !opus || len <= 0) return -1; |
|
|
|
|
struct call_session* s = call_session_find(ctx, call_id); |
|
|
|
|
if (!s || s->state != CALL_ST_ACTIVE) return -1; |
|
|
|
|
if (CALL_MEDIA_HDR_SIZE + (size_t)len > 1024) return -1; |
|
|
|
|
if (timing && (timing->delay_samples > CALL_OPUS_SAMPLE_RATE || (timing->pts_us != INT64_MIN |
|
|
|
|
&& (timing->pts_us < 0 || timing->pts_us > INT64_MAX / 2 || !timing->epoch)))) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call media invalid capture metadata pts=%lld epoch=%llu delay=%u", |
|
|
|
|
(long long)timing->pts_us, (unsigned long long)timing->epoch, timing->delay_samples); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint8_t buf[1024]; |
|
|
|
|
struct call_pkt_media* m = (struct call_pkt_media*)buf; |
|
|
|
|
@ -857,6 +875,9 @@ int call_send_media(struct UTUN_INSTANCE* inst, uint64_t call_id, const uint8_t*
|
|
|
|
|
m->track_id = CALL_TRACK_AUDIO; |
|
|
|
|
m->seq = s->tx_media_seq++; |
|
|
|
|
m->ts_ms = (uint32_t)(get_time_tb() / 10); |
|
|
|
|
m->capture_pts_us = timing ? timing->pts_us : INT64_MIN; |
|
|
|
|
m->capture_epoch = timing ? timing->epoch : 0; |
|
|
|
|
m->codec_delay_samples = timing ? timing->delay_samples : 0; |
|
|
|
|
memcpy(buf + CALL_MEDIA_HDR_SIZE, opus, (size_t)len); |
|
|
|
|
size_t mlen = CALL_MEDIA_HDR_SIZE + (size_t)len; |
|
|
|
|
|
|
|
|
|
@ -1025,6 +1046,6 @@ void call_hangup_trampoline(void* arg) {
|
|
|
|
|
|
|
|
|
|
void call_send_media_trampoline(void* arg) { |
|
|
|
|
struct call_media_arg* a = (struct call_media_arg*)arg; |
|
|
|
|
call_send_media(a->inst, a->call_id, a->opus, a->len); |
|
|
|
|
call_send_media(a->inst, a->call_id, a->opus, a->len, &a->timing); |
|
|
|
|
u_free(a); |
|
|
|
|
} |
|
|
|
|
|