/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 | 94 | { |
58 | 94 | } |
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 | 98 | { |
67 | 98 | } |
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 | | * Iterate helper |
79 | | */ |
80 | | static ToxAV *setup_av_instance(Tox *tox, CallControl *cc) |
81 | 4 | { |
82 | 4 | Toxav_Err_New error; |
83 | | |
84 | 4 | ToxAV *av = toxav_new(tox, &error); |
85 | 4 | ck_assert(error == TOXAV_ERR_NEW_OK); |
86 | | |
87 | 4 | toxav_callback_call(av, t_toxav_call_cb, cc); |
88 | 4 | toxav_callback_call_state(av, t_toxav_call_state_cb, cc); |
89 | 4 | toxav_callback_video_receive_frame(av, t_toxav_receive_video_frame_cb, cc); |
90 | 4 | toxav_callback_audio_receive_frame(av, t_toxav_receive_audio_frame_cb, cc); |
91 | | |
92 | 4 | return av; |
93 | 4 | } |
94 | | |
95 | | static void *call_thread(void *pd) |
96 | 3 | { |
97 | 3 | ToxAV *alice_av = ((Thread_Data *) pd)->alice_av; |
98 | 3 | ToxAV *bob_av = ((Thread_Data *) pd)->bob_av; |
99 | 3 | uint32_t friend_number = ((Thread_Data *) pd)->friend_number; |
100 | | |
101 | 3 | int16_t *pcm = (int16_t *)calloc(960, sizeof(int16_t)); |
102 | 3 | uint8_t *video_y = (uint8_t *)calloc(800 * 600, sizeof(uint8_t)); |
103 | 3 | uint8_t *video_u = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
104 | 3 | uint8_t *video_v = (uint8_t *)calloc(800 * 600 / 4, sizeof(uint8_t)); |
105 | | |
106 | 3 | time_t start_time = time(nullptr); |
107 | | |
108 | 504 | do { |
109 | 504 | toxav_iterate(alice_av); |
110 | 504 | toxav_iterate(bob_av); |
111 | | |
112 | 504 | toxav_audio_send_frame(alice_av, friend_number, pcm, 960, 1, 48000, nullptr); |
113 | 504 | toxav_audio_send_frame(bob_av, 0, pcm, 960, 1, 48000, nullptr); |
114 | | |
115 | 504 | toxav_video_send_frame(alice_av, friend_number, 800, 600, video_y, video_u, video_v, nullptr); |
116 | 504 | toxav_video_send_frame(bob_av, 0, 800, 600, video_y, video_u, video_v, nullptr); |
117 | | |
118 | 504 | c_sleep(10); |
119 | 504 | } while (time(nullptr) - start_time < 4); |
120 | | |
121 | 3 | free(pcm); |
122 | 3 | free(video_y); |
123 | 3 | free(video_u); |
124 | 3 | free(video_v); |
125 | | |
126 | 3 | printf("Closing thread\n"); |
127 | 3 | pthread_exit(nullptr); |
128 | | |
129 | 0 | return nullptr; |
130 | 3 | } |
131 | | |
132 | | typedef struct Time_Data { |
133 | | pthread_mutex_t lock; |
134 | | uint64_t clock; |
135 | | } Time_Data; |
136 | | |
137 | | static uint64_t get_state_clock_callback(void *user_data) |
138 | 442k | { |
139 | 442k | Time_Data *time_data = (Time_Data *)user_data; |
140 | 442k | pthread_mutex_lock(&time_data->lock); |
141 | 442k | uint64_t clock = time_data->clock; |
142 | 442k | pthread_mutex_unlock(&time_data->lock); |
143 | 442k | return clock; |
144 | 442k | } |
145 | | |
146 | | static void increment_clock(Time_Data *time_data, uint64_t count) |
147 | 2.01k | { |
148 | 2.01k | pthread_mutex_lock(&time_data->lock); |
149 | 2.01k | time_data->clock += count; |
150 | 2.01k | pthread_mutex_unlock(&time_data->lock); |
151 | 2.01k | } |
152 | | |
153 | | static void set_current_time_callback(Tox *tox, Time_Data *time_data) |
154 | 8 | { |
155 | 8 | Mono_Time *mono_time = tox->mono_time; |
156 | 8 | mono_time_set_current_time_callback(mono_time, get_state_clock_callback, time_data); |
157 | 8 | } |
158 | | |
159 | | static void test_av_three_calls(void) |
160 | 1 | { |
161 | 1 | uint32_t index[] = { 1, 2, 3, 4, 5 }; |
162 | 1 | Tox *alice, *bootstrap, *bobs[3]; |
163 | 1 | ToxAV *alice_av, *bobs_av[3]; |
164 | 1 | void *retval; |
165 | | |
166 | 1 | CallControl alice_cc[3], bobs_cc[3]; |
167 | | |
168 | 1 | Time_Data time_data; |
169 | 1 | pthread_mutex_init(&time_data.lock, nullptr); |
170 | 1 | { |
171 | 1 | Tox_Options *opts = tox_options_new(nullptr); |
172 | 1 | ck_assert(opts != nullptr); |
173 | 1 | tox_options_set_experimental_thread_safety(opts, true); |
174 | 1 | Tox_Err_New error; |
175 | | |
176 | 1 | bootstrap = tox_new_log(opts, &error, &index[0]); |
177 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
178 | | |
179 | 1 | time_data.clock = current_time_monotonic(bootstrap->mono_time); |
180 | 1 | set_current_time_callback(bootstrap, &time_data); |
181 | | |
182 | 1 | alice = tox_new_log(opts, &error, &index[1]); |
183 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
184 | 1 | set_current_time_callback(alice, &time_data); |
185 | | |
186 | 1 | bobs[0] = tox_new_log(opts, &error, &index[2]); |
187 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
188 | 1 | set_current_time_callback(bobs[0], &time_data); |
189 | | |
190 | 1 | bobs[1] = tox_new_log(opts, &error, &index[3]); |
191 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
192 | 1 | set_current_time_callback(bobs[1], &time_data); |
193 | | |
194 | 1 | bobs[2] = tox_new_log(opts, &error, &index[4]); |
195 | 1 | ck_assert(error == TOX_ERR_NEW_OK); |
196 | 1 | set_current_time_callback(bobs[2], &time_data); |
197 | 1 | tox_options_free(opts); |
198 | 1 | } |
199 | | |
200 | 0 | printf("Created 5 instances of Tox\n"); |
201 | 1 | printf("Preparing network...\n"); |
202 | 1 | time_t cur_time = time(nullptr); |
203 | | |
204 | 1 | uint8_t address[TOX_ADDRESS_SIZE]; |
205 | | |
206 | 1 | tox_callback_friend_request(alice, t_accept_friend_request_cb); |
207 | 1 | tox_self_get_address(alice, address); |
208 | | |
209 | 1 | printf("bootstrapping Alice and the %u Bobs off a third bootstrap node\n", |
210 | 1 | (unsigned)(sizeof(bobs) / sizeof(bobs[0]))); |
211 | 1 | uint8_t dht_key[TOX_PUBLIC_KEY_SIZE]; |
212 | 1 | tox_self_get_dht_id(bootstrap, dht_key); |
213 | 1 | const uint16_t dht_port = tox_self_get_udp_port(bootstrap, nullptr); |
214 | | |
215 | 1 | tox_bootstrap(alice, "localhost", dht_port, dht_key, nullptr); |
216 | 1 | tox_bootstrap(bobs[0], "localhost", dht_port, dht_key, nullptr); |
217 | 1 | tox_bootstrap(bobs[1], "localhost", dht_port, dht_key, nullptr); |
218 | 1 | tox_bootstrap(bobs[2], "localhost", dht_port, dht_key, nullptr); |
219 | | |
220 | 1 | ck_assert(tox_friend_add(bobs[0], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); |
221 | 1 | ck_assert(tox_friend_add(bobs[1], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); |
222 | 1 | ck_assert(tox_friend_add(bobs[2], address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1); |
223 | | |
224 | 1 | uint8_t off = 1; |
225 | | |
226 | 50 | while (true) { |
227 | 50 | tox_iterate(bootstrap, nullptr); |
228 | 50 | tox_iterate(alice, nullptr); |
229 | 50 | tox_iterate(bobs[0], nullptr); |
230 | 50 | tox_iterate(bobs[1], nullptr); |
231 | 50 | tox_iterate(bobs[2], nullptr); |
232 | | |
233 | 50 | if (tox_self_get_connection_status(bootstrap) && |
234 | 50 | tox_self_get_connection_status(alice) && |
235 | 50 | tox_self_get_connection_status(bobs[0]) && |
236 | 50 | tox_self_get_connection_status(bobs[1]) && |
237 | 50 | tox_self_get_connection_status(bobs[2]) && off) { |
238 | 1 | printf("Toxes are online, took %lu seconds\n", (unsigned long)(time(nullptr) - cur_time)); |
239 | 1 | off = 0; |
240 | 1 | } |
241 | | |
242 | 50 | if (tox_friend_get_connection_status(alice, 0, nullptr) == TOX_CONNECTION_UDP && |
243 | 50 | tox_friend_get_connection_status(alice, 1, nullptr) == TOX_CONNECTION_UDP && |
244 | 50 | tox_friend_get_connection_status(alice, 2, nullptr) == TOX_CONNECTION_UDP && |
245 | 50 | tox_friend_get_connection_status(bobs[0], 0, nullptr) == TOX_CONNECTION_UDP && |
246 | 50 | tox_friend_get_connection_status(bobs[1], 0, nullptr) == TOX_CONNECTION_UDP && |
247 | 50 | tox_friend_get_connection_status(bobs[2], 0, nullptr) == TOX_CONNECTION_UDP) { |
248 | 1 | break; |
249 | 1 | } |
250 | | |
251 | 49 | increment_clock(&time_data, 200); |
252 | 49 | c_sleep(5); |
253 | 49 | } |
254 | | |
255 | 1 | alice_av = setup_av_instance(alice, alice_cc); |
256 | 1 | bobs_av[0] = setup_av_instance(bobs[0], &bobs_cc[0]); |
257 | 1 | bobs_av[1] = setup_av_instance(bobs[1], &bobs_cc[1]); |
258 | 1 | bobs_av[2] = setup_av_instance(bobs[2], &bobs_cc[2]); |
259 | | |
260 | 1 | printf("Created 4 instances of ToxAV\n"); |
261 | 1 | printf("All set after %lu seconds!\n", (unsigned long)(time(nullptr) - cur_time)); |
262 | | |
263 | 1 | Thread_Data tds[3]; |
264 | | |
265 | 4 | for (size_t i = 0; i < 3; i++) { |
266 | 3 | tds[i].alice_av = alice_av; |
267 | 3 | tds[i].bob_av = bobs_av[i]; |
268 | 3 | tds[i].alice_cc = &alice_cc[i]; |
269 | 3 | tds[i].bob_cc = &bobs_cc[i]; |
270 | 3 | tds[i].friend_number = i; |
271 | 3 | memset(tds[i].alice_cc, 0, sizeof(CallControl)); |
272 | 3 | memset(tds[i].bob_cc, 0, sizeof(CallControl)); |
273 | 3 | } |
274 | | |
275 | 1 | pthread_t tids[3]; |
276 | | |
277 | 4 | for (size_t i = 0; i < 3; i++) { |
278 | 3 | (void) pthread_create(&tids[i], nullptr, call_thread, &tds[i]); |
279 | 3 | } |
280 | | |
281 | 1 | time_t start_time = time(nullptr); |
282 | | |
283 | 56 | do { |
284 | 56 | tox_iterate(bootstrap, nullptr); |
285 | 56 | tox_iterate(alice, nullptr); |
286 | 56 | tox_iterate(bobs[0], nullptr); |
287 | 56 | tox_iterate(bobs[1], nullptr); |
288 | 56 | tox_iterate(bobs[2], nullptr); |
289 | | |
290 | 56 | increment_clock(&time_data, 100); |
291 | 56 | c_sleep(5); |
292 | 56 | } while (time(nullptr) - start_time < 1); |
293 | | |
294 | | /* Call */ |
295 | 4 | for (size_t i = 0; i < 3; i++) { |
296 | 3 | Toxav_Err_Call rc; |
297 | 3 | toxav_call(alice_av, tds[i].friend_number, 48, 3000, &rc); |
298 | | |
299 | 3 | if (rc != TOXAV_ERR_CALL_OK) { |
300 | 0 | printf("toxav_call failed: %u\n", rc); |
301 | 0 | ck_assert(0); |
302 | 0 | } |
303 | 3 | } |
304 | | |
305 | 117 | do { |
306 | 117 | tox_iterate(bootstrap, nullptr); |
307 | 117 | tox_iterate(alice, nullptr); |
308 | 117 | tox_iterate(bobs[0], nullptr); |
309 | 117 | tox_iterate(bobs[1], nullptr); |
310 | 117 | tox_iterate(bobs[2], nullptr); |
311 | | |
312 | 468 | for (size_t i = 0; i < 3; i++) { |
313 | 351 | if (bobs_cc[i].incoming) { |
314 | | /* Answer */ |
315 | 3 | Toxav_Err_Answer rc; |
316 | 3 | toxav_answer(bobs_av[i], 0, 8, 500, &rc); |
317 | | |
318 | 3 | if (rc != TOXAV_ERR_ANSWER_OK) { |
319 | 0 | printf("toxav_answer failed: %u\n", rc); |
320 | 0 | ck_assert(0); |
321 | 0 | } |
322 | | |
323 | 3 | bobs_cc[i].incoming = false; |
324 | 3 | } |
325 | 351 | } |
326 | | |
327 | 117 | increment_clock(&time_data, 100); |
328 | 117 | c_sleep(5); |
329 | 117 | } while (time(nullptr) - start_time < 3); |
330 | | |
331 | | /* Hangup */ |
332 | 4 | for (size_t i = 0; i < 3; i++) { |
333 | 3 | Toxav_Err_Call_Control rc; |
334 | 3 | toxav_call_control(alice_av, i, TOXAV_CALL_CONTROL_CANCEL, &rc); |
335 | | |
336 | 3 | if (rc != TOXAV_ERR_CALL_CONTROL_OK) { |
337 | 0 | printf("toxav_call_control failed: %u %p %p\n", rc, (void *)alice_av, (void *)&bobs_av[i]); |
338 | 0 | } |
339 | 3 | } |
340 | | |
341 | 162 | do { |
342 | 162 | tox_iterate(bootstrap, nullptr); |
343 | 162 | tox_iterate(alice, nullptr); |
344 | 162 | tox_iterate(bobs[0], nullptr); |
345 | 162 | tox_iterate(bobs[1], nullptr); |
346 | 162 | tox_iterate(bobs[2], nullptr); |
347 | | |
348 | 162 | increment_clock(&time_data, 100); |
349 | 162 | c_sleep(5); |
350 | 162 | } while (time(nullptr) - start_time < 5); |
351 | | |
352 | 1 | ck_assert(pthread_join(tids[0], &retval) == 0); |
353 | 1 | ck_assert(retval == nullptr); |
354 | | |
355 | 1 | ck_assert(pthread_join(tids[1], &retval) == 0); |
356 | 1 | ck_assert(retval == nullptr); |
357 | | |
358 | 1 | ck_assert(pthread_join(tids[2], &retval) == 0); |
359 | 1 | ck_assert(retval == nullptr); |
360 | | |
361 | 1 | printf("Killing all instances\n"); |
362 | 1 | toxav_kill(bobs_av[2]); |
363 | 1 | toxav_kill(bobs_av[1]); |
364 | 1 | toxav_kill(bobs_av[0]); |
365 | 1 | toxav_kill(alice_av); |
366 | 1 | tox_kill(bobs[2]); |
367 | 1 | tox_kill(bobs[1]); |
368 | 1 | tox_kill(bobs[0]); |
369 | 1 | tox_kill(alice); |
370 | 1 | tox_kill(bootstrap); |
371 | | |
372 | 1 | pthread_mutex_destroy(&time_data.lock); |
373 | | |
374 | 1 | printf("\nTest successful!\n"); |
375 | 1 | } |
376 | | |
377 | | int main(void) |
378 | 545 | { |
379 | 545 | setvbuf(stdout, nullptr, _IONBF, 0); |
380 | | |
381 | 545 | test_av_three_calls(); |
382 | 545 | return 0; |
383 | 545 | } |