|
|
|
|
@ -19,6 +19,7 @@
|
|
|
|
|
#include "../dm/dm_crypto.h" |
|
|
|
|
#include "../call/call_proto.h" |
|
|
|
|
#include "../call/call_video_transport.h" |
|
|
|
|
#include "../call/call_video_port.h" |
|
|
|
|
#include "../routing_layer/topo_node_sqlite.h" |
|
|
|
|
#include "../routing_layer/topo_group.h" |
|
|
|
|
#include "../routing_layer/topo_node.h" |
|
|
|
|
@ -63,7 +64,7 @@ enum call_phase {
|
|
|
|
|
P_SEND_MEDIA, /* A: call_send_media (тестовый Opus-кадр) */ |
|
|
|
|
P_WAIT_MEDIA, /* B: media_recv_cb получил кадр */ |
|
|
|
|
P_VIDEO_CONFIG, P_VIDEO_SEND, P_VIDEO_HOLD, P_VIDEO_BUSY, P_VIDEO_RESUME, P_VIDEO_RANGE_WAIT, P_VIDEO_SWITCH, P_VIDEO_SWITCH_WAIT, |
|
|
|
|
P_VIDEO_SHRINK_WAIT, |
|
|
|
|
P_VIDEO_SHRINK_WAIT, P_VIDEO_PORT_OPEN, P_VIDEO_PORT_RECEIVE, P_VIDEO_PORT_SEND, P_VIDEO_PORT_ACK, |
|
|
|
|
P_HANGUP, /* A: call_hangup */ |
|
|
|
|
P_WAIT_ENDED1, /* обе ENDED */ |
|
|
|
|
P_CALL2_START, /* A: call_start (2-й звонок) */ |
|
|
|
|
@ -121,6 +122,12 @@ static uint64_t g_rate_generation, g_rate_request;
|
|
|
|
|
static uint32_t g_rate_bps; |
|
|
|
|
static unsigned g_rate_commands; |
|
|
|
|
static unsigned g_video_keys[2]; |
|
|
|
|
static int g_port_frame; |
|
|
|
|
static void port_received(void *arg, const struct call_video_frame *f) { |
|
|
|
|
(void)arg; |
|
|
|
|
g_port_frame = f->frame_id == 1 && f->format.generation == 1 && f->size == sizeof(g_video_data) |
|
|
|
|
&& !memcmp(f->data, g_video_data, sizeof(g_video_data)) ? 1 : -1; |
|
|
|
|
} |
|
|
|
|
static void video_caps(void *arg, const struct call_video_caps *caps) { g_video_peer[(size_t)arg] = *caps; } |
|
|
|
|
static void video_need_key(void *arg) { g_video_keys[(size_t)arg]++; } |
|
|
|
|
static int video_ready(void *arg, uint32_t bytes) { (void)arg; return bytes <= sizeof(g_video_data) && g_video_ready; } |
|
|
|
|
@ -601,6 +608,53 @@ static void call_tick(void* arg) {
|
|
|
|
|
if (call_video_configure_rate(A, t->call_id, &f.format, 350000, 400000) || call_video_send_frame(A, &f) != 1) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video failed to replace withdrawn envelope"); t->result = 2; break; |
|
|
|
|
} |
|
|
|
|
if (call_video_port_attach(B) || call_video_port_open(t->call_id, &g_video_peer[0])) { t->result = 2; break; } |
|
|
|
|
t->phase = P_VIDEO_PORT_OPEN; break; |
|
|
|
|
} |
|
|
|
|
case P_VIDEO_PORT_OPEN: { |
|
|
|
|
struct call_video_port_status status; |
|
|
|
|
if (call_video_port_status(t->call_id, &status) || !status.have_peer) break; |
|
|
|
|
struct call_capture_time timing = sent_timing; timing.pts_us += 200000; |
|
|
|
|
uint8_t opus[16] = {3}; |
|
|
|
|
if (call_send_media(A, t->call_id, opus, sizeof(opus), &timing)) { t->result = 2; break; } |
|
|
|
|
t->phase = P_VIDEO_PORT_RECEIVE; break; |
|
|
|
|
} |
|
|
|
|
case P_VIDEO_PORT_RECEIVE: { |
|
|
|
|
struct call_video_frame received; |
|
|
|
|
if (!call_video_port_pull(t->call_id, &received)) break; |
|
|
|
|
int valid = received.frame_id == 4 && received.format.maximum_bps == 3000000 |
|
|
|
|
&& received.size == sizeof(g_video_data) && !memcmp(received.data, g_video_data, sizeof(g_video_data)); |
|
|
|
|
u_free((void *)received.data); |
|
|
|
|
if (!valid) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port RX ownership/metadata mismatch"); t->result = 2; break; } |
|
|
|
|
struct call_video_ops callbacks = video_ops; callbacks.frame = port_received; |
|
|
|
|
if (call_video_configure(A, t->call_id, &g_video_peer[1], &callbacks, (void *)0)) { t->result = 2; break; } |
|
|
|
|
struct call_video_frame f = video_test_frame(t->call_id, 1); |
|
|
|
|
if (call_video_port_range(t->call_id, 300000, 500000) || call_video_port_format(t->call_id, &f.format, 500000)) { |
|
|
|
|
t->result = 2; break; |
|
|
|
|
} |
|
|
|
|
g_video_ready = 1; t->phase = P_VIDEO_PORT_SEND; break; |
|
|
|
|
} |
|
|
|
|
case P_VIDEO_PORT_SEND: { |
|
|
|
|
struct call_video_port_status status; |
|
|
|
|
if (call_video_port_status(t->call_id, &status) || status.configured_generation != 1) break; |
|
|
|
|
struct call_video_frame f = video_test_frame(t->call_id, 1); |
|
|
|
|
if (status.minimum_bps != 300000 || status.maximum_bps != 500000 |
|
|
|
|
|| call_video_port_send(&f) != 1 || call_video_port_send(&f) != 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port TX mailbox/range mismatch"); t->result = 2; break; |
|
|
|
|
} |
|
|
|
|
struct call_capture_time timing = sent_timing; timing.pts_us += 200000; |
|
|
|
|
uint8_t opus[16] = {4}; |
|
|
|
|
if (call_send_media(B, t->call_id, opus, sizeof(opus), &timing)) { t->result = 2; break; } |
|
|
|
|
t->phase = P_VIDEO_PORT_ACK; break; |
|
|
|
|
} |
|
|
|
|
case P_VIDEO_PORT_ACK: { |
|
|
|
|
if (!g_port_frame) break; |
|
|
|
|
if (g_port_frame != 1) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port TX payload mismatch"); t->result = 2; break; } |
|
|
|
|
call_video_port_request_key(t->call_id); |
|
|
|
|
call_video_port_close(t->call_id); |
|
|
|
|
call_video_port_detach(B); // Отменяет уже поставленный post до destroy ядра.
|
|
|
|
|
struct call_video_port_status status; |
|
|
|
|
if (call_video_port_status(t->call_id, &status) != -1) { t->result = 2; break; } |
|
|
|
|
t->phase = P_HANGUP; break; |
|
|
|
|
} |
|
|
|
|
case P_HANGUP: |
|
|
|
|
@ -720,7 +774,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
int ok = (t.result == 1); |
|
|
|
|
|
|
|
|
|
if (t.inst[IDX_A]) utun_instance_destroy(t.inst[IDX_A]); |
|
|
|
|
if (t.inst[IDX_B]) utun_instance_destroy(t.inst[IDX_B]); |
|
|
|
|
if (t.inst[IDX_B]) { call_video_port_detach(t.inst[IDX_B]); utun_instance_destroy(t.inst[IDX_B]); } |
|
|
|
|
uasync_poll(ua, 0); |
|
|
|
|
uasync_destroy(ua, 0); |
|
|
|
|
|
|
|
|
|
|