Coverage Report

Created: 2024-01-26 01:52

/work/auto_tests/toxav_basic_test.c
Line
Count
Source (jump to first uncovered line)
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <time.h>
5
6
#include <vpx/vpx_image.h>
7
8
#include "../testing/misc_tools.h"
9
#include "../toxav/toxav.h"
10
#include "../toxcore/crypto_core.h"
11
#include "../toxcore/logger.h"
12
#include "../toxcore/tox.h"
13
#include "../toxcore/util.h"
14
#include "auto_test_support.h"
15
#include "check_compat.h"
16
17
1
#define TEST_REGULAR_AV 1
18
1
#define TEST_REGULAR_A 1
19
1
#define TEST_REGULAR_V 1
20
1
#define TEST_REJECT 1
21
1
#define TEST_CANCEL 1
22
1
#define TEST_MUTE_UNMUTE 1
23
1
#define TEST_STOP_RESUME_PAYLOAD 1
24
1
#define TEST_PAUSE_RESUME_SEND 1
25
26
27
10
#define ck_assert_call_control(a, b, c) do { \
28
10
    Toxav_Err_Call_Control cc_err; \
29
10
    bool ok = toxav_call_control(a, b, c, &cc_err); \
30
10
    if (!ok) { \
31
0
        printf("toxav_call_control returned error %d\n", cc_err); \
32
0
    } \
33
10
    ck_assert(ok); \
34
10
    ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK); \
35
10
} while (0)
36
37
38
typedef struct {
39
    bool incoming;
40
    uint32_t state;
41
} CallControl;
42
43
static void clear_call_control(CallControl *cc)
44
16
{
45
16
    const CallControl empty = {0};
46
16
    *cc = empty;
47
16
}
48
49
50
/**
51
 * Callbacks
52
 */
53
static void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
54
11
{
55
11
    printf("Handling CALL callback\n");
56
11
    ((CallControl *)user_data)->incoming = true;
57
11
}
58
59
static void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
60
33
{
61
33
    printf("Handling CALL STATE callback: %u\n", state);
62
33
    ((CallControl *)user_data)->state = state;
63
33
}
64
65
static void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
66
        uint16_t width, uint16_t height,
67
        uint8_t const *y, uint8_t const *u, uint8_t const *v,
68
        int32_t ystride, int32_t ustride, int32_t vstride,
69
        void *user_data)
70
126
{
71
126
    printf("Received video payload\n");
72
126
}
73
74
static void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
75
        int16_t const *pcm,
76
        size_t sample_count,
77
        uint8_t channels,
78
        uint32_t sampling_rate,
79
        void *user_data)
80
131
{
81
131
    printf("Received audio payload\n");
82
131
}
83
84
static void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length,
85
                                       void *userdata)
86
4
{
87
4
    if (length == 7 && memcmp("gentoo", data, 7) == 0) {
88
4
        ck_assert(tox_friend_add_norequest(m, public_key, nullptr) != (uint32_t) -1);
89
4
    }
90
4
}
91
92
93
/**
94
 * Iterate helper
95
 */
96
static void iterate_tox(Tox *bootstrap, Tox *alice, Tox *bob)
97
139
{
98
139
    c_sleep(100);
99
139
    tox_iterate(bootstrap, nullptr);
100
139
    tox_iterate(alice, nullptr);
101
139
    tox_iterate(bob, nullptr);
102
139
}
103
104
static bool toxav_audio_send_frame_helper(ToxAV *av, uint32_t friend_number, Toxav_Err_Send_Frame *error)
105
4
{
106
4
    static const int16_t pcm[960] = {0};
107
4
    return toxav_audio_send_frame(av, 0, pcm, 960, 1, 48000, nullptr);
108
4
}
109
110
static void regular_call_flow(
111
    Tox *alice, Tox *bob, Tox *bootstrap,
112
    ToxAV *alice_av, ToxAV *bob_av,
113
    CallControl *alice_cc, CallControl *bob_cc,
114
    int a_br, int v_br)
