Coverage Report

Created: 2026-10-24 08:16

/work/auto_tests/scenarios/scenario_toxav_basic_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
typedef struct {
8
    bool incoming;
9
    uint32_t state;
10
} CallState;
11
12
6
#define WAIT_UNTIL_AV(av, cond) do { \
13
24
    while(!(cond) && tox_scenario_is_running(self)) { \
14
18
        toxav_iterate(av); \
15
18
        tox_scenario_yield(self); \
16
18
    } \
17
6
} while(0)
18
19
static void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
20
6
{
21
6
    ToxNode *self = (ToxNode *)user_data;
22
6
    CallState *state = (CallState *)tox_node_get_script_ctx(self);
23
6
    tox_node_log(self, "Received call from friend %u", friend_number);
24
6
    state->incoming = true;
25
6
}
26
27
static void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
28
10
{
29
10
    ToxNode *self = (ToxNode *)user_data;
30
10
    CallState *cs = (CallState *)tox_node_get_script_ctx(self);
31
10
    tox_node_log(self, "Call state changed to %u", state);
32
10
    cs->state = state;
33
10
}
34
35
static void on_audio_receive(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
36
                             uint8_t channels, uint32_t sampling_rate, void *user_data)
37
48
{
38
48
    (void)av;
39
48
    (void)friend_number;
40
48
    (void)pcm;
41
48
    (void)sample_count;
42
48
    (void)channels;
43
48
    (void)sampling_rate;
44
48
    (void)user_data;
45
48
}
46
47
static void on_video_receive(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height,
48
                             uint8_t const *y, uint8_t const *u, uint8_t const *v,
49
                             int32_t ystride, int32_t ustride, int32_t vstride, void *user_data)
50
48
{
51
48
    (void)av;
52
48
    (void)friend_number;
53
48
    (void)width;
54
48
    (void)height;
55
48
    (void)y;
56
48
    (void)u;
57
48
    (void)v;
58
48
    (void)ystride;
59
48
    (void)ustride;
60
48
    (void)vstride;
61
48
    (void)user_data;
62
48
}
63
64
static void alice_script(ToxNode *self, void *ctx)
65
1
{
66
1
    CallState *state = (CallState *)ctx;
67
1
    Tox *tox = tox_node_get_tox(self);
68
1
    Toxav_Err_New av_err;
69
1
    ToxAV *av = toxav_new(tox, &av_err);
70
1
    ck_assert(av_err == TOXAV_ERR_NEW_OK);
71
72
1
    toxav_callback_call(av, on_call, self);
73
1
    toxav_callback_call_state(av, on_call_state, self);
74
1
    toxav_callback_audio_receive_frame(av, on_audio_receive, self);
75
1
    toxav_callback_video_receive_frame(av, on_video_receive, self);
76
77
1
    WAIT_UNTIL(tox_node_is_self_connected(self));
78
1
    WAIT_UNTIL(tox_node_is_friend_connected(self, 0));
79
80
    // 1. Regular AV call - Alice calls, Bob answers, Bob hangs up
81
1
    tox_node_log(self, "--- Starting Regular AV Call ---");
82
1
    state->state = 0;
83
1
    Toxav_Err_Call call_err;
84
1
    toxav_call(av, 0, 48, 4000, &call_err);
85
1
    ck_assert(call_err == TOXAV_ERR_CALL_OK);
86
87
1
    WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED);
88
1
    tox_node_log(self, "Regular AV Call finished (state=%u)", state->state);
89
90
1
    tox_scenario_barrier_wait(self);
91
92
    // 2. Reject flow - Alice calls, Bob rejects
93
1
    tox_node_log(self, "--- Starting Reject Flow ---");
94
1
    state->state = 0;
95
1
    toxav_call(av, 0, 48, 0, &call_err);
96
1
    ck_assert(call_err == TOXAV_ERR_CALL_OK);
97
98
1
    WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED);
99
1
    tox_node_log(self, "Reject Flow finished");
100
101
1
    tox_scenario_barrier_wait(self);
102
103
    // 3. Cancel flow - Alice calls, Alice cancels
104
1
    tox_node_log(self, "--- Starting Cancel Flow ---");
105
1
    state->state = 0;
106
1
    toxav_call(av, 0, 48, 0, &call_err);
107
1
    ck_assert(call_err == TOXAV_ERR_CALL_OK);
108
109
    // Wait for Bob to see it ringing
110
1
    tox_scenario_barrier_wait(self);
