/work/auto_tests/toxav_many_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <stdint.h> |
2 | | #include <stdio.h> |
3 | | #include <stdlib.h> |
4 | | #include <string.h> |
5 | | #include <sys/types.h> |
6 | | #include <time.h> |
7 | | |
8 | | #if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) |
9 | | #include <pthread.h> |
10 | | #endif |
11 | | |
12 | | #include <vpx/vpx_image.h> |
13 | | |
14 | | #include "../testing/misc_tools.h" |
15 | | #include "../toxav/toxav.h" |
16 | | #include "../toxcore/crypto_core.h" |
17 | | #include "../toxcore/logger.h" |
18 | | #include "../toxcore/tox.h" |
19 | | #include "../toxcore/tox_struct.h" |
20 | | #include "../toxcore/util.h" |
21 | | #include "auto_test_support.h" |
22 | | #include "check_compat.h" |
23 | | |
24 | | typedef struct CallControl { |
25 | | bool incoming; |
26 | | uint32_t state; |
27 | | } CallControl; |
28 | | |
29 | | typedef struct Thread_Data { |
30 | | ToxAV *alice_av; |
31 | | ToxAV *bob_av; |
32 | | CallControl *alice_cc; |
33 | | CallControl *bob_cc; |
34 | | uint32_t friend_number; |
35 | | } Thread_Data; |
36 | | |
37 | | /** |
38 | | * Callbacks |
39 | | */ |
40 | | static void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) |
41 | 11 | { |
42 | 11 | printf("Handling CALL callback\n"); |
43 | 11 | ((CallControl *)user_data)[friend_number].incoming = true; |
44 | 11 | } |
45 | | |
46 | | static void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) |
47 | 33 | { |
48 | 33 | printf("Handling CALL STATE callback: %u %p\n", state, (void *)av); |
49 | 33 | ((CallControl *)user_data)[friend_number].state = state; |
50 | 33 | } |
51 | | |
52 | | static void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, |
53 | | uint16_t width, uint16_t height, |
54 | | uint8_t const *y, uint8_t const *u, uint8_t const *v, |
55 | | int32_t ystride, int32_t ustride, int32_t vstride, |
56 | | void *user_data) |
57 | 126 | { |
58 | 126 | } |
59 | | |
60 | | static void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, |
61 | | int16_t const *pcm, |
62 | | size_t sample_count, |
63 | | uint8_t channels, |
64 | | uint32_t sampling_rate, |
65 | | void *user_data) |
66 | 131 | { |
67 | 131 | } |
68 | | |
69 | | static void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, |
70 | | void *userdata) |
71 | 4 | { |
72 | 4 | if (length == 7 && memcmp("gentoo", data, 7) == 0) { |
73 | 4 | ck_assert(tox_friend_add_norequest(m, public_key, nullptr) != (uint32_t) -1); |
74 | 4 | } |
75 | 4 | } |
76 | | |
77 | | |
78 | | /** |
79 | | * Iterate helper |
80 | | */ |
81 | | static ToxAV *setup_av_instance(Tox *tox, CallControl *cc) |
82 | 4 | { |
83 | 4 | Toxav_Err_New error; |
84 | | |
85 | 4 | ToxAV *av = toxav_new(tox, &error); |
86 | 4 | ck_assert(error == TOXAV_ERR_NEW_OK); |
87 | | |
88 | 4 | toxav_callback_call(av, t_toxav_call_cb, cc); |
89 | 4 | toxav_callback_call_state(av, t_toxav_call_state_cb, cc); |
90 | 4 | toxav_callback_video_receive_frame(av, t_toxav_receive_video_frame_cb, cc); |
91 | 4 | toxav_callback_audio_receive_frame(av, t_toxav_receive_audio_frame_cb, cc); |
92 | | |
93 | 4 | return av; |
94 | 4 | } |
95 | | |
96 | | static void *call_thread(void *pd) |
97 | 3 | { |
98 | 3 | ToxAV *alice_av = ((Thread_Data *) pd)->alice_av; |
99 | 3 | ToxAV *bob_av = ((Thread_Data *) pd)->bob_av; |
100 | 3 | uint32_t friend_number = ((Thread_Data *) pd)->friend_number; |
101 | | |
102 | 3 | int16_t *pcm = (int16_t *)calloc(960, sizeof(int16_t)); |
103 | 3 | uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t)); |
104 | 3 | uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
105 | 3 | uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
106 | | |
107 | 3 | time_t start_time = time(nullptr); |
108 | | |
109 | 507 | do { |
110 | 507 | toxav_iterate(alice_av); |
111 | 507 | toxav_iterate(bob_av); |
112 | | |
113 | 507 | toxav_audio_send_frame(alice_av, friend_number, pcm, 960, 1, 48000, nullptr); |
114 | 507 | toxav_audio_send_frame(bob_av, 0, pcm, 960, 1, 48000, nullptr); |
115 | | |
116 | 507 | toxav_video_send_frame(alice_av, friend_number, 800, 600, video_y, video_u, video_v, nullptr); |
117 | 507 | toxav_video_send_frame(bob_av, 0, 800, 600, video_y, video_u, video_v, nullptr); |
118 | | |
119 | 507 | c_sleep(10); |
120 | 507 | } while (time(nullptr) - start_time < 4); |
121 | | |
122 | 3 | free(pcm); |
123 | 3 | free(video_y); |
124 | 3 | free(video_u); |
125 | 3 | free(video_v); |
126 | | |
127 | 3 | printf("Closing thread\n"); |
128 | 3 | pthread_exit(nullptr); |
129 | | |
130 | 0 | return nullptr; |
131 | 3 | } |
132 | | |
133 | | typedef struct Time_Data { |
134 | | pthread_mutex_t lock; |
135 | | uint64_t clock; |
136 | | } Time_Data; |
137 | | |
138 | | static uint64_t get_state_clock_callback(void *user_data) |
139 | 463k | { |
140 | 463k | Time_Data *time_data = (Time_Data *)user_data; |
141 | 463k | pthread_mutex_lock(&time_data->lock); |
142 | 463k | uint64_t clock = time_data->clock; |
143 | 463k | pthread_mutex_unlock(&time_data->lock); |
144 | 463k | return clock; |
145 | 463k | } |
146 | | |
147 | | static void increment_clock(Time_Data *time_data, uint64_t count) |
148 | 2.23k | { |
149 | 2.23k | pthread_mutex_lock(&time_data->lock); |
150 | 2.23k | time_data->clock += count; |
151 | 2.23k | pthread_mutex_unlock(&time_data->lock); |
152 | 2.23k | } |
153 | | |
154 | | static void set_current_time_callback(Tox *tox, Time_Data *time_data) |
155 | 8 | { |
156 | 8 | Mono_Time *mono_time = tox->mono_time; |
157 | 8 | mono_time_set_current_time_callback(mono_time, get_state_clock_callback, time_data); |
158 | 8 | } |
159 | | |
160 | | static void test_av_three_calls(void) |
161 | 1 | { |
162 | 1 | uint32_t index[] = { 1, 2, 3, 4, 5 }; |
163 | 1 | Tox *alice, *bootstrap, *bobs[3]; |
164 | 1 | ToxAV *alice_av, *bobs_av[3]; |
165 | 1 | void *retval; |
166 | | |
167 | 1 | CallControl alice_cc[3], bobs_cc[3]; |
168 | | |
169 | 1 | Time_Data time_data; |
170 | 1 | pthread_mutex_init(&time_data.lock, nullptr); |
171 | 1 | { |
172 | 1 | Tox_Err_New error; |
173 | | |
174 | 1 | bootstrap = tox_new_log(nullptr, &error, &index[0]); |
175 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
176 | | |
177 | 1 | time_data.clock = current_time_monotonic(bootstrap->mono_time); |
178 | 1 | set_current_time_callback(bootstrap, &time_data); |
179 | | |
180 | 1 | alice = tox_new_log(nullptr, &error, &index[1]); |
181 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
182 | 1 | set_current_time_callback(alice, &time_data); |
183 | | |
184 | 1 | bobs[0] = tox_new_log(nullptr, &error, &index[2]); |
185 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
186 | 1 | set_current_time_callback(bobs[0], &time_data); |
187 | | |
188 | 1 | bobs[1] = tox_new_log(nullptr, &error, &index[3]); |
189 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
190 | 1 | set_current_time_callback(bobs[1], &time_data); |
191 | | |
192 | 1 | bobs[2] = tox_new_log(nullptr, &error, &index[4]); |
193 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
194 | 1 | set_current_time_callback(bobs[2], &time_data); |
195 | 1 | } |
196 | | |
197 | 0 | printf("Created 5 instances of Tox\n"); |
198 | 1 | printf("Preparing network...\n"); |
199 | 1 | time_t cur_time = time(nullptr); |
200 | | |
201 | 1 | uint8_t address[TOX_ADDRESS_SIZE]; |
202 | | |
203 | 1 | tox_callback_friend_request(alice, t_accept_friend_request_cb); |
204 | 1 | tox_self_get_address(alice, address); |
205 | | |
206 | 1 | printf("bootstrapping Alice and the %u Bobs off a third bootstrap node\n", |
207 | 1 | (unsigned)(sizeof(bobs) / sizeof(bobs[0]))); |
208 | 1 | uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; |
209 | 1 | tox_self_get_dht_id(bootstrap, dht_key); |
210 | 1 | const uint16_t dht_port = tox_self_get_udp_port(bootstrap, nullptr); |
211 | | |
212 | 1 | tox_bootstrap(alice, "localhost", dht_port, dht_key, nullptr); |
213 | 1 | tox_bootstrap(bobs[0], "localhost", dht_port, dht_key, nullptr); |
214 | 1 | tox_bootstrap(bobs[1], "localhost", dht_port, dht_key, nullptr); |
215 | 1 | tox_bootstrap(bobs[2], "localhost", dht_port, dht_key, nullptr); |
216 | | |
217 | 1 | ck_assert(tox_friend_add(bobs[0], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); |
218 | 1 | ck_assert(tox_friend_add(bobs[1], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); |
219 | 1 | ck_assert(tox_friend_add(bobs[2], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); |
220 | | |
221 | 1 | uint8_t off = 1; |
222 | | |
223 | 50 | while (true) { |
224 | 50 | tox_iterate(bootstrap, nullptr); |
225 | 50 | tox_iterate(alice, nullptr); |
226 | 50 | tox_iterate(bobs[0], nullptr); |
227 | 50 | tox_iterate(bobs[1], nullptr); |
228 | 50 | tox_iterate(bobs[2], nullptr); |
229 | | |
230 | 50 | if (tox_self_get_connection_status(bootstrap) && |
231 | 50 | tox_self_get_connection_status(alice) && |
232 | 50 | tox_self_get_connection_status(bobs[0]) && |
233 | 50 | tox_self_get_connection_status(bobs[1]) && |
234 | 50 | tox_self_get_connection_status(bobs[2]) && off) { |
235 | 1 | printf("Toxes are online, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); |
236 | 1 | off = 0; |
237 | 1 | } |
238 | | |
239 | 50 | if (tox_friend_get_connection_status(alice, 0, nullptr) == TOX_CONNECTION_UDP && |
240 | 50 | tox_friend_get_connection_status(alice, 1, nullptr) == TOX_CONNECTION_UDP && |
241 | 50 | tox_friend_get_connection_status(alice, 2, nullptr) == TOX_CONNECTION_UDP && |
242 | 50 | tox_friend_get_connection_status(bobs[0], 0, nullptr) == TOX_CONNECTION_UDP && |
243 | 50 | tox_friend_get_connection_status(bobs[1], 0, nullptr) == TOX_CONNECTION_UDP && |
244 | 50 | tox_friend_get_connection_status(bobs[2], 0, nullptr) == TOX_CONNECTION_UDP) { |
245 | 1 | break; |
246 | 1 | } |
247 | | |
248 | 49 | increment_clock(&time_data, 200); |
249 | 49 | c_sleep(5); |
250 | 49 | } |
251 | | |
252 | 1 | alice_av = setup_av_instance(alice, alice_cc); |
253 | 1 | bobs_av[0] = setup_av_instance(bobs[0], &bobs_cc[0]); |
254 | 1 | bobs_av[1] = setup_av_instance(bobs[1], &bobs_cc[1]); |
255 | 1 | bobs_av[2] = setup_av_instance(bobs[2], &bobs_cc[2]); |
256 | | |
257 | 1 | printf("Created 4 instances of ToxAV\n"); |
258 | 1 | printf("All set after %lu seconds!\n", (unsigned long)(time(nullptr) - cur_time)); |
259 | | |
260 | 1 | Thread_Data tds[3]; |
261 | | |
262 | 4 | for (size_t i = 0; i < 3; i++) { |
263 | 3 | tds[i].alice_av = alice_av; |
264 | 3 | tds[i].bob_av = bobs_av[i]; |
265 | 3 | tds[i].alice_cc = &alice_cc[i]; |
266 | 3 | tds[i].bob_cc = &bobs_cc[i]; |
267 | 3 | tds[i].friend_number = i; |
268 | 3 | memset(tds[i].alice_cc, 0, sizeof(CallControl)); |
269 | 3 | memset(tds[i].bob_cc, 0, sizeof(CallControl)); |
270 | 3 | } |
271 | | |
272 | 1 | pthread_t tids[3]; |
273 | | |
274 | 4 | for (size_t i = 0; i < 3; i++) { |
275 | 3 | (void) pthread_create(&tids[i], nullptr, call_thread, &tds[i]); |
276 | 3 | } |
277 | | |
278 | 1 | time_t start_time = time(nullptr); |
279 | | |
280 | 74 | do { |
281 | 74 | tox_iterate(bootstrap, nullptr); |
282 | 74 | tox_iterate(alice, nullptr); |
283 | 74 | tox_iterate(bobs[0], nullptr); |
284 | 74 | tox_iterate(bobs[1], nullptr); |
285 | 74 | tox_iterate(bobs[2], nullptr); |
286 | | |
287 | 74 | increment_clock(&time_data, 100); |
288 | 74 | c_sleep(5); |
289 | 74 | } while (time(nullptr) - start_time < 1); |
290 | | |
291 | | /* Call */ |
292 | 4 | for (size_t i = 0; i < 3; i++) { |
293 | 3 | Toxav_Err_Call rc; |
294 | 3 | toxav_call(alice_av, tds[i].friend_number, 48, 3000, &rc); |
295 | | |
296 | 3 | if (rc != TOXAV_ERR_CALL_OK) { |
297 | 0 | printf("toxav_call failed: %d\n", rc); |
298 | 0 | ck_assert(0); |
299 | 0 | } |
300 | 3 | } |
301 | | |
302 | | |
303 | 84 | do { |
304 | 84 | tox_iterate(bootstrap, nullptr); |
305 | 84 | tox_iterate(alice, nullptr); |
306 | 84 | tox_iterate(bobs[0], nullptr); |
307 | 84 | tox_iterate(bobs[1], nullptr); |
308 | 84 | tox_iterate(bobs[2], nullptr); |
309 | | |
310 | 336 | for (size_t i = 0; i < 3; i++) { |
311 | 252 | if (bobs_cc[i].incoming) { |
312 | | /* Answer */ |
313 | 3 | Toxav_Err_Answer rc; |
314 | 3 | toxav_answer(bobs_av[i], 0, 8, 500, &rc); |
315 | | |
316 | 3 | if (rc != TOXAV_ERR_ANSWER_OK) { |
317 | 0 | printf("toxav_answer failed: %d\n", rc); |
318 | 0 | ck_assert(0); |
319 | 0 | } |
320 | | |
321 | 3 | bobs_cc[i].incoming = false; |
322 | 3 | } |
323 | 252 | } |
324 | | |
325 | 84 | increment_clock(&time_data, 100); |
326 | 84 | c_sleep(5); |
327 | 84 | } while (time(nullptr) - start_time < 3); |
328 | | |
329 | | /* Hangup */ |
330 | 4 | for (size_t i = 0; i < 3; i++) { |
331 | 3 | Toxav_Err_Call_Control rc; |
332 | 3 | toxav_call_control(alice_av, i, TOXAV_CALL_CONTROL_CANCEL, &rc); |
333 | | |
334 | 3 | if (rc != TOXAV_ERR_CALL_CONTROL_OK) { |
335 | 0 | printf("toxav_call_control failed: %d %p %p\n", rc, (void *)alice_av, (void *)&bobs_av[i]); |
336 | 0 | } |
337 | 3 | } |
338 | | |
339 | 253 | do { |
340 | 253 | tox_iterate(bootstrap, nullptr); |
341 | 253 | tox_iterate(alice, nullptr); |
342 | 253 | tox_iterate(bobs[0], nullptr); |
343 | 253 | tox_iterate(bobs[1], nullptr); |
344 | 253 | tox_iterate(bobs[2], nullptr); |
345 | | |
346 | 253 | increment_clock(&time_data, 100); |
347 | 253 | c_sleep(5); |
348 | 253 | } while (time(nullptr) - start_time < 5); |
349 | | |
350 | 1 | ck_assert(pthread_join(tids[0], &retval) == 0); |
351 | 1 | ck_assert(retval == nullptr); |
352 | | |
353 | 1 | ck_assert(pthread_join(tids[1], &retval) == 0); |
354 | 1 | ck_assert(retval == nullptr); |
355 | | |
356 | 1 | ck_assert(pthread_join(tids[2], &retval) == 0); |
357 | 1 | ck_assert(retval == nullptr); |
358 | | |
359 | 1 | printf("Killing all instances\n"); |
360 | 1 | toxav_kill(bobs_av[2]); |
361 | 1 | toxav_kill(bobs_av[1]); |
362 | 1 | toxav_kill(bobs_av[0]); |
363 | 1 | toxav_kill(alice_av); |
364 | 1 | tox_kill(bobs[2]); |
365 | 1 | tox_kill(bobs[1]); |
366 | 1 | tox_kill(bobs[0]); |
367 | 1 | tox_kill(alice); |
368 | 1 | tox_kill(bootstrap); |
369 | | |
370 | 1 | pthread_mutex_destroy(&time_data.lock); |
371 | | |
372 | 1 | printf("\nTest successful!\n"); |
373 | 1 | } |
374 | | |
375 | | int main(void) |
376 | 721 | { |
377 | 721 | setvbuf(stdout, nullptr, _IONBF, 0); |
378 | | |
379 | 721 | test_av_three_calls(); |
380 | 721 | return 0; |
381 | 721 | } |