115
3
{
116
3
    clear_call_control(alice_cc);
117
3
    clear_call_control(bob_cc);
118
119
3
    Toxav_Err_Call call_err;
120
3
    toxav_call(alice_av, 0, a_br, v_br, &call_err);
121
122
3
    ck_assert_msg(call_err == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", call_err);
123
124
3
    const time_t start_time = time(nullptr);
125
126
25
    do {
127
25
        if (bob_cc->incoming) {
128
3
            Toxav_Err_Answer answer_err;
129
3
            toxav_answer(bob_av, 0, a_br, v_br, &answer_err);
130
131
3
            ck_assert_msg(answer_err == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", answer_err);
132
133
3
            bob_cc->incoming = false;
134
22
        } else { /* TODO(mannol): rtp */
135
22
            if (time(nullptr) - start_time >= 1) {
136
137
3
                Toxav_Err_Call_Control cc_err;
138
3
                toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
139
140
3
                ck_assert_msg(cc_err == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", cc_err);
141
3
            }
142
22
        }
143
144
25
        iterate_tox(bootstrap, alice, bob);
145
25
    } while (bob_cc->state != TOXAV_FRIEND_CALL_STATE_FINISHED);
146
147
3
    printf("Success!\n");
148
3
}
149
150
static void test_av_flows(void)
151
1
{
152
1
    Tox *alice, *bob, *bootstrap;
153
1
    ToxAV *alice_av, *bob_av;
154
1
    uint32_t index[] = { 1, 2, 3 };
155
156
1
    CallControl alice_cc, bob_cc;
157
158
1
    {
159
1
        Tox_Err_New error;
160
161
1
        bootstrap = tox_new_log(nullptr, &error, &index[0]);
162
1
        ck_assert(error == TOX_ERR_NEW_OK);
163
164
1
        alice = tox_new_log(nullptr, &error, &index[1]);
165
1
        ck_assert(error == TOX_ERR_NEW_OK);
166
167
1
        bob = tox_new_log(nullptr, &error, &index[2]);
168
1
        ck_assert(error == TOX_ERR_NEW_OK);
169
1
    }
170
171
1
    printf("Created 3 instances of Tox\n");
172
1
    printf("Preparing network...\n");
173
1
    long long unsigned int cur_time = time(nullptr);
174
175
1
    uint8_t address[TOX_ADDRESS_SIZE];
176
177
1
    tox_callback_friend_request(alice, t_accept_friend_request_cb);
178
1
    tox_self_get_address(alice, address);
179
180
1
    printf("bootstrapping Alice and Bob off a third bootstrap node\n");
181
1
    uint8_t dht_key[TOX_PUBLIC_KEY_SIZE];
182
1
    tox_self_get_dht_id(bootstrap, dht_key);
183
1
    const uint16_t dht_port = tox_self_get_udp_port(bootstrap, nullptr);
184
185
1
    tox_bootstrap(alice, "localhost", dht_port, dht_key, nullptr);
186
1
    tox_bootstrap(bob, "localhost", dht_port, dht_key, nullptr);
187
188
1
    ck_assert(tox_friend_add(bob, address, (const uint8_t *)"gentoo", 7, nullptr) != (uint32_t) -1);
189
190
1
    uint8_t off = 1;
191
192
87
    while (true) {
193
87
        iterate_tox(bootstrap, alice, bob);
194
195
87
        if (tox_self_get_connection_status(bootstrap) &&
196
87
                tox_self_get_connection_status(alice) &&
197
87
                tox_self_get_connection_status(bob) && off) {
198
1
            printf("Toxes are online, took %llu seconds\n", time(nullptr) - cur_time);
199
1
            off = 0;
200
1
        }
201
202
87
        if (tox_friend_get_connection_status(alice, 0, nullptr) == TOX_CONNECTION_UDP &&
203
87
                tox_friend_get_connection_status(bob, 0, nullptr) == TOX_CONNECTION_UDP) {
204
1
            break;
205
1
        }
206
207
86
        c_sleep(20);
208
86
    }
209
210
211
1
    {
212
1
        Toxav_Err_New error;
213
1
        alice_av = toxav_new(alice, &error);
214
1
        ck_assert(error == TOXAV_ERR_NEW_OK);
215
216
1
        bob_av = toxav_new(bob, &error);
217
1
        ck_assert(error == TOXAV_ERR_NEW_OK);
218
1
    }
219
220
1
    toxav_callback_call(alice_av, t_toxav_call_cb, &alice_cc);
221
1
    toxav_callback_call_state(alice_av, t_toxav_call_state_cb, &alice_cc);
222
1
    toxav_callback_video_receive_frame(alice_av, t_toxav_receive_video_frame_cb, &alice_cc);
223
1
    toxav_callback_audio_receive_frame(alice_av, t_toxav_receive_audio_frame_cb, &alice_cc);
224
225
1
    toxav_callback_call(bob_av, t_toxav_call_cb, &bob_cc);
226
1
    toxav_callback_call_state(bob_av, t_toxav_call_state_cb, &bob_cc);
227
1
    toxav_callback_video_receive_frame(bob_av, t_toxav_receive_video_frame_cb, &bob_cc);
228
1
    toxav_callback_audio_receive_frame(bob_av, t_toxav_receive_audio_frame_cb, &bob_cc);
229
230
1
    printf("Created 2 instances of ToxAV\n");
231
1
    printf("All set after %llu seconds!\n", time(nullptr) - cur_time);
232
233
1
    if (TEST_REGULAR_AV) {
234
1
        printf("\nTrying regular call (Audio and Video)...\n");
235
1
        regular_call_flow(alice, bob, bootstrap, alice_av, bob_av, &alice_cc, &bob_cc,
236
1
                          48, 4000);
237
1
    }
238
239
1
    if (TEST_REGULAR_A) {
240
1
        printf("\nTrying regular call (Audio only)...\n");
241
1
        regular_call_flow(alice, bob, bootstrap, alice_av, bob_av, &alice_cc, &bob_cc,
242
1
                          48, 0);
243
1
    }
244
245
1
    if (TEST_REGULAR_V) {
246
1
        printf("\nTrying regular call (Video only)...\n");
247
1
        regular_call_flow(alice, bob, bootstrap, alice_av, bob_av, &alice_cc, &bob_cc,
248
1
                          0, 4000);
249
1
    }
250
251
1
    if (TEST_REJECT) { /* Alice calls; Bob rejects */
252
1
        printf("\nTrying reject flow...\n");
253
254
1
        clear_call_control(&alice_cc);
255
1
        clear_call_control(&bob_cc);
256
257
1
        {
258
1
            Toxav_Err_Call rc;
259
1
            toxav_call(alice_av, 0, 48, 0, &rc);
260
261
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc);
262
1
        }
263
264
1
        do {
265
1
            iterate_tox(bootstrap, alice, bob);
266
1
        } while (!bob_cc.incoming);
267
268
        /* Reject */
269
1
        {
270
1
            Toxav_Err_Call_Control rc;
271
1
            toxav_call_control(bob_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
272
273
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc);
274
1
        }
275
276
1
        do {
277
1
            iterate_tox(bootstrap, alice, bob);
278
1
        } while (alice_cc.state != TOXAV_FRIEND_CALL_STATE_FINISHED);
279
280
1
        printf("Success!\n");
281
1
    }
282
283
1
    if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */
284
1
        printf("\nTrying cancel (while ringing) flow...\n");
285
286
1
        clear_call_control(&alice_cc);
287
1
        clear_call_control(&bob_cc);
288
289
1
        {
290
1
            Toxav_Err_Call rc;
291
1
            toxav_call(alice_av, 0, 48, 0, &rc);
292
293
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc);
294
1
        }
295
296
1
        do {
297
1
            iterate_tox(bootstrap, alice, bob);
298
1
        } while (!bob_cc.incoming);
299
300
        /* Cancel */
301
1
        {
302
1
            Toxav_Err_Call_Control rc;
303
1
            toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
304
305
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc);
306
1
        }
307
308
        /* Alice will not receive end state */
309
1
        do {
310
1
            iterate_tox(bootstrap, alice, bob);
311
1
        } while (bob_cc.state != TOXAV_FRIEND_CALL_STATE_FINISHED);
312
313
1
        printf("Success!\n");
314
1
    }
