Coverage Report

Created: 2026-10-24 08:16

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