Coverage Report

Created: 2024-01-26 01:52

/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
}