315
316
1
    if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */
317
1
        printf("\nTrying mute functionality...\n");
318
319
1
        clear_call_control(&alice_cc);
320
1
        clear_call_control(&bob_cc);
321
322
        /* Assume sending audio and video */
323
1
        {
324
1
            Toxav_Err_Call rc;
325
1
            toxav_call(alice_av, 0, 48, 1000, &rc);
326
327
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc);
328
1
        }
329
330
1
        do {
331
1
            iterate_tox(bootstrap, alice, bob);
332
1
        } while (!bob_cc.incoming);
333
334
        /* At first try all stuff while in invalid state */
335
1
        ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_PAUSE, nullptr));
336
1
        ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_RESUME, nullptr));
337
1
        ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, nullptr));
338
1
        ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, nullptr));
339
1
        ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_HIDE_VIDEO, nullptr));
340
1
        ck_assert(!toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_SHOW_VIDEO, nullptr));
341
342
1
        {
343
1
            Toxav_Err_Answer rc;
344
1
            toxav_answer(bob_av, 0, 48, 4000, &rc);
345
346
1
            ck_assert_msg(rc == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", rc);
347
1
        }
348
349
1
        iterate_tox(bootstrap, alice, bob);
350
351
        /* Pause and Resume */
352
1
        printf("Pause and Resume\n");
353
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_PAUSE);
354
1
        iterate_tox(bootstrap, alice, bob);
