/work/auto_tests/scenarios/scenario_toxav_basic_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "framework/framework.h" |
2 | | #include "../../toxav/toxav.h" |
3 | | #include <stdio.h> |
4 | | #include <string.h> |
5 | | #include <stdlib.h> |
6 | | |
7 | | typedef struct { |
8 | | bool incoming; |
9 | | uint32_t state; |
10 | | } CallState; |
11 | | |
12 | 6 | #define WAIT_UNTIL_AV(av, cond) do { \ |
13 | 24 | while(!(cond) && tox_scenario_is_running(self)) { \ |
14 | 18 | toxav_iterate(av); \ |
15 | 18 | tox_scenario_yield(self); \ |
16 | 18 | } \ |
17 | 6 | } while(0) |
18 | | |
19 | | static void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) |
20 | 6 | { |
21 | 6 | ToxNode *self = (ToxNode *)user_data; |
22 | 6 | CallState *state = (CallState *)tox_node_get_script_ctx(self); |
23 | 6 | tox_node_log(self, "Received call from friend %u", friend_number); |
24 | 6 | state->incoming = true; |
25 | 6 | } |
26 | | |
27 | | static void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) |
28 | 10 | { |
29 | 10 | ToxNode *self = (ToxNode *)user_data; |
30 | 10 | CallState *cs = (CallState *)tox_node_get_script_ctx(self); |
31 | 10 | tox_node_log(self, "Call state changed to %u", state); |
32 | 10 | cs->state = state; |
33 | 10 | } |
34 | | |
35 | | static void on_audio_receive(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count, |
36 | | uint8_t channels, uint32_t sampling_rate, void *user_data) |
37 | 48 | { |
38 | 48 | (void)av; |
39 | 48 | (void)friend_number; |
40 | 48 | (void)pcm; |
41 | 48 | (void)sample_count; |
42 | 48 | (void)channels; |
43 | 48 | (void)sampling_rate; |
44 | 48 | (void)user_data; |
45 | 48 | } |
46 | | |
47 | | static void on_video_receive(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, |
48 | | uint8_t const *y, uint8_t const *u, uint8_t const *v, |
49 | | int32_t ystride, int32_t ustride, int32_t vstride, void *user_data) |
50 | 48 | { |
51 | 48 | (void)av; |
52 | 48 | (void)friend_number; |
53 | 48 | (void)width; |
54 | 48 | (void)height; |
55 | 48 | (void)y; |
56 | 48 | (void)u; |
57 | 48 | (void)v; |
58 | 48 | (void)ystride; |
59 | 48 | (void)ustride; |
60 | 48 | (void)vstride; |
61 | 48 | (void)user_data; |
62 | 48 | } |
63 | | |
64 | | static void alice_script(ToxNode *self, void *ctx) |
65 | 1 | { |
66 | 1 | CallState *state = (CallState *)ctx; |
67 | 1 | Tox *tox = tox_node_get_tox(self); |
68 | 1 | Toxav_Err_New av_err; |
69 | 1 | ToxAV *av = toxav_new(tox, &av_err); |
70 | 1 | ck_assert(av_err == TOXAV_ERR_NEW_OK); |
71 | | |
72 | 1 | toxav_callback_call(av, on_call, self); |
73 | 1 | toxav_callback_call_state(av, on_call_state, self); |
74 | 1 | toxav_callback_audio_receive_frame(av, on_audio_receive, self); |
75 | 1 | toxav_callback_video_receive_frame(av, on_video_receive, self); |
76 | | |
77 | 1 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
78 | 1 | WAIT_UNTIL(tox_node_is_friend_connected(self, 0)); |
79 | | |
80 | | // 1. Regular AV call - Alice calls, Bob answers, Bob hangs up |
81 | 1 | tox_node_log(self, "--- Starting Regular AV Call ---"); |
82 | 1 | state->state = 0; |
83 | 1 | Toxav_Err_Call call_err; |
84 | 1 | toxav_call(av, 0, 48, 4000, &call_err); |
85 | 1 | ck_assert(call_err == TOXAV_ERR_CALL_OK); |
86 | | |
87 | 1 | WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED); |
88 | 1 | tox_node_log(self, "Regular AV Call finished (state=%u)", state->state); |
89 | | |
90 | 1 | tox_scenario_barrier_wait(self); |
91 | | |
92 | | // 2. Reject flow - Alice calls, Bob rejects |
93 | 1 | tox_node_log(self, "--- Starting Reject Flow ---"); |
94 | 1 | state->state = 0; |
95 | 1 | toxav_call(av, 0, 48, 0, &call_err); |
96 | 1 | ck_assert(call_err == TOXAV_ERR_CALL_OK); |
97 | | |
98 | 1 | WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED); |
99 | 1 | tox_node_log(self, "Reject Flow finished"); |
100 | | |
101 | 1 | tox_scenario_barrier_wait(self); |
102 | | |
103 | | // 3. Cancel flow - Alice calls, Alice cancels |
104 | 1 | tox_node_log(self, "--- Starting Cancel Flow ---"); |
105 | 1 | state->state = 0; |
106 | 1 | toxav_call(av, 0, 48, 0, &call_err); |
107 | 1 | ck_assert(call_err == TOXAV_ERR_CALL_OK); |
108 | | |
109 | | // Wait for Bob to see it ringing |
110 | 1 | tox_scenario_barrier_wait(self); |
111 | | |
112 | 1 | tox_node_log(self, "Alice: Canceling call..."); |
113 | 1 | Toxav_Err_Call_Control cc_err; |
114 | 1 | toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err); |
115 | 1 | ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK); |
116 | | |
117 | | // Alice doesn't receive FINISHED state when SHE cancels |
118 | 1 | tox_node_log(self, "Alice: Cancel Flow finished"); |
119 | | |
120 | 1 | tox_scenario_barrier_wait(self); |
121 | | |
122 | 1 | toxav_kill(av); |
123 | 1 | } |
124 | | |
125 | | static void bob_script(ToxNode *self, void *ctx) |
126 | 1 | { |
127 | 1 | CallState *state = (CallState *)ctx; |
128 | 1 | Tox *tox = tox_node_get_tox(self); |
129 | 1 | Toxav_Err_New av_err; |
130 | 1 | ToxAV *av = toxav_new(tox, &av_err); |
131 | 1 | ck_assert(av_err == TOXAV_ERR_NEW_OK); |
132 | | |
133 | 1 | toxav_callback_call(av, on_call, self); |
134 | 1 | toxav_callback_call_state(av, on_call_state, self); |
135 | 1 | toxav_callback_audio_receive_frame(av, on_audio_receive, self); |
136 | 1 | toxav_callback_video_receive_frame(av, on_video_receive, self); |
137 | | |
138 | 1 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
139 | 1 | WAIT_UNTIL(tox_node_is_friend_connected(self, 0)); |
140 | | |
141 | | // 1. Regular AV call - Bob answers, then hangs up |
142 | 1 | WAIT_UNTIL_AV(av, state->incoming); |
143 | 1 | state->incoming = false; |
144 | 1 | Toxav_Err_Answer answer_err; |
145 | 1 | toxav_answer(av, 0, 48, 4000, &answer_err); |
146 | 1 | ck_assert(answer_err == TOXAV_ERR_ANSWER_OK); |
147 | | |
148 | | // Wait a bit and hang up |
149 | 11 | for (int i = 0; i < 10; i++) { |
150 | 10 | toxav_iterate(av); |
151 | 10 | tox_scenario_yield(self); |
152 | 10 | } |
153 | 1 | tox_node_log(self, "Bob: Hanging up..."); |
154 | 1 | Toxav_Err_Call_Control cc_err; |
155 | 1 | toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err); |
156 | 1 | ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK); |
157 | | |
158 | 1 | tox_scenario_barrier_wait(self); |
159 | | |
160 | | // 2. Reject flow - Bob rejects |
161 | 1 | WAIT_UNTIL_AV(av, state->incoming); |
162 | 1 | state->incoming = false; |
163 | 1 | tox_node_log(self, "Bob: Rejecting call..."); |
164 | 1 | toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err); |
165 | 1 | ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK); |
166 | | |
167 | 1 | tox_scenario_barrier_wait(self); |
168 | | |
169 | | // 3. Cancel flow - Alice cancels |
170 | 1 | WAIT_UNTIL_AV(av, state->incoming); |
171 | 1 | state->incoming = false; |
172 | 1 | tox_scenario_barrier_wait(self); // Alice will now cancel |
173 | | |
174 | 1 | WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED); |
175 | 1 | tox_node_log(self, "Bob: Cancel Flow finished (Alice canceled)"); |
176 | | |
177 | 1 | tox_scenario_barrier_wait(self); |
178 | | |
179 | 1 | toxav_kill(av); |
180 | 1 | } |
181 | | |
182 | | int main(int argc, char *argv[]) |
183 | 1 | { |
184 | 1 | ToxScenario *s = tox_scenario_new(argc, argv, 60000); |
185 | | |
186 | 1 | CallState alice_state = {0}; |
187 | 1 | CallState bob_state = {0}; |
188 | | |
189 | 1 | Tox_Options *opts = tox_options_new(nullptr); |
190 | 1 | tox_options_set_ipv6_enabled(opts, false); |
191 | 1 | tox_options_set_local_discovery_enabled(opts, false); |
192 | | |
193 | 1 | ToxNode *alice = tox_scenario_add_node_ex(s, "Alice", alice_script, &alice_state, sizeof(CallState), opts); |
194 | 1 | ToxNode *bob = tox_scenario_add_node_ex(s, "Bob", bob_script, &bob_state, sizeof(CallState), opts); |
195 | | |
196 | 1 | tox_options_free(opts); |
197 | | |
198 | 1 | tox_node_bootstrap(bob, alice); |
199 | 1 | tox_node_friend_add(alice, bob); |
200 | 1 | tox_node_friend_add(bob, alice); |
201 | | |
202 | 1 | ToxScenarioStatus res = tox_scenario_run(s); |
203 | 1 | tox_scenario_free(s); |
204 | 1 | return (res == TOX_SCENARIO_DONE) ? 0 : 1; |
205 | 1 | } |