/work/auto_tests/scenarios/scenario_toxav_many_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 | 96 | #define NUM_BOBS 3 |
8 | | |
9 | | typedef struct { |
10 | | bool incoming; |
11 | | uint32_t state; |
12 | | } CallState; |
13 | | |
14 | | static void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) |
15 | 6 | { |
16 | 6 | ToxNode *self = (ToxNode *)user_data; |
17 | 6 | CallState *states = (CallState *)tox_node_get_script_ctx(self); |
18 | 6 | tox_node_log(self, "Received call from friend %u", friend_number); |
19 | 6 | states[friend_number].incoming = true; |
20 | 6 | } |
21 | | |
22 | | static void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) |
23 | 10 | { |
24 | 10 | ToxNode *self = (ToxNode *)user_data; |
25 | 10 | CallState *states = (CallState *)tox_node_get_script_ctx(self); |
26 | 10 | tox_node_log(self, "Call state for friend %u changed to %u", friend_number, state); |
27 | 10 | states[friend_number].state = state; |
28 | 10 | } |
29 | | |
30 | | static void on_audio_receive(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count, |
31 | | uint8_t channels, uint32_t sampling_rate, void *user_data) |
32 | 48 | { |
33 | 48 | } |
34 | | |
35 | | static void on_video_receive(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, |
36 | | uint8_t const *y, uint8_t const *u, uint8_t const *v, |
37 | | int32_t ystride, int32_t ustride, int32_t vstride, void *user_data) |
38 | 48 | { |
39 | 48 | } |
40 | | |
41 | | static void alice_script(ToxNode *self, void *ctx) |
42 | 1 | { |
43 | 1 | CallState *states = (CallState *)ctx; |
44 | 1 | Tox *tox = tox_node_get_tox(self); |
45 | 1 | Toxav_Err_New av_err; |
46 | 1 | ToxAV *av = toxav_new(tox, &av_err); |
47 | 1 | ck_assert(av_err == TOXAV_ERR_NEW_OK); |
48 | | |
49 | 1 | toxav_callback_call(av, on_call, self); |
50 | 1 | toxav_callback_call_state(av, on_call_state, self); |
51 | 1 | toxav_callback_audio_receive_frame(av, on_audio_receive, self); |
52 | 1 | toxav_callback_video_receive_frame(av, on_video_receive, self); |
53 | | |
54 | 1 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
55 | 4 | for (uint32_t i = 0; i < NUM_BOBS; i++) { |
56 | 3 | WAIT_UNTIL(tox_node_is_friend_connected(self, i)); |
57 | 3 | } |
58 | | |
59 | 1 | tox_node_log(self, "All Bobs connected. Calling them..."); |
60 | | |
61 | 4 | for (uint32_t i = 0; i < NUM_BOBS; i++) { |
62 | 3 | Toxav_Err_Call call_err; |
63 | 3 | toxav_call(av, i, 48, 3000, &call_err); |
64 | 3 | ck_assert(call_err == TOXAV_ERR_CALL_OK); |
65 | 3 | } |
66 | | |
67 | 1 | int16_t pcm[960] = {0}; |
68 | 1 | uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t)); |
69 | 1 | uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
70 | 1 | uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
71 | | |
72 | | // Send a few frames to verify flow |
73 | 21 | for (int i = 0; i < 20; i++) { |
74 | 20 | toxav_iterate(av); |
75 | 80 | for (uint32_t j = 0; j < NUM_BOBS; j++) { |
76 | 60 | if (states[j].state & TOXAV_FRIEND_CALL_STATE_SENDING_A) { |
77 | 48 | toxav_audio_send_frame(av, j, pcm, 960, 1, 48000, nullptr); |
78 | 48 | } |
79 | 60 | if (states[j].state & TOXAV_FRIEND_CALL_STATE_SENDING_V) { |
80 | 48 | toxav_video_send_frame(av, j, 800, 600, video_y, video_u, video_v, nullptr); |
81 | 48 | } |
82 | 60 | } |
83 | 20 | tox_scenario_yield(self); |
84 | 20 | } |
85 | | |
86 | 1 | tox_node_log(self, "Hanging up all calls..."); |
87 | 4 | for (uint32_t i = 0; i < NUM_BOBS; i++) { |
88 | 3 | toxav_call_control(av, i, TOXAV_CALL_CONTROL_CANCEL, nullptr); |
89 | 3 | } |
90 | | |
91 | | // Give it a few ticks to send hangup packets |
92 | 6 | for (int i = 0; i < 5; i++) { |
93 | 5 | toxav_iterate(av); |
94 | 5 | tox_scenario_yield(self); |
95 | 5 | } |
96 | | |
97 | 1 | free(video_y); |
98 | 1 | free(video_u); |
99 | 1 | free(video_v); |
100 | 1 | toxav_kill(av); |
101 | 1 | } |
102 | | |
103 | | static void bob_script(ToxNode *self, void *ctx) |
104 | 3 | { |
105 | 3 | CallState *states = (CallState *)ctx; |
106 | 3 | Tox *tox = tox_node_get_tox(self); |
107 | 3 | Toxav_Err_New av_err; |
108 | 3 | ToxAV *av = toxav_new(tox, &av_err); |
109 | 3 | ck_assert(av_err == TOXAV_ERR_NEW_OK); |
110 | | |
111 | 3 | toxav_callback_call(av, on_call, self); |
112 | 3 | toxav_callback_call_state(av, on_call_state, self); |
113 | 3 | toxav_callback_audio_receive_frame(av, on_audio_receive, self); |
114 | 3 | toxav_callback_video_receive_frame(av, on_video_receive, self); |
115 | | |
116 | 3 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
117 | 3 | WAIT_UNTIL(tox_node_is_friend_connected(self, 0)); |
118 | | |
119 | 16 | while (!states[0].incoming && tox_scenario_is_running(self)) { |
120 | 13 | toxav_iterate(av); |
121 | 13 | tox_scenario_yield(self); |
122 | 13 | } |
123 | | |
124 | 3 | tox_node_log(self, "Answering call..."); |
125 | 3 | Toxav_Err_Answer answer_err; |
126 | 3 | toxav_answer(av, 0, 8, 500, &answer_err); |
127 | 3 | ck_assert(answer_err == TOXAV_ERR_ANSWER_OK); |
128 | | |
129 | 3 | int16_t pcm[960] = {0}; |
130 | 3 | uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t)); |
131 | 3 | uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
132 | 3 | uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
133 | | |
134 | 63 | while (!(states[0].state & TOXAV_FRIEND_CALL_STATE_FINISHED) && tox_scenario_is_running(self)) { |
135 | 60 | toxav_iterate(av); |
136 | 60 | if (states[0].state & TOXAV_FRIEND_CALL_STATE_SENDING_A) { |
137 | 0 | toxav_audio_send_frame(av, 0, pcm, 960, 1, 48000, nullptr); |
138 | 0 | } |
139 | 60 | if (states[0].state & TOXAV_FRIEND_CALL_STATE_SENDING_V) { |
140 | 0 | toxav_video_send_frame(av, 0, 800, 600, video_y, video_u, video_v, nullptr); |
141 | 0 | } |
142 | 60 | tox_scenario_yield(self); |
143 | 60 | } |
144 | | |
145 | 3 | tox_node_log(self, "Call finished."); |
146 | | |
147 | 3 | free(video_y); |
148 | 3 | free(video_u); |
149 | 3 | free(video_v); |
150 | 3 | toxav_kill(av); |
151 | 3 | } |
152 | | |
153 | | int main(int argc, char *argv[]) |
154 | 1 | { |
155 | 1 | ToxScenario *s = tox_scenario_new(argc, argv, 60000); |
156 | | |
157 | 1 | CallState alice_states[NUM_BOBS] = {0}; |
158 | 1 | Tox_Options *opts = tox_options_new(nullptr); |
159 | 1 | tox_options_set_ipv6_enabled(opts, false); |
160 | 1 | tox_options_set_local_discovery_enabled(opts, false); |
161 | | |
162 | 1 | ToxNode *alice = tox_scenario_add_node_ex(s, "Alice", alice_script, alice_states, sizeof(alice_states), opts); |
163 | | |
164 | 1 | ToxNode *bobs[NUM_BOBS]; |
165 | 1 | CallState bob_states[NUM_BOBS]; |
166 | 4 | for (int i = 0; i < NUM_BOBS; i++) { |
167 | 3 | char name[32]; |
168 | 3 | snprintf(name, sizeof(name), "Bob-%d", i); |
169 | 3 | bob_states[i] = (CallState) { |
170 | 3 | 0 |
171 | 3 | }; |
172 | 3 | bobs[i] = tox_scenario_add_node_ex(s, name, bob_script, &bob_states[i], sizeof(CallState), opts); |
173 | | |
174 | 3 | tox_node_bootstrap(bobs[i], alice); |
175 | 3 | tox_node_friend_add(alice, bobs[i]); |
176 | 3 | tox_node_friend_add(bobs[i], alice); |
177 | 3 | } |
178 | | |
179 | 1 | tox_options_free(opts); |
180 | | |
181 | 1 | ToxScenarioStatus res = tox_scenario_run(s); |
182 | 1 | tox_scenario_free(s); |
183 | 1 | return (res == TOX_SCENARIO_DONE) ? 0 : 1; |
184 | 1 | } |