355
1
        ck_assert(bob_cc.state == 0);
356
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_RESUME);
357
1
        iterate_tox(bootstrap, alice, bob);
358
1
        ck_assert(bob_cc.state & (TOXAV_FRIEND_CALL_STATE_SENDING_A | TOXAV_FRIEND_CALL_STATE_SENDING_V));
359
360
        /* Mute/Unmute single */
361
1
        printf("Mute/Unmute single\n");
362
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO);
363
1
        iterate_tox(bootstrap, alice, bob);
364
1
        ck_assert(bob_cc.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);
365
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO);
366
1
        iterate_tox(bootstrap, alice, bob);
367
1
        ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);
368
369
        /* Mute/Unmute both */
370
1
        printf("Mute/Unmute both\n");
371
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO);
372
1
        iterate_tox(bootstrap, alice, bob);
373
1
        ck_assert(bob_cc.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);
374
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_HIDE_VIDEO);
375
1
        iterate_tox(bootstrap, alice, bob);
376
1
        ck_assert(bob_cc.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_V);
377
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO);
378
1
        iterate_tox(bootstrap, alice, bob);
379
1
        ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);
380
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_SHOW_VIDEO);
381
1
        iterate_tox(bootstrap, alice, bob);
382
1
        ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V);
383
384
1
        {
385
1
            Toxav_Err_Call_Control rc;
386
1
            toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
387
388
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc);
389
1
        }
390
391
1
        iterate_tox(bootstrap, alice, bob);
392
1
        ck_assert(bob_cc.state == TOXAV_FRIEND_CALL_STATE_FINISHED);
393
394
1
        printf("Success!\n");
395
1
    }
396
397
1
    if (TEST_STOP_RESUME_PAYLOAD) { /* Stop and resume audio/video payload */
398
1
        printf("\nTrying stop/resume functionality...\n");
399
400
1
        clear_call_control(&alice_cc);
401
1
        clear_call_control(&bob_cc);
402
403
        /* Assume sending audio and video */
404
1
        {
405
1
            Toxav_Err_Call rc;
406
1
            toxav_call(alice_av, 0, 48, 0, &rc);
407
408
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc);
409
1
        }
410
411
1
        do {
412
1
            iterate_tox(bootstrap, alice, bob);
413
1
        } while (!bob_cc.incoming);
