/work/auto_tests/scenarios/scenario_conference_av_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 | 39 | #define NUM_NODES 4 |
8 | | |
9 | | typedef struct { |
10 | | bool invited_next; |
11 | | uint32_t audio_received_mask; |
12 | | uint32_t group_number; |
13 | | bool joined; |
14 | | } State; |
15 | | |
16 | | static void audio_callback(void *tox, uint32_t group_number, uint32_t peer_number, const int16_t *pcm, |
17 | | unsigned int samples, uint8_t channels, uint32_t sample_rate, void *user_data) |
18 | 452 | { |
19 | 452 | (void)tox; |
20 | 452 | (void)group_number; |
21 | 452 | (void)sample_rate; |
22 | 452 | (void)channels; |
23 | 452 | ToxNode *self = (ToxNode *)user_data; |
24 | 452 | State *state = (State *)tox_node_get_script_ctx(self); |
25 | 452 | if (samples > 0) { |
26 | 452 | state->audio_received_mask |= (1 << peer_number); |
27 | 452 | } |
28 | 452 | } |
29 | | |
30 | | static void on_conference_invite(const Tox_Event_Conference_Invite *event, void *user_data) |
31 | 3 | { |
32 | 3 | ToxNode *self = (ToxNode *)user_data; |
33 | 3 | State *state = (State *)tox_node_get_script_ctx(self); |
34 | 3 | uint32_t friend_number = tox_event_conference_invite_get_friend_number(event); |
35 | | |
36 | 3 | if (state->joined) { |
37 | 0 | return; |
38 | 0 | } |
39 | | |
40 | 3 | const uint8_t *cookie = tox_event_conference_invite_get_cookie(event); |
41 | 3 | size_t length = tox_event_conference_invite_get_cookie_length(event); |
42 | | |
43 | 3 | tox_node_log(self, "Received conference invite from friend %u", friend_number); |
44 | 3 | state->group_number = toxav_join_av_groupchat(tox_node_get_tox(self), friend_number, cookie, length, audio_callback, self); |
45 | 3 | ck_assert(state->group_number != (uint32_t) -1); |
46 | 3 | state->joined = true; |
47 | 3 | } |
48 | | |
49 | | static void on_conference_connected(const Tox_Event_Conference_Connected *event, void *user_data) |
50 | 3 | { |
51 | 3 | ToxNode *self = (ToxNode *)user_data; |
52 | 3 | State *state = (State *)tox_node_get_script_ctx(self); |
53 | 3 | uint32_t group_number = tox_event_conference_connected_get_conference_number(event); |
54 | | |
55 | 3 | if (state->invited_next) { |
56 | 0 | return; |
57 | 0 | } |
58 | | |
59 | | // In a linear graph, friend 0 is i-1, friend 1 is i+1 (if exists) |
60 | | // We want to invite the next peer. |
61 | 3 | uint32_t friend_count = tox_self_get_friend_list_size(tox_node_get_tox(self)); |
62 | 3 | if (friend_count > 1 || tox_node_get_index(self) == 0) { |
63 | 2 | uint32_t friend_to_invite = (tox_node_get_index(self) == 0) ? 0 : 1; |
64 | 2 | if (friend_to_invite < friend_count) { |
65 | 2 | Tox_Err_Conference_Invite err; |
66 | 2 | tox_conference_invite(tox_node_get_tox(self), friend_to_invite, group_number, &err); |
67 | 2 | if (err == TOX_ERR_CONFERENCE_INVITE_OK) { |
68 | 2 | tox_node_log(self, "Invited next friend (%u)", friend_to_invite); |
69 | 2 | state->invited_next = true; |
70 | 2 | } |
71 | 2 | } |
72 | 2 | } |
73 | 3 | } |
74 | | |
75 | | static void peer_script(ToxNode *self, void *ctx) |
76 | 4 | { |
77 | 4 | State *state = (State *)ctx; |
78 | 4 | Tox *tox = tox_node_get_tox(self); |
79 | 4 | Tox_Dispatch *dispatch = tox_node_get_dispatch(self); |
80 | | |
81 | 4 | tox_events_callback_conference_invite(dispatch, on_conference_invite); |
82 | 4 | tox_events_callback_conference_connected(dispatch, on_conference_connected); |
83 | | |
84 | 4 | WAIT_UNTIL(tox_node_is_self_connected(self)); |
85 | | |
86 | 4 | if (tox_node_get_index(self) == 0) { |
87 | 1 | tox_node_log(self, "Creating AV group..."); |
88 | 1 | state->group_number = toxav_add_av_groupchat(tox, audio_callback, self); |
89 | 1 | ck_assert(state->group_number != (uint32_t) -1); |
90 | 1 | state->joined = true; |
91 | | |
92 | | // Peer 0 has only one friend (Peer 1) |
93 | 1 | WAIT_UNTIL(tox_node_is_friend_connected(self, 0)); |
94 | 1 | tox_conference_invite(tox, 0, state->group_number, nullptr); |
95 | 1 | state->invited_next = true; |
96 | 1 | } |
97 | | |
98 | | // Wait until joined and everyone is in the group |
99 | 4 | WAIT_UNTIL(state->joined); |
100 | | |
101 | | // Invite and friend connection order can be unreliable, so we add a fallback here. |
102 | 4 | if (tox_node_get_index(self) < NUM_NODES - 1 && !state->invited_next) { |
103 | 2 | WAIT_UNTIL(tox_node_is_friend_connected(self, 1)); |
104 | 2 | Tox_Err_Conference_Invite err; |
105 | 2 | tox_conference_invite(tox_node_get_tox(self), 1, state->group_number, &err); |
106 | 2 | state->invited_next = (err == TOX_ERR_CONFERENCE_INVITE_OK); |
107 | 2 | } |
108 | | |
109 | 22 | while (tox_node_get_conference_peer_count(self, state->group_number) < (uint32_t)NUM_NODES) { |
110 | 18 | tox_scenario_yield(self); |
111 | 18 | } |
112 | 4 | tox_node_log(self, "All %u peers in group!", (uint32_t)NUM_NODES); |
113 | | |
114 | | // Send audio for a bit |
115 | 4 | const int16_t pcm[960] = {0}; |
116 | 164 | for (int i = 0; i < 40; i++) { |
117 | 160 | toxav_group_send_audio(tox, state->group_number, pcm, 960, 1, 48000); |
118 | 160 | tox_scenario_yield(self); |
119 | 160 | } |
120 | | |
121 | 4 | tox_node_log(self, "Audio sent. Received audio mask: %u", state->audio_received_mask); |
122 | 4 | } |
123 | | |
124 | | int main(int argc, char *argv[]) |
125 | 1 | { |
126 | 1 | ToxScenario *s = tox_scenario_new(argc, argv, 60000); |
127 | 1 | State states[NUM_NODES] = {0}; |
128 | 1 | ToxNode *nodes[NUM_NODES]; |
129 | | |
130 | 5 | for (uint32_t i = 0; i < NUM_NODES; i++) { |
131 | 4 | char name[32]; |
132 | 4 | snprintf(name, sizeof(name), "Peer-%u", i); |
133 | 4 | nodes[i] = tox_scenario_add_node(s, name, peer_script, &states[i], sizeof(State)); |
134 | 4 | } |
135 | | |
136 | | // Linear graph |
137 | 4 | for (uint32_t i = 0; i < NUM_NODES - 1; i++) { |
138 | 3 | tox_node_bootstrap(nodes[i + 1], nodes[i]); |
139 | 3 | tox_node_friend_add(nodes[i], nodes[i + 1]); |
140 | 3 | tox_node_friend_add(nodes[i + 1], nodes[i]); |
141 | 3 | } |
142 | | |
143 | 1 | ToxScenarioStatus res = tox_scenario_run(s); |
144 | 1 | tox_scenario_free(s); |
145 | 1 | return (res == TOX_SCENARIO_DONE) ? 0 : 1; |
146 | 1 | } |