forked from Green-Sky/tomato
c9cdae001 fix(toxav): remove extra copy of video frame on encode 4f6d4546b test: Improve the fake network library. a2581e700 refactor(toxcore): generate `Friend_Request` and `Dht_Nodes_Response` 2aaa11770 refactor(toxcore): use Tox_Memory in generated events 5c367452b test(toxcore): fix incorrect mutex in tox_scenario_get_time 8f92e710f perf: Add a timed limit of number of cookie requests. 695b6417a test: Add some more simulated network support. 815ae9ce9 test(toxcore): fix thread-safety in scenario framework 6d85c754e test(toxcore): add unit tests for net_crypto 9c22e79cc test(support): add SimulatedEnvironment for deterministic testing f34fcb195 chore: Update windows Dockerfile to debian stable (trixie). ece0e8980 fix(group_moderation): allow validating unsorted sanction list signatures a4fa754d7 refactor: rename struct Packet to struct Net_Packet d6f330f85 cleanup: Fix some warnings from coverity. e206bffa2 fix(group_chats): fix sync packets reverting topics 0e4715598 test: Add new scenario testing framework. 668291f44 refactor(toxcore): decouple Network_Funcs from sockaddr via IP_Port fc4396cef fix: potential division by zero in toxav and unsafe hex parsing 8e8b352ab refactor: Add nullable annotations to struct members. 7740bb421 refactor: decouple net_crypto from DHT 1936d4296 test: add benchmark for toxav audio and video 46bfdc2df fix: correct printf format specifiers for unsigned integers REVERT: 1828c5356 fix(toxav): remove extra copy of video frame on encode git-subtree-dir: external/toxcore/c-toxcore git-subtree-split: c9cdae001341e701fca980c9bb9febfeb95d2902
206 lines
6.4 KiB
C
206 lines
6.4 KiB
C
#include "framework/framework.h"
|
|
#include "../../toxav/toxav.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef struct {
|
|
bool incoming;
|
|
uint32_t state;
|
|
} CallState;
|
|
|
|
#define WAIT_UNTIL_AV(av, cond) do { \
|
|
while(!(cond) && tox_scenario_is_running(self)) { \
|
|
toxav_iterate(av); \
|
|
tox_scenario_yield(self); \
|
|
} \
|
|
} while(0)
|
|
|
|
static void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
|
{
|
|
ToxNode *self = (ToxNode *)user_data;
|
|
CallState *state = (CallState *)tox_node_get_script_ctx(self);
|
|
tox_node_log(self, "Received call from friend %u", friend_number);
|
|
state->incoming = true;
|
|
}
|
|
|
|
static void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
|
|
{
|
|
ToxNode *self = (ToxNode *)user_data;
|
|
CallState *cs = (CallState *)tox_node_get_script_ctx(self);
|
|
tox_node_log(self, "Call state changed to %u", state);
|
|
cs->state = state;
|
|
}
|
|
|
|
static void on_audio_receive(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
|
|
uint8_t channels, uint32_t sampling_rate, void *user_data)
|
|
{
|
|
(void)av;
|
|
(void)friend_number;
|
|
(void)pcm;
|
|
(void)sample_count;
|
|
(void)channels;
|
|
(void)sampling_rate;
|
|
(void)user_data;
|
|
}
|
|
|
|
static void on_video_receive(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height,
|
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
|
int32_t ystride, int32_t ustride, int32_t vstride, void *user_data)
|
|
{
|
|
(void)av;
|
|
(void)friend_number;
|
|
(void)width;
|
|
(void)height;
|
|
(void)y;
|
|
(void)u;
|
|
(void)v;
|
|
(void)ystride;
|
|
(void)ustride;
|
|
(void)vstride;
|
|
(void)user_data;
|
|
}
|
|
|
|
static void alice_script(ToxNode *self, void *ctx)
|
|
{
|
|
CallState *state = (CallState *)ctx;
|
|
Tox *tox = tox_node_get_tox(self);
|
|
Toxav_Err_New av_err;
|
|
ToxAV *av = toxav_new(tox, &av_err);
|
|
ck_assert(av_err == TOXAV_ERR_NEW_OK);
|
|
|
|
toxav_callback_call(av, on_call, self);
|
|
toxav_callback_call_state(av, on_call_state, self);
|
|
toxav_callback_audio_receive_frame(av, on_audio_receive, self);
|
|
toxav_callback_video_receive_frame(av, on_video_receive, self);
|
|
|
|
WAIT_UNTIL(tox_node_is_self_connected(self));
|
|
WAIT_UNTIL(tox_node_is_friend_connected(self, 0));
|
|
|
|
// 1. Regular AV call - Alice calls, Bob answers, Bob hangs up
|
|
tox_node_log(self, "--- Starting Regular AV Call ---");
|
|
state->state = 0;
|
|
Toxav_Err_Call call_err;
|
|
toxav_call(av, 0, 48, 4000, &call_err);
|
|
ck_assert(call_err == TOXAV_ERR_CALL_OK);
|
|
|
|
WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED);
|
|
tox_node_log(self, "Regular AV Call finished (state=%u)", state->state);
|
|
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
// 2. Reject flow - Alice calls, Bob rejects
|
|
tox_node_log(self, "--- Starting Reject Flow ---");
|
|
state->state = 0;
|
|
toxav_call(av, 0, 48, 0, &call_err);
|
|
ck_assert(call_err == TOXAV_ERR_CALL_OK);
|
|
|
|
WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED);
|
|
tox_node_log(self, "Reject Flow finished");
|
|
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
// 3. Cancel flow - Alice calls, Alice cancels
|
|
tox_node_log(self, "--- Starting Cancel Flow ---");
|
|
state->state = 0;
|
|
toxav_call(av, 0, 48, 0, &call_err);
|
|
ck_assert(call_err == TOXAV_ERR_CALL_OK);
|
|
|
|
// Wait for Bob to see it ringing
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
tox_node_log(self, "Alice: Canceling call...");
|
|
Toxav_Err_Call_Control cc_err;
|
|
toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
|
|
ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK);
|
|
|
|
// Alice doesn't receive FINISHED state when SHE cancels
|
|
tox_node_log(self, "Alice: Cancel Flow finished");
|
|
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
toxav_kill(av);
|
|
}
|
|
|
|
static void bob_script(ToxNode *self, void *ctx)
|
|
{
|
|
CallState *state = (CallState *)ctx;
|
|
Tox *tox = tox_node_get_tox(self);
|
|
Toxav_Err_New av_err;
|
|
ToxAV *av = toxav_new(tox, &av_err);
|
|
ck_assert(av_err == TOXAV_ERR_NEW_OK);
|
|
|
|
toxav_callback_call(av, on_call, self);
|
|
toxav_callback_call_state(av, on_call_state, self);
|
|
toxav_callback_audio_receive_frame(av, on_audio_receive, self);
|
|
toxav_callback_video_receive_frame(av, on_video_receive, self);
|
|
|
|
WAIT_UNTIL(tox_node_is_self_connected(self));
|
|
WAIT_UNTIL(tox_node_is_friend_connected(self, 0));
|
|
|
|
// 1. Regular AV call - Bob answers, then hangs up
|
|
WAIT_UNTIL_AV(av, state->incoming);
|
|
state->incoming = false;
|
|
Toxav_Err_Answer answer_err;
|
|
toxav_answer(av, 0, 48, 4000, &answer_err);
|
|
ck_assert(answer_err == TOXAV_ERR_ANSWER_OK);
|
|
|
|
// Wait a bit and hang up
|
|
for (int i = 0; i < 10; i++) {
|
|
toxav_iterate(av);
|
|
tox_scenario_yield(self);
|
|
}
|
|
tox_node_log(self, "Bob: Hanging up...");
|
|
Toxav_Err_Call_Control cc_err;
|
|
toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
|
|
ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK);
|
|
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
// 2. Reject flow - Bob rejects
|
|
WAIT_UNTIL_AV(av, state->incoming);
|
|
state->incoming = false;
|
|
tox_node_log(self, "Bob: Rejecting call...");
|
|
toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
|
|
ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK);
|
|
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
// 3. Cancel flow - Alice cancels
|
|
WAIT_UNTIL_AV(av, state->incoming);
|
|
state->incoming = false;
|
|
tox_scenario_barrier_wait(self); // Alice will now cancel
|
|
|
|
WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED);
|
|
tox_node_log(self, "Bob: Cancel Flow finished (Alice canceled)");
|
|
|
|
tox_scenario_barrier_wait(self);
|
|
|
|
toxav_kill(av);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
ToxScenario *s = tox_scenario_new(argc, argv, 60000);
|
|
|
|
CallState alice_state = {0};
|
|
CallState bob_state = {0};
|
|
|
|
Tox_Options *opts = tox_options_new(nullptr);
|
|
tox_options_set_ipv6_enabled(opts, false);
|
|
tox_options_set_local_discovery_enabled(opts, false);
|
|
|
|
ToxNode *alice = tox_scenario_add_node_ex(s, "Alice", alice_script, &alice_state, sizeof(CallState), opts);
|
|
ToxNode *bob = tox_scenario_add_node_ex(s, "Bob", bob_script, &bob_state, sizeof(CallState), opts);
|
|
|
|
tox_options_free(opts);
|
|
|
|
tox_node_bootstrap(bob, alice);
|
|
tox_node_friend_add(alice, bob);
|
|
tox_node_friend_add(bob, alice);
|
|
|
|
ToxScenarioStatus res = tox_scenario_run(s);
|
|
tox_scenario_free(s);
|
|
return (res == TOX_SCENARIO_DONE) ? 0 : 1;
|
|
}
|