414
415
1
        {
416
1
            Toxav_Err_Answer rc;
417
1
            toxav_answer(bob_av, 0, 48, 0, &rc);
418
419
1
            ck_assert_msg(rc == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", rc);
420
1
        }
421
422
1
        iterate_tox(bootstrap, alice, bob);
423
424
1
        printf("Call started as audio only\n");
425
1
        printf("Turning on video for Alice...\n");
426
1
        ck_assert(toxav_video_set_bit_rate(alice_av, 0, 1000, nullptr));
427
428
1
        iterate_tox(bootstrap, alice, bob);
429
1
        ck_assert(bob_cc.state & TOXAV_FRIEND_CALL_STATE_SENDING_V);
430
431
1
        printf("Turning off video for Alice...\n");
432
1
        ck_assert(toxav_video_set_bit_rate(alice_av, 0, 0, nullptr));
433
434
1
        iterate_tox(bootstrap, alice, bob);
435
1
        ck_assert(!(bob_cc.state & TOXAV_FRIEND_CALL_STATE_SENDING_V));
436
437
1
        printf("Turning off audio for Alice...\n");
438
1
        ck_assert(toxav_audio_set_bit_rate(alice_av, 0, 0, nullptr));
439
440
1
        iterate_tox(bootstrap, alice, bob);
441
1
        ck_assert(!(bob_cc.state & TOXAV_FRIEND_CALL_STATE_SENDING_A));
442
443
1
        {
444
1
            Toxav_Err_Call_Control rc;
445
1
            toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
446
447
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc);
448
1
        }
449
450
1
        iterate_tox(bootstrap, alice, bob);
451
1
        ck_assert(bob_cc.state == TOXAV_FRIEND_CALL_STATE_FINISHED);
452
453
1
        printf("Success!\n");
454
1
    }
455
456
1
    if (TEST_PAUSE_RESUME_SEND) { /* Stop and resume audio/video payload and test send options */
457
1
        printf("\nTrying stop/resume functionality...\n");
458
459
1
        clear_call_control(&alice_cc);
460
1
        clear_call_control(&bob_cc);
461
462
        /* Assume sending audio and video */
463
1
        {
464
1
            Toxav_Err_Call rc;
465
1
            toxav_call(alice_av, 0, 48, 0, &rc);
466
467
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_OK, "toxav_call failed: %d\n", rc);
468
1
        }
469
470
1
        do {
471
1
            iterate_tox(bootstrap, alice, bob);
472
1
        } while (!bob_cc.incoming);
473
474
1
        {
475
1
            Toxav_Err_Answer rc;
476
1
            toxav_answer(bob_av, 0, 48, 0, &rc);
477
478
1
            ck_assert_msg(rc == TOXAV_ERR_ANSWER_OK, "toxav_answer failed: %d\n", rc);
479
1
        }
480
481
1
        iterate_tox(bootstrap, alice, bob);
482
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_PAUSE);
483
1
        iterate_tox(bootstrap, alice, bob);
484
1
        ck_assert(!toxav_audio_send_frame_helper(alice_av, 0, nullptr));
485
1
        ck_assert(!toxav_audio_send_frame_helper(bob_av, 0, nullptr));
486
1
        ck_assert_call_control(alice_av, 0, TOXAV_CALL_CONTROL_RESUME);
487
1
        iterate_tox(bootstrap, alice, bob);
488
1
        ck_assert(toxav_audio_send_frame_helper(alice_av, 0, nullptr));
489
1
        ck_assert(toxav_audio_send_frame_helper(bob_av, 0, nullptr));
490
1
        iterate_tox(bootstrap, alice, bob);
491
492
1
        {
493
1
            Toxav_Err_Call_Control rc;
494
1
            toxav_call_control(alice_av, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
495
496
1
            ck_assert_msg(rc == TOXAV_ERR_CALL_CONTROL_OK, "toxav_call_control failed: %d\n", rc);
497
1
        }
498
499
1
        iterate_tox(bootstrap, alice, bob);
500
1
        ck_assert(bob_cc.state == TOXAV_FRIEND_CALL_STATE_FINISHED);
501
502
1
        printf("Success!\n");
503
1
    }
504
505
1
    toxav_kill(bob_av);
506
1
    toxav_kill(alice_av);
507
1
    tox_kill(bob);
508
1
    tox_kill(alice);
509
1
    tox_kill(bootstrap);
510
511
1
    printf("\nTest successful!\n");
512
1
}
513
514
int main(void)
515
721
{
516
721
    setvbuf(stdout, nullptr, _IONBF, 0);
517
518
721
    test_av_flows();
519
721
    return 0;
520
721
}