summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--auto_tests/Makefile.inc6
-rw-r--r--auto_tests/conference_av_test.c467
-rw-r--r--auto_tests/conference_test.c99
-rw-r--r--auto_tests/run_auto_test.h15
-rw-r--r--toxav/groupav.c53
-rw-r--r--toxav/groupav.h14
-rw-r--r--toxav/toxav.api.h21
-rw-r--r--toxav/toxav.h21
-rw-r--r--toxav/toxav_old.c29
-rw-r--r--toxcore/group.c22
11 files changed, 697 insertions, 51 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7f04ba61..63df3aba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -434,6 +434,7 @@ auto_test(version)
434auto_test(save_compatibility) 434auto_test(save_compatibility)
435 435
436if(BUILD_TOXAV) 436if(BUILD_TOXAV)
437 auto_test(conference_av)
437 auto_test(toxav_basic) 438 auto_test(toxav_basic)
438 auto_test(toxav_many) 439 auto_test(toxav_many)
439endif() 440endif()
diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc
index 3a4b6c7e..98f9db13 100644
--- a/auto_tests/Makefile.inc
+++ b/auto_tests/Makefile.inc
@@ -57,7 +57,7 @@ AUTOTEST_LDADD = \
57 57
58 58
59if BUILD_AV 59if BUILD_AV
60TESTS += toxav_basic_test toxav_many_test 60TESTS += conference_av_test toxav_basic_test toxav_many_test
61AUTOTEST_LDADD += libtoxav.la 61AUTOTEST_LDADD += libtoxav.la
62endif 62endif
63 63
@@ -221,6 +221,10 @@ version_test_LDADD = $(AUTOTEST_LDADD)
221 221
222if BUILD_AV 222if BUILD_AV
223 223
224conference_av_test_SOURCES = ../auto_tests/conference_av_test.c
225conference_av_test_CFLAGS = $(AUTOTEST_CFLAGS)
226conference_av_test_LDADD = $(AUTOTEST_LDADD)
227
224toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c 228toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c
225toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) 229toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
226toxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS) 230toxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS)
diff --git a/auto_tests/conference_av_test.c b/auto_tests/conference_av_test.c
new file mode 100644
index 00000000..6d701751
--- /dev/null
+++ b/auto_tests/conference_av_test.c
@@ -0,0 +1,467 @@
1/* Auto Tests: Conferences AV.
2 */
3
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif
7
8#include <stdlib.h>
9#include <string.h>
10#include <time.h>
11#include <stdint.h>
12
13#include "../toxav/toxav.h"
14#include "check_compat.h"
15
16#define NUM_AV_GROUP_TOX 16
17#define NUM_AV_DISCONNECT (NUM_AV_GROUP_TOX / 2)
18#define NUM_AV_DISABLE (NUM_AV_GROUP_TOX / 2)
19
20typedef struct State {
21 uint32_t index;
22 uint64_t clock;
23
24 bool invited_next;
25
26 uint32_t received_audio_peers[NUM_AV_GROUP_TOX];
27 uint32_t received_audio_num;
28} State;
29
30#include "run_auto_test.h"
31
32static void handle_self_connection_status(
33 Tox *tox, Tox_Connection connection_status, void *user_data)
34{
35 const State *state = (State *)user_data;
36
37 if (connection_status != TOX_CONNECTION_NONE) {
38 printf("tox #%u: is now connected\n", state->index);
39 } else {
40 printf("tox #%u: is now disconnected\n", state->index);
41 }
42}
43
44static void handle_friend_connection_status(
45 Tox *tox, uint32_t friendnumber, Tox_Connection connection_status, void *user_data)
46{
47 const State *state = (State *)user_data;
48
49 if (connection_status != TOX_CONNECTION_NONE) {
50 printf("tox #%u: is now connected to friend %u\n", state->index, friendnumber);
51 } else {
52 printf("tox #%u: is now disconnected from friend %u\n", state->index, friendnumber);
53 }
54}
55
56static void audio_callback(void *tox, uint32_t groupnumber, uint32_t peernumber,
57 const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
58 sample_rate, void *userdata)
59{
60 if (samples == 0) {
61 return;
62 }
63
64 State *state = (State *)userdata;
65
66 for (uint32_t i = 0; i < state->received_audio_num; ++i) {
67 if (state->received_audio_peers[i] == peernumber) {
68 return;
69 }
70 }
71
72 ck_assert(state->received_audio_num < NUM_AV_GROUP_TOX);
73
74 state->received_audio_peers[state->received_audio_num] = peernumber;
75 ++state->received_audio_num;
76}
77
78static void handle_conference_invite(
79 Tox *tox, uint32_t friendnumber, Tox_Conference_Type type,
80 const uint8_t *data, size_t length, void *user_data)
81{
82 const State *state = (State *)user_data;
83 ck_assert_msg(type == TOX_CONFERENCE_TYPE_AV, "tox #%u: wrong conference type: %d", state->index, type);
84
85 ck_assert_msg(toxav_join_av_groupchat(tox, friendnumber, data, length, audio_callback, user_data) == 0,
86 "tox #%u: failed to join group", state->index);
87}
88
89static void handle_conference_connected(
90 Tox *tox, uint32_t conference_number, void *user_data)
91{
92 State *state = (State *)user_data;
93
94 if (state->invited_next || tox_self_get_friend_list_size(tox) <= 1) {
95 return;
96 }
97
98 Tox_Err_Conference_Invite err;
99 tox_conference_invite(tox, 1, 0, &err);
100 ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", state->index, err);
101 printf("tox #%u: invited next friend\n", state->index);
102 state->invited_next = true;
103}
104
105static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
106 bool *disconnected)
107{
108 uint32_t num_disconnected = 0;
109
110 for (uint32_t i = 0; i < tox_count; ++i) {
111 num_disconnected += disconnected[i];
112 }
113
114 for (uint32_t i = 0; i < tox_count; i++) {
115 if (disconnected[i]) {
116 continue;
117 }
118
119 if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - num_disconnected) {
120 return false;
121 }
122 }
123
124 return true;
125}
126
127static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
128 const bool *disconnect, const bool *exclude)
129{
130 /* Fake a network outage for a set of peers D by iterating only the other
131 * peers D' until the connections time out according to D', then iterating
132 * only D until the connections time out according to D. */
133
134 VLA(bool, disconnect_now, tox_count);
135 bool invert = false;
136
137 do {
138 for (uint32_t i = 0; i < tox_count; ++i) {
139 disconnect_now[i] = exclude[i] || (invert ^ disconnect[i]);
140 }
141
142 do {
143 for (uint32_t i = 0; i < tox_count; ++i) {
144 if (!disconnect_now[i]) {
145 tox_iterate(toxes[i], &state[i]);
146 state[i].clock += 1000;
147 }
148 }
149
150 c_sleep(20);
151 } while (!toxes_are_disconnected_from_group(tox_count, toxes, disconnect_now));
152
153 invert = !invert;
154 } while (invert);
155}
156
157static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
158{
159 for (uint32_t i = 0; i < tox_count; i++) {
160 if (tox_conference_peer_count(toxes[i], 0, nullptr) < tox_count) {
161 return false;
162 }
163 }
164
165 return true;
166}
167
168/**
169 * returns a random index at which a list of booleans is false
170 * (some such index is required to exist)
171 */
172static uint32_t random_false_index(bool *list, const uint32_t length)
173{
174 uint32_t index;
175
176 do {
177 index = random_u32() % length;
178 } while (list[index]);
179
180 return index;
181}
182
183static bool all_got_audio(State *state, const bool *disabled)
184{
185 uint32_t num_disabled = 0;
186
187 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
188 num_disabled += disabled[i];
189 }
190
191 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
192 if (disabled[i] ^ (state[i].received_audio_num
193 != NUM_AV_GROUP_TOX - num_disabled - 1)) {
194 return false;
195 }
196 }
197
198 return true;
199}
200
201static void reset_received_audio(Tox **toxes, State *state)
202{
203 for (uint32_t j = 0; j < NUM_AV_GROUP_TOX; ++j) {
204 state[j].received_audio_num = 0;
205 }
206}
207
208#define GROUP_AV_TEST_SAMPLES 960
209
210/* must have
211 * GROUP_AV_AUDIO_ITERATIONS - NUM_AV_GROUP_TOX >= 2^n >= GROUP_JBUF_SIZE
212 * for some n, to give messages time to be relayed and to let the jitter
213 * buffers fill up. */
214#define GROUP_AV_AUDIO_ITERATIONS (8 + NUM_AV_GROUP_TOX)
215
216static bool test_audio(Tox **toxes, State *state, const bool *disabled, bool quiet)
217{
218 if (!quiet) {
219 printf("testing sending and receiving audio\n");
220 }
221
222 int16_t PCM[GROUP_AV_TEST_SAMPLES];
223
224 reset_received_audio(toxes, state);
225
226 for (uint32_t n = 0; n < GROUP_AV_AUDIO_ITERATIONS; n++) {
227 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
228 if (disabled[i]) {
229 continue;
230 }
231
232 if (toxav_group_send_audio(toxes[i], 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) != 0) {
233 if (!quiet) {
234 ck_abort_msg("#%u failed to send audio", state[i].index);
235 }
236
237 return false;
238 }
239 }
240
241 iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
242
243 if (all_got_audio(state, disabled)) {
244 return true;
245 }
246 }
247
248 if (!quiet) {
249 ck_abort_msg("group failed to receive audio");
250 }
251
252 return false;
253}
254
255static void test_eventual_audio(Tox **toxes, State *state, const bool *disabled, uint64_t timeout)
256{
257 uint64_t start = state[0].clock;
258
259 while (state[0].clock < start + timeout) {
260 if (test_audio(toxes, state, disabled, true)
261 && test_audio(toxes, state, disabled, true)) {
262 printf("audio test successful after %d seconds\n", (int)((state[0].clock - start) / 1000));
263 return;
264 }
265 }
266
267 printf("audio seems not to be getting through: testing again with errors.\n");
268 test_audio(toxes, state, disabled, false);
269}
270
271static void do_audio(Tox **toxes, State *state, uint32_t iterations)
272{
273 int16_t PCM[GROUP_AV_TEST_SAMPLES];
274 printf("running audio for %u iterations\n", iterations);
275
276 for (uint32_t f = 0; f < iterations; ++f) {
277 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
278 ck_assert_msg(toxav_group_send_audio(toxes[i], 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) == 0,
279 "#%u failed to send audio", state[i].index);
280 iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
281 }
282 }
283}
284
285// should agree with value in groupav.c
286#define GROUP_JBUF_DEAD_SECONDS 4
287
288#define JITTER_SETTLE_TIME (GROUP_JBUF_DEAD_SECONDS*1000 + NUM_AV_GROUP_TOX*ITERATION_INTERVAL*(GROUP_AV_AUDIO_ITERATIONS+1))
289
290static void run_conference_tests(Tox **toxes, State *state)
291{
292 bool disabled[NUM_AV_GROUP_TOX] = {0};
293
294 test_audio(toxes, state, disabled, false);
295
296 /* have everyone send audio for a bit so we can test that the audio
297 * sequnums dropping to 0 on restart isn't a problem */
298 do_audio(toxes, state, 20);
299
300 printf("letting random toxes timeout\n");
301 bool disconnected[NUM_AV_GROUP_TOX] = {0};
302 bool restarting[NUM_AV_GROUP_TOX] = {0};
303
304 ck_assert(NUM_AV_DISCONNECT < NUM_AV_GROUP_TOX);
305
306 for (uint32_t i = 0; i < NUM_AV_DISCONNECT; ++i) {
307 uint32_t disconnect = random_false_index(disconnected, NUM_AV_GROUP_TOX);
308 disconnected[disconnect] = true;
309
310 if (i < NUM_AV_DISCONNECT / 2) {
311 restarting[disconnect] = true;
312 printf("Restarting #%u\n", state[disconnect].index);
313 } else {
314 printf("Disconnecting #%u\n", state[disconnect].index);
315 }
316 }
317
318 uint8_t *save[NUM_AV_GROUP_TOX];
319 size_t save_size[NUM_AV_GROUP_TOX];
320
321 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
322 if (restarting[i]) {
323 save_size[i] = tox_get_savedata_size(toxes[i]);
324 ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]);
325 save[i] = (uint8_t *)malloc(save_size[i]);
326 ck_assert_msg(save[i] != nullptr, "malloc failed");
327 tox_get_savedata(toxes[i], save[i]);
328 tox_kill(toxes[i]);
329 }
330 }
331
332 disconnect_toxes(NUM_AV_GROUP_TOX, toxes, state, disconnected, restarting);
333
334 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
335 if (restarting[i]) {
336 struct Tox_Options *const options = tox_options_new(nullptr);
337 tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
338 tox_options_set_savedata_data(options, save[i], save_size[i]);
339 toxes[i] = tox_new_log(options, nullptr, &state[i].index);
340 tox_options_free(options);
341 free(save[i]);
342
343 set_mono_time_callback(toxes[i], &state[i]);
344 }
345 }
346
347 printf("reconnecting toxes\n");
348
349 do {
350 iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
351 } while (!all_connected_to_group(NUM_AV_GROUP_TOX, toxes));
352
353 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
354 if (restarting[i]) {
355 ck_assert_msg(toxav_groupchat_enable_av(toxes[i], 0, audio_callback, &state[i]) == 0,
356 "#%u failed to re-enable av", state[i].index);
357 }
358 }
359
360 printf("testing audio\n");
361
362 /* Allow time for the jitter buffers to reset and for the group to become
363 * connected enough for lossy messages to get through
364 * (all_connected_to_group() only checks lossless connectivity, which is a
365 * looser condition). */
366 test_eventual_audio(toxes, state, disabled, JITTER_SETTLE_TIME + NUM_AV_GROUP_TOX * 1000);
367
368 printf("testing disabling av\n");
369
370 ck_assert(NUM_AV_DISABLE < NUM_AV_GROUP_TOX);
371
372 for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) {
373 uint32_t disable = random_false_index(disabled, NUM_AV_GROUP_TOX);
374 disabled[disable] = true;
375 printf("Disabling #%u\n", state[disable].index);
376 ck_assert_msg(toxav_groupchat_enable_av(toxes[disable], 0, audio_callback, &state[disable]) != 0,
377 "#%u could enable already enabled av!", state[i].index);
378 ck_assert_msg(toxav_groupchat_disable_av(toxes[disable], 0) == 0,
379 "#%u failed to disable av", state[i].index);
380 }
381
382 // Run test without error to clear out messages from now-disabled peers.
383 test_audio(toxes, state, disabled, true);
384
385 printf("testing audio with some peers having disabled their av\n");
386 test_audio(toxes, state, disabled, false);
387
388 for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) {
389 if (!disabled[i]) {
390 continue;
391 }
392
393 disabled[i] = false;
394 ck_assert_msg(toxav_groupchat_disable_av(toxes[i], 0) != 0,
395 "#%u could disable already disabled av!", state[i].index);
396 ck_assert_msg(toxav_groupchat_enable_av(toxes[i], 0, audio_callback, &state[i]) == 0,
397 "#%u failed to re-enable av", state[i].index);
398 }
399
400 printf("testing audio after re-enabling all av\n");
401 test_eventual_audio(toxes, state, disabled, JITTER_SETTLE_TIME);
402}
403
404static void test_groupav(Tox **toxes, State *state)
405{
406 const time_t test_start_time = time(nullptr);
407
408 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
409 tox_callback_self_connection_status(toxes[i], &handle_self_connection_status);
410 tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status);
411 tox_callback_conference_invite(toxes[i], &handle_conference_invite);
412 tox_callback_conference_connected(toxes[i], &handle_conference_connected);
413 }
414
415 ck_assert_msg(toxav_add_av_groupchat(toxes[0], audio_callback, &state[0]) != UINT32_MAX, "failed to create group");
416 printf("tox #%u: inviting its first friend\n", state[0].index);
417 ck_assert_msg(tox_conference_invite(toxes[0], 0, 0, nullptr) != 0, "failed to invite friend");
418 state[0].invited_next = true;
419
420
421 printf("waiting for invitations to be made\n");
422 uint32_t invited_count = 0;
423
424 do {
425 iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
426
427 invited_count = 0;
428
429 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
430 invited_count += state[i].invited_next;
431 }
432 } while (invited_count != NUM_AV_GROUP_TOX - 1);
433
434 uint64_t pregroup_clock = state[0].clock;
435 printf("waiting for all toxes to be in the group\n");
436 uint32_t fully_connected_count = 0;
437
438 do {
439 fully_connected_count = 0;
440 iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
441
442 for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
443 Tox_Err_Conference_Peer_Query err;
444 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err);
445
446 if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
447 peer_count = 0;
448 }
449
450 fully_connected_count += peer_count == NUM_AV_GROUP_TOX;
451 }
452 } while (fully_connected_count != NUM_AV_GROUP_TOX);
453
454 printf("group connected, took %d seconds\n", (int)((state[0].clock - pregroup_clock) / 1000));
455
456 run_conference_tests(toxes, state);
457
458 printf("test_many_group succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time));
459}
460
461int main(void)
462{
463 setvbuf(stdout, nullptr, _IONBF, 0);
464
465 run_auto_test(NUM_AV_GROUP_TOX, test_groupav, true);
466 return 0;
467}
diff --git a/auto_tests/conference_test.c b/auto_tests/conference_test.c
index 349c2905..5f08b823 100644
--- a/auto_tests/conference_test.c
+++ b/auto_tests/conference_test.c
@@ -8,11 +8,8 @@
8#include <stdlib.h> 8#include <stdlib.h>
9#include <string.h> 9#include <string.h>
10#include <time.h> 10#include <time.h>
11#include <stdint.h>
11 12
12#include "../testing/misc_tools.h"
13#include "../toxcore/crypto_core.h"
14#include "../toxcore/tox.h"
15#include "../toxcore/util.h"
16#include "check_compat.h" 13#include "check_compat.h"
17 14
18#define NUM_GROUP_TOX 16 15#define NUM_GROUP_TOX 16
@@ -91,7 +88,7 @@ static void handle_conference_connected(
91 state->invited_next = true; 88 state->invited_next = true;
92} 89}
93 90
94static uint16_t num_recv; 91static uint32_t num_recv;
95 92
96static void handle_conference_message( 93static void handle_conference_message(
97 Tox *tox, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type, 94 Tox *tox, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
@@ -102,15 +99,21 @@ static void handle_conference_message(
102 } 99 }
103} 100}
104 101
105static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes, int disconnected_count, 102static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
106 bool *disconnected) 103 bool *disconnected)
107{ 104{
105 uint32_t num_disconnected = 0;
106
107 for (uint32_t i = 0; i < tox_count; ++i) {
108 num_disconnected += disconnected[i];
109 }
110
108 for (uint32_t i = 0; i < tox_count; i++) { 111 for (uint32_t i = 0; i < tox_count; i++) {
109 if (disconnected[i]) { 112 if (disconnected[i]) {
110 continue; 113 continue;
111 } 114 }
112 115
113 if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - NUM_DISCONNECT) { 116 if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - num_disconnected) {
114 return false; 117 return false;
115 } 118 }
116 } 119 }
@@ -118,6 +121,36 @@ static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes, i
118 return true; 121 return true;
119} 122}
120 123
124static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
125 const bool *disconnect, const bool *exclude)
126{
127 /* Fake a network outage for a set of peers D by iterating only the other
128 * peers D' until the connections time out according to D', then iterating
129 * only D until the connections time out according to D. */
130
131 VLA(bool, disconnect_now, tox_count);
132 bool invert = false;
133
134 do {
135 for (uint32_t i = 0; i < tox_count; ++i) {
136 disconnect_now[i] = exclude[i] || (invert ^ disconnect[i]);
137 }
138
139 do {
140 for (uint32_t i = 0; i < tox_count; ++i) {
141 if (!disconnect_now[i]) {
142 tox_iterate(toxes[i], &state[i]);
143 state[i].clock += 1000;
144 }
145 }
146
147 c_sleep(20);
148 } while (!toxes_are_disconnected_from_group(tox_count, toxes, disconnect_now));
149
150 invert = !invert;
151 } while (invert);
152}
153
121static bool all_connected_to_group(uint32_t tox_count, Tox **toxes) 154static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
122{ 155{
123 for (uint32_t i = 0; i < tox_count; i++) { 156 for (uint32_t i = 0; i < tox_count; i++) {
@@ -131,8 +164,8 @@ static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
131 164
132static bool names_propagated(uint32_t tox_count, Tox **toxes, State *state) 165static bool names_propagated(uint32_t tox_count, Tox **toxes, State *state)
133{ 166{
134 for (uint16_t i = 0; i < tox_count; ++i) { 167 for (uint32_t i = 0; i < tox_count; ++i) {
135 for (uint16_t j = 0; j < tox_count; ++j) { 168 for (uint32_t j = 0; j < tox_count; ++j) {
136 const size_t len = tox_conference_peer_get_name_size(toxes[i], 0, j, nullptr); 169 const size_t len = tox_conference_peer_get_name_size(toxes[i], 0, j, nullptr);
137 170
138 if (len != NAMELEN) { 171 if (len != NAMELEN) {
@@ -145,9 +178,10 @@ static bool names_propagated(uint32_t tox_count, Tox **toxes, State *state)
145} 178}
146 179
147 180
148/* returns a random index at which a list of booleans is false 181/**
182 * returns a random index at which a list of booleans is false
149 * (some such index is required to exist) 183 * (some such index is required to exist)
150 * */ 184 */
151static uint32_t random_false_index(bool *list, const uint32_t length) 185static uint32_t random_false_index(bool *list, const uint32_t length)
152{ 186{
153 uint32_t index; 187 uint32_t index;
@@ -171,7 +205,7 @@ static void run_conference_tests(Tox **toxes, State *state)
171 205
172 ck_assert(NUM_DISCONNECT < NUM_GROUP_TOX); 206 ck_assert(NUM_DISCONNECT < NUM_GROUP_TOX);
173 207
174 for (uint16_t i = 0; i < NUM_DISCONNECT; ++i) { 208 for (uint32_t i = 0; i < NUM_DISCONNECT; ++i) {
175 uint32_t disconnect = random_false_index(disconnected, NUM_GROUP_TOX); 209 uint32_t disconnect = random_false_index(disconnected, NUM_GROUP_TOX);
176 disconnected[disconnect] = true; 210 disconnected[disconnect] = true;
177 211
@@ -186,7 +220,7 @@ static void run_conference_tests(Tox **toxes, State *state)
186 uint8_t *save[NUM_GROUP_TOX]; 220 uint8_t *save[NUM_GROUP_TOX];
187 size_t save_size[NUM_GROUP_TOX]; 221 size_t save_size[NUM_GROUP_TOX];
188 222
189 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 223 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
190 if (restarting[i]) { 224 if (restarting[i]) {
191 save_size[i] = tox_get_savedata_size(toxes[i]); 225 save_size[i] = tox_get_savedata_size(toxes[i]);
192 ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]); 226 ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]);
@@ -197,18 +231,9 @@ static void run_conference_tests(Tox **toxes, State *state)
197 } 231 }
198 } 232 }
199 233
200 do { 234 disconnect_toxes(NUM_GROUP_TOX, toxes, state, disconnected, restarting);
201 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
202 if (!disconnected[i]) {
203 tox_iterate(toxes[i], &state[i]);
204 state[i].clock += 1000;
205 }
206 }
207 235
208 c_sleep(20); 236 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
209 } while (!toxes_are_disconnected_from_group(NUM_GROUP_TOX, toxes, NUM_DISCONNECT, disconnected));
210
211 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
212 if (restarting[i]) { 237 if (restarting[i]) {
213 struct Tox_Options *const options = tox_options_new(nullptr); 238 struct Tox_Options *const options = tox_options_new(nullptr);
214 tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); 239 tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
@@ -216,13 +241,15 @@ static void run_conference_tests(Tox **toxes, State *state)
216 toxes[i] = tox_new_log(options, nullptr, &state[i].index); 241 toxes[i] = tox_new_log(options, nullptr, &state[i].index);
217 tox_options_free(options); 242 tox_options_free(options);
218 free(save[i]); 243 free(save[i]);
244
245 set_mono_time_callback(toxes[i], &state[i]);
219 } 246 }
220 } 247 }
221 248
222 if (check_name_change_propagation) { 249 if (check_name_change_propagation) {
223 printf("changing names\n"); 250 printf("changing names\n");
224 251
225 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 252 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
226 char name[NAMELEN + 1]; 253 char name[NAMELEN + 1];
227 snprintf(name, NAMELEN + 1, NEW_NAME_FORMAT_STR, state[i].index); 254 snprintf(name, NAMELEN + 1, NEW_NAME_FORMAT_STR, state[i].index);
228 tox_self_set_name(toxes[i], (const uint8_t *)name, NAMELEN, nullptr); 255 tox_self_set_name(toxes[i], (const uint8_t *)name, NAMELEN, nullptr);
@@ -237,7 +264,7 @@ static void run_conference_tests(Tox **toxes, State *state)
237 264
238 printf("running conference tests\n"); 265 printf("running conference tests\n");
239 266
240 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 267 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
241 tox_callback_conference_message(toxes[i], &handle_conference_message); 268 tox_callback_conference_message(toxes[i], &handle_conference_message);
242 269
243 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL); 270 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
@@ -259,8 +286,8 @@ static void run_conference_tests(Tox **toxes, State *state)
259 ck_assert_msg(num_recv == NUM_GROUP_TOX, "failed to recv group messages"); 286 ck_assert_msg(num_recv == NUM_GROUP_TOX, "failed to recv group messages");
260 287
261 if (check_name_change_propagation) { 288 if (check_name_change_propagation) {
262 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 289 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
263 for (uint16_t j = 0; j < NUM_GROUP_TOX; ++j) { 290 for (uint32_t j = 0; j < NUM_GROUP_TOX; ++j) {
264 uint8_t name[NAMELEN]; 291 uint8_t name[NAMELEN];
265 tox_conference_peer_get_name(toxes[i], 0, j, name, nullptr); 292 tox_conference_peer_get_name(toxes[i], 0, j, name, nullptr);
266 /* Note the toxes will have been reordered */ 293 /* Note the toxes will have been reordered */
@@ -270,14 +297,14 @@ static void run_conference_tests(Tox **toxes, State *state)
270 } 297 }
271 } 298 }
272 299
273 for (uint16_t k = NUM_GROUP_TOX; k != 0 ; --k) { 300 for (uint32_t k = NUM_GROUP_TOX; k != 0 ; --k) {
274 tox_conference_delete(toxes[k - 1], 0, nullptr); 301 tox_conference_delete(toxes[k - 1], 0, nullptr);
275 302
276 for (uint8_t j = 0; j < 10 || j < NUM_GROUP_TOX; ++j) { 303 for (uint8_t j = 0; j < 10 || j < NUM_GROUP_TOX; ++j) {
277 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL); 304 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
278 } 305 }
279 306
280 for (uint16_t i = 0; i < k - 1; ++i) { 307 for (uint32_t i = 0; i < k - 1; ++i) {
281 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr); 308 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr);
282 ck_assert_msg(peer_count == (k - 1), "\n\tBad number of group peers (post check)." 309 ck_assert_msg(peer_count == (k - 1), "\n\tBad number of group peers (post check)."
283 "\n\t\t\tExpected: %u but tox_instance(%u) only has: %u\n\n", 310 "\n\t\t\tExpected: %u but tox_instance(%u) only has: %u\n\n",
@@ -290,7 +317,7 @@ static void test_many_group(Tox **toxes, State *state)
290{ 317{
291 const time_t test_start_time = time(nullptr); 318 const time_t test_start_time = time(nullptr);
292 319
293 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 320 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
294 tox_callback_self_connection_status(toxes[i], &handle_self_connection_status); 321 tox_callback_self_connection_status(toxes[i], &handle_self_connection_status);
295 tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status); 322 tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status);
296 tox_callback_conference_invite(toxes[i], &handle_conference_invite); 323 tox_callback_conference_invite(toxes[i], &handle_conference_invite);
@@ -310,21 +337,21 @@ static void test_many_group(Tox **toxes, State *state)
310 337
311 338
312 printf("waiting for invitations to be made\n"); 339 printf("waiting for invitations to be made\n");
313 uint16_t invited_count = 0; 340 uint32_t invited_count = 0;
314 341
315 do { 342 do {
316 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL); 343 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
317 344
318 invited_count = 0; 345 invited_count = 0;
319 346
320 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 347 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
321 invited_count += state[i].invited_next; 348 invited_count += state[i].invited_next;
322 } 349 }
323 } while (invited_count != NUM_GROUP_TOX - 1); 350 } while (invited_count != NUM_GROUP_TOX - 1);
324 351
325 uint64_t pregroup_clock = state[0].clock; 352 uint64_t pregroup_clock = state[0].clock;
326 printf("waiting for all toxes to be in the group\n"); 353 printf("waiting for all toxes to be in the group\n");
327 uint16_t fully_connected_count = 0; 354 uint32_t fully_connected_count = 0;
328 355
329 do { 356 do {
330 fully_connected_count = 0; 357 fully_connected_count = 0;
@@ -332,7 +359,7 @@ static void test_many_group(Tox **toxes, State *state)
332 359
333 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL); 360 iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
334 361
335 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 362 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
336 Tox_Err_Conference_Peer_Query err; 363 Tox_Err_Conference_Peer_Query err;
337 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err); 364 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err);
338 365
@@ -353,7 +380,7 @@ static void test_many_group(Tox **toxes, State *state)
353 fflush(stdout); 380 fflush(stdout);
354 } while (fully_connected_count != NUM_GROUP_TOX); 381 } while (fully_connected_count != NUM_GROUP_TOX);
355 382
356 for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) { 383 for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
357 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr); 384 uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr);
358 385
359 ck_assert_msg(peer_count == NUM_GROUP_TOX, "\n\tBad number of group peers (pre check)." 386 ck_assert_msg(peer_count == NUM_GROUP_TOX, "\n\tBad number of group peers (pre check)."
diff --git a/auto_tests/run_auto_test.h b/auto_tests/run_auto_test.h
index 4f2dc278..47d9dc4a 100644
--- a/auto_tests/run_auto_test.h
+++ b/auto_tests/run_auto_test.h
@@ -48,6 +48,15 @@ static uint64_t get_state_clock_callback(Mono_Time *mono_time, void *user_data)
48 return state->clock; 48 return state->clock;
49} 49}
50 50
51static void set_mono_time_callback(Tox *tox, State *state)
52{
53 // TODO(iphydf): Don't rely on toxcore internals.
54 Mono_Time *mono_time = ((Messenger *)tox)->mono_time;
55
56 state->clock = current_time_monotonic(mono_time);
57 mono_time_set_current_time_callback(mono_time, get_state_clock_callback, state);
58}
59
51static void run_auto_test(uint32_t tox_count, void test(Tox **toxes, State *state), bool chain) 60static void run_auto_test(uint32_t tox_count, void test(Tox **toxes, State *state), bool chain)
52{ 61{
53 printf("initialising %u toxes\n", tox_count); 62 printf("initialising %u toxes\n", tox_count);
@@ -59,11 +68,7 @@ static void run_auto_test(uint32_t tox_count, void test(Tox **toxes, State *stat
59 toxes[i] = tox_new_log(nullptr, nullptr, &state[i].index); 68 toxes[i] = tox_new_log(nullptr, nullptr, &state[i].index);
60 ck_assert_msg(toxes[i], "failed to create %u tox instances", i + 1); 69 ck_assert_msg(toxes[i], "failed to create %u tox instances", i + 1);
61 70
62 // TODO(iphydf): Don't rely on toxcore internals. 71 set_mono_time_callback(toxes[i], &state[i]);
63 Mono_Time *mono_time = (*(Messenger **)toxes[i])->mono_time;
64
65 state[i].clock = current_time_monotonic(mono_time);
66 mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &state[i]);
67 } 72 }
68 73
69 if (chain) { 74 if (chain) {
diff --git a/toxav/groupav.c b/toxav/groupav.c
index 4c16d1de..f49848de 100644
--- a/toxav/groupav.c
+++ b/toxav/groupav.c
@@ -433,14 +433,19 @@ static int handle_group_audio_packet(void *object, uint32_t groupnumber, uint32_
433 return 0; 433 return 0;
434} 434}
435 435
436/* Convert groupchat to an A/V groupchat. 436/* Enable A/V in a groupchat.
437 * 437 *
438 * return 0 on success. 438 * return 0 on success.
439 * return -1 on failure. 439 * return -1 on failure.
440 */ 440 */
441static int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber, 441int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
442 audio_data_cb *audio_callback, void *userdata) 442 audio_data_cb *audio_callback, void *userdata)
443{ 443{
444 if (group_get_type(g_c, groupnumber) != GROUPCHAT_TYPE_AV
445 || group_get_object(g_c, groupnumber) != nullptr) {
446 return -1;
447 }
448
444 Group_AV *group_av = new_group_av(log, tox, g_c, audio_callback, userdata); 449 Group_AV *group_av = new_group_av(log, tox, g_c, audio_callback, userdata);
445 450
446 if (group_av == nullptr) { 451 if (group_av == nullptr) {
@@ -455,10 +460,52 @@ static int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, ui
455 return -1; 460 return -1;
456 } 461 }
457 462
463 int numpeers = group_number_peers(g_c, groupnumber, false);
464
465 for (uint32_t i = 0; i < numpeers; ++i) {
466 group_av_peer_new(group_av, groupnumber, i);
467 }
468
458 group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet); 469 group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet);
459 return 0; 470 return 0;
460} 471}
461 472
473/* Disable A/V in a groupchat.
474 *
475 * return 0 on success.
476 * return -1 on failure.
477 */
478int groupchat_disable_av(Group_Chats *g_c, uint32_t groupnumber)
479{
480 if (group_get_type(g_c, groupnumber) != GROUPCHAT_TYPE_AV) {
481 return -1;
482 }
483
484 Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
485
486 if (group_av == nullptr) {
487 return -1;
488 }
489
490 int numpeers = group_number_peers(g_c, groupnumber, false);
491
492 for (uint32_t i = 0; i < numpeers; ++i) {
493 group_av_peer_delete(group_av, groupnumber, group_peer_get_object(g_c, groupnumber, i));
494 group_peer_set_object(g_c, groupnumber, i, nullptr);
495 }
496
497 kill_group_av(group_av);
498
499 if (group_set_object(g_c, groupnumber, nullptr) == -1
500 || callback_groupchat_peer_new(g_c, groupnumber, nullptr) == -1
501 || callback_groupchat_peer_delete(g_c, groupnumber, nullptr) == -1
502 || callback_groupchat_delete(g_c, groupnumber, nullptr) == -1) {
503 return -1;
504 }
505
506 return 0;
507}
508
462/* Create a new toxav group. 509/* Create a new toxav group.
463 * 510 *
464 * return group number on success. 511 * return group number on success.
diff --git a/toxav/groupav.h b/toxav/groupav.h
index a65921a4..45ff1d60 100644
--- a/toxav/groupav.h
+++ b/toxav/groupav.h
@@ -59,5 +59,19 @@ int join_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t fr
59int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, 59int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
60 uint32_t sample_rate); 60 uint32_t sample_rate);
61 61
62/* Enable A/V in a groupchat.
63 *
64 * return 0 on success.
65 * return -1 on failure.
66 */
67int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
68 audio_data_cb *audio_callback, void *userdata);
69
70/* Disable A/V in a groupchat.
71 *
72 * return 0 on success.
73 * return -1 on failure.
74 */
75int groupchat_disable_av(Group_Chats *g_c, uint32_t groupnumber);
62 76
63#endif // C_TOXCORE_TOXAV_GROUPAV_H 77#endif // C_TOXCORE_TOXAV_GROUPAV_H
diff --git a/toxav/toxav.api.h b/toxav/toxav.api.h
index 14c6a8e1..84c006b7 100644
--- a/toxav/toxav.api.h
+++ b/toxav/toxav.api.h
@@ -654,6 +654,27 @@ int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data
654int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, 654int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
655 uint32_t sample_rate); 655 uint32_t sample_rate);
656 656
657/* Enable A/V in a groupchat.
658 *
659 * return 0 on success.
660 * return -1 on failure.
661 *
662 * Audio data callback format (same as the one for toxav_add_av_groupchat()):
663 * audio_callback(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t sample_rate, void *userdata)
664 *
665 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
666 */
667int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber,
668 void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
669 void *userdata);
670
671/* Disable A/V in a groupchat.
672 *
673 * return 0 on success.
674 * return -1 on failure.
675 */
676int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber);
677
657#ifdef __cplusplus 678#ifdef __cplusplus
658} 679}
659#endif 680#endif
diff --git a/toxav/toxav.h b/toxav/toxav.h
index bc634e91..6c1ea093 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -782,6 +782,27 @@ int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data
782int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, 782int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
783 uint32_t sample_rate); 783 uint32_t sample_rate);
784 784
785/* Enable A/V in a groupchat.
786 *
787 * return 0 on success.
788 * return -1 on failure.
789 *
790 * Audio data callback format (same as the one for toxav_add_av_groupchat()):
791 * audio_callback(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t sample_rate, void *userdata)
792 *
793 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
794 */
795int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber,
796 void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
797 void *userdata);
798
799/* Disable A/V in a groupchat.
800 *
801 * return 0 on success.
802 * return -1 on failure.
803 */
804int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber);
805
785#ifdef __cplusplus 806#ifdef __cplusplus
786} 807}
787#endif 808#endif
diff --git a/toxav/toxav_old.c b/toxav/toxav_old.c
index e9850973..af9980b0 100644
--- a/toxav/toxav_old.c
+++ b/toxav/toxav_old.c
@@ -80,3 +80,32 @@ int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, u
80 Messenger *m = *(Messenger **)tox; 80 Messenger *m = *(Messenger **)tox;
81 return group_send_audio(m->conferences_object, groupnumber, pcm, samples, channels, sample_rate); 81 return group_send_audio(m->conferences_object, groupnumber, pcm, samples, channels, sample_rate);
82} 82}
83
84/* Enable A/V in a groupchat.
85 *
86 * return 0 on success.
87 * return -1 on failure.
88 *
89 * Audio data callback format (same as the one for toxav_add_av_groupchat()):
90 * audio_callback(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t sample_rate, void *userdata)
91 *
92 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
93 */
94int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber, audio_data_cb *audio_callback, void *userdata)
95{
96 // TODO(iphydf): Don't rely on toxcore internals.
97 Messenger *m = *(Messenger **)tox;
98 return groupchat_enable_av(m->log, tox, m->conferences_object, groupnumber, audio_callback, userdata);
99}
100
101/* Disable A/V in a groupchat.
102 *
103 * return 0 on success.
104 * return -1 on failure.
105 */
106int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber)
107{
108 // TODO(iphydf): Don't rely on toxcore internals.
109 Messenger *m = *(Messenger **)tox;
110 return groupchat_disable_av(m->conferences_object, groupnumber);
111}
diff --git a/toxcore/group.c b/toxcore/group.c
index 101c1196..20ee5459 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -539,9 +539,7 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
539 539
540 ++g->numpeers; 540 ++g->numpeers;
541 541
542 if (!delete_frozen(g, frozen_index)) { 542 delete_frozen(g, frozen_index);
543 return -1;
544 }
545 543
546 if (g_c->peer_list_changed_callback) { 544 if (g_c->peer_list_changed_callback) {
547 g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata); 545 g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata);
@@ -774,6 +772,7 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v
774 772
775 g->frozen = temp; 773 g->frozen = temp;
776 g->frozen[g->numfrozen] = g->group[peer_index]; 774 g->frozen[g->numfrozen] = g->group[peer_index];
775 g->frozen[g->numfrozen].object = nullptr;
777 ++g->numfrozen; 776 ++g->numfrozen;
778 777
779 return delpeer(g_c, groupnumber, peer_index, userdata, true); 778 return delpeer(g_c, groupnumber, peer_index, userdata, true);
@@ -2831,6 +2830,12 @@ static unsigned int lossy_packet_not_received(const Group_c *g, int peer_index,
2831 2830
2832} 2831}
2833 2832
2833/* Does this group type make use of lossy packets? */
2834static bool type_uses_lossy(uint8_t type)
2835{
2836 return (type == GROUPCHAT_TYPE_AV);
2837}
2838
2834static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) 2839static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata)
2835{ 2840{
2836 Group_Chats *g_c = (Group_Chats *)object; 2841 Group_Chats *g_c = (Group_Chats *)object;
@@ -2857,6 +2862,10 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2857 return -1; 2862 return -1;
2858 } 2863 }
2859 2864
2865 if (!type_uses_lossy(g->type)) {
2866 return -1;
2867 }
2868
2860 const int index = friend_in_close(g, friendcon_id); 2869 const int index = friend_in_close(g, friendcon_id);
2861 2870
2862 if (index == -1) { 2871 if (index == -1) {
@@ -2883,6 +2892,8 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2883 ++lossy_data; 2892 ++lossy_data;
2884 --lossy_length; 2893 --lossy_length;
2885 2894
2895 send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
2896
2886 if (g_c->lossy_packethandlers[message_id].function) { 2897 if (g_c->lossy_packethandlers[message_id].function) {
2887 if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object, 2898 if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object,
2888 lossy_data, lossy_length) == -1) { 2899 lossy_data, lossy_length) == -1) {
@@ -2892,7 +2903,6 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2892 return -1; 2903 return -1;
2893 } 2904 }
2894 2905
2895 send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
2896 return 0; 2906 return 0;
2897} 2907}
2898 2908
@@ -2934,7 +2944,7 @@ int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peer
2934 return 0; 2944 return 0;
2935} 2945}
2936 2946
2937/* Return the object tide to the group chat previously set by group_set_object. 2947/* Return the object tied to the group chat previously set by group_set_object.
2938 * 2948 *
2939 * return NULL on failure. 2949 * return NULL on failure.
2940 * return object on success. 2950 * return object on success.
@@ -2950,7 +2960,7 @@ void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber)
2950 return g->object; 2960 return g->object;
2951} 2961}
2952 2962
2953/* Return the object tide to the group chat peer previously set by group_peer_set_object. 2963/* Return the object tied to the group chat peer previously set by group_peer_set_object.
2954 * 2964 *
2955 * return NULL on failure. 2965 * return NULL on failure.
2956 * return object on success. 2966 * return object on success.