111
112
1
    tox_node_log(self, "Alice: Canceling call...");
113
1
    Toxav_Err_Call_Control cc_err;
114
1
    toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
115
1
    ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK);
116
117
    // Alice doesn't receive FINISHED state when SHE cancels
118
1
    tox_node_log(self, "Alice: Cancel Flow finished");
119
120
1
    tox_scenario_barrier_wait(self);
121
122
1
    toxav_kill(av);
123
1
}
124
125
static void bob_script(ToxNode *self, void *ctx)
126
1
{
127
1
    CallState *state = (CallState *)ctx;
128
1
    Tox *tox = tox_node_get_tox(self);
129
1
    Toxav_Err_New av_err;
130
1
    ToxAV *av = toxav_new(tox, &av_err);
131
1
    ck_assert(av_err == TOXAV_ERR_NEW_OK);
132
133
1
    toxav_callback_call(av, on_call, self);
134
1
    toxav_callback_call_state(av, on_call_state, self);
135
1
    toxav_callback_audio_receive_frame(av, on_audio_receive, self);
136
1
    toxav_callback_video_receive_frame(av, on_video_receive, self);
137
138
1
    WAIT_UNTIL(tox_node_is_self_connected(self));
139
1
    WAIT_UNTIL(tox_node_is_friend_connected(self, 0));
140
141
    // 1. Regular AV call - Bob answers, then hangs up
142
1
    WAIT_UNTIL_AV(av, state->incoming);
143
1
    state->incoming = false;
144
1
    Toxav_Err_Answer answer_err;
145
1
    toxav_answer(av, 0, 48, 4000, &answer_err);
146
1
    ck_assert(answer_err == TOXAV_ERR_ANSWER_OK);
147
148
    // Wait a bit and hang up
149
11
    for (int i = 0; i < 10; i++) {
150
10
        toxav_iterate(av);
151
10
        tox_scenario_yield(self);
152
10
    }
153
1
    tox_node_log(self, "Bob: Hanging up...");
154
1
    Toxav_Err_Call_Control cc_err;
155
1
    toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
156
1
    ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK);
157
158
1
    tox_scenario_barrier_wait(self);
159
160
    // 2. Reject flow - Bob rejects
161
1
    WAIT_UNTIL_AV(av, state->incoming);
162
1
    state->incoming = false;
163
1
    tox_node_log(self, "Bob: Rejecting call...");
164
1
    toxav_call_control(av, 0, TOXAV_CALL_CONTROL_CANCEL, &cc_err);
165
1
    ck_assert(cc_err == TOXAV_ERR_CALL_CONTROL_OK);
166
167
1
    tox_scenario_barrier_wait(self);
168
169
    // 3. Cancel flow - Alice cancels
170
1
    WAIT_UNTIL_AV(av, state->incoming);
171
1
    state->incoming = false;
172
1
    tox_scenario_barrier_wait(self); // Alice will now cancel
173
174
1
    WAIT_UNTIL_AV(av, state->state & TOXAV_FRIEND_CALL_STATE_FINISHED);
175
1
    tox_node_log(self, "Bob: Cancel Flow finished (Alice canceled)");
176
177
1
    tox_scenario_barrier_wait(self);
178
179
1
    toxav_kill(av);
180
1
}
181
182
int main(int argc, char *argv[])
183
1
{
184
1
    ToxScenario *s = tox_scenario_new(argc, argv, 60000);
185
186
1
    CallState alice_state = {0};
187
1
    CallState bob_state = {0};
188
189
1
    Tox_Options *opts = tox_options_new(nullptr);
190
1
    tox_options_set_ipv6_enabled(opts, false);
191
1
    tox_options_set_local_discovery_enabled(opts, false);
192
193
1
    ToxNode *alice = tox_scenario_add_node_ex(s, "Alice", alice_script, &alice_state, sizeof(CallState), opts);
194
1
    ToxNode *bob = tox_scenario_add_node_ex(s, "Bob", bob_script, &bob_state, sizeof(CallState), opts);
195
196
1
    tox_options_free(opts);
197
198
1
    tox_node_bootstrap(bob, alice);
199
1
    tox_node_friend_add(alice, bob);
200
1
    tox_node_friend_add(bob, alice);
201
202
1
    ToxScenarioStatus res = tox_scenario_run(s);
203
1
    tox_scenario_free(s);
204
1
    return (res == TOX_SCENARIO_DONE) ? 0 : 1;
205
1
}