mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Expose api functions for enabling and disabling AV in AV groups
A group loaded from a savefile starts with AV disabled.
This commit is contained in:
parent
0aad180d1e
commit
49e2406ffa
|
@ -434,6 +434,7 @@ auto_test(version)
|
|||
auto_test(save_compatibility)
|
||||
|
||||
if(BUILD_TOXAV)
|
||||
auto_test(conference_av)
|
||||
auto_test(toxav_basic)
|
||||
auto_test(toxav_many)
|
||||
endif()
|
||||
|
|
|
@ -57,7 +57,7 @@ AUTOTEST_LDADD = \
|
|||
|
||||
|
||||
if BUILD_AV
|
||||
TESTS += toxav_basic_test toxav_many_test
|
||||
TESTS += conference_av_test toxav_basic_test toxav_many_test
|
||||
AUTOTEST_LDADD += libtoxav.la
|
||||
endif
|
||||
|
||||
|
@ -221,6 +221,10 @@ version_test_LDADD = $(AUTOTEST_LDADD)
|
|||
|
||||
if BUILD_AV
|
||||
|
||||
conference_av_test_SOURCES = ../auto_tests/conference_av_test.c
|
||||
conference_av_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||
conference_av_test_LDADD = $(AUTOTEST_LDADD)
|
||||
|
||||
toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c
|
||||
toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||
toxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS)
|
||||
|
|
467
auto_tests/conference_av_test.c
Normal file
467
auto_tests/conference_av_test.c
Normal file
|
@ -0,0 +1,467 @@
|
|||
/* Auto Tests: Conferences AV.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../toxav/toxav.h"
|
||||
#include "check_compat.h"
|
||||
|
||||
#define NUM_AV_GROUP_TOX 16
|
||||
#define NUM_AV_DISCONNECT (NUM_AV_GROUP_TOX / 2)
|
||||
#define NUM_AV_DISABLE (NUM_AV_GROUP_TOX / 2)
|
||||
|
||||
typedef struct State {
|
||||
uint32_t index;
|
||||
uint64_t clock;
|
||||
|
||||
bool invited_next;
|
||||
|
||||
uint32_t received_audio_peers[NUM_AV_GROUP_TOX];
|
||||
uint32_t received_audio_num;
|
||||
} State;
|
||||
|
||||
#include "run_auto_test.h"
|
||||
|
||||
static void handle_self_connection_status(
|
||||
Tox *tox, Tox_Connection connection_status, void *user_data)
|
||||
{
|
||||
const State *state = (State *)user_data;
|
||||
|
||||
if (connection_status != TOX_CONNECTION_NONE) {
|
||||
printf("tox #%u: is now connected\n", state->index);
|
||||
} else {
|
||||
printf("tox #%u: is now disconnected\n", state->index);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_friend_connection_status(
|
||||
Tox *tox, uint32_t friendnumber, Tox_Connection connection_status, void *user_data)
|
||||
{
|
||||
const State *state = (State *)user_data;
|
||||
|
||||
if (connection_status != TOX_CONNECTION_NONE) {
|
||||
printf("tox #%u: is now connected to friend %u\n", state->index, friendnumber);
|
||||
} else {
|
||||
printf("tox #%u: is now disconnected from friend %u\n", state->index, friendnumber);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_callback(void *tox, uint32_t groupnumber, uint32_t peernumber,
|
||||
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
|
||||
sample_rate, void *userdata)
|
||||
{
|
||||
if (samples == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
State *state = (State *)userdata;
|
||||
|
||||
for (uint32_t i = 0; i < state->received_audio_num; ++i) {
|
||||
if (state->received_audio_peers[i] == peernumber) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ck_assert(state->received_audio_num < NUM_AV_GROUP_TOX);
|
||||
|
||||
state->received_audio_peers[state->received_audio_num] = peernumber;
|
||||
++state->received_audio_num;
|
||||
}
|
||||
|
||||
static void handle_conference_invite(
|
||||
Tox *tox, uint32_t friendnumber, Tox_Conference_Type type,
|
||||
const uint8_t *data, size_t length, void *user_data)
|
||||
{
|
||||
const State *state = (State *)user_data;
|
||||
ck_assert_msg(type == TOX_CONFERENCE_TYPE_AV, "tox #%u: wrong conference type: %d", state->index, type);
|
||||
|
||||
ck_assert_msg(toxav_join_av_groupchat(tox, friendnumber, data, length, audio_callback, user_data) == 0,
|
||||
"tox #%u: failed to join group", state->index);
|
||||
}
|
||||
|
||||
static void handle_conference_connected(
|
||||
Tox *tox, uint32_t conference_number, void *user_data)
|
||||
{
|
||||
State *state = (State *)user_data;
|
||||
|
||||
if (state->invited_next || tox_self_get_friend_list_size(tox) <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tox_Err_Conference_Invite err;
|
||||
tox_conference_invite(tox, 1, 0, &err);
|
||||
ck_assert_msg(err == TOX_ERR_CONFERENCE_INVITE_OK, "tox #%u failed to invite next friend: err = %d", state->index, err);
|
||||
printf("tox #%u: invited next friend\n", state->index);
|
||||
state->invited_next = true;
|
||||
}
|
||||
|
||||
static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
|
||||
bool *disconnected)
|
||||
{
|
||||
uint32_t num_disconnected = 0;
|
||||
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
num_disconnected += disconnected[i];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < tox_count; i++) {
|
||||
if (disconnected[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - num_disconnected) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
|
||||
const bool *disconnect, const bool *exclude)
|
||||
{
|
||||
/* Fake a network outage for a set of peers D by iterating only the other
|
||||
* peers D' until the connections time out according to D', then iterating
|
||||
* only D until the connections time out according to D. */
|
||||
|
||||
VLA(bool, disconnect_now, tox_count);
|
||||
bool invert = false;
|
||||
|
||||
do {
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
disconnect_now[i] = exclude[i] || (invert ^ disconnect[i]);
|
||||
}
|
||||
|
||||
do {
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
if (!disconnect_now[i]) {
|
||||
tox_iterate(toxes[i], &state[i]);
|
||||
state[i].clock += 1000;
|
||||
}
|
||||
}
|
||||
|
||||
c_sleep(20);
|
||||
} while (!toxes_are_disconnected_from_group(tox_count, toxes, disconnect_now));
|
||||
|
||||
invert = !invert;
|
||||
} while (invert);
|
||||
}
|
||||
|
||||
static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
|
||||
{
|
||||
for (uint32_t i = 0; i < tox_count; i++) {
|
||||
if (tox_conference_peer_count(toxes[i], 0, nullptr) < tox_count) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a random index at which a list of booleans is false
|
||||
* (some such index is required to exist)
|
||||
*/
|
||||
static uint32_t random_false_index(bool *list, const uint32_t length)
|
||||
{
|
||||
uint32_t index;
|
||||
|
||||
do {
|
||||
index = random_u32() % length;
|
||||
} while (list[index]);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static bool all_got_audio(State *state, const bool *disabled)
|
||||
{
|
||||
uint32_t num_disabled = 0;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
num_disabled += disabled[i];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
if (disabled[i] ^ (state[i].received_audio_num
|
||||
!= NUM_AV_GROUP_TOX - num_disabled - 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void reset_received_audio(Tox **toxes, State *state)
|
||||
{
|
||||
for (uint32_t j = 0; j < NUM_AV_GROUP_TOX; ++j) {
|
||||
state[j].received_audio_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define GROUP_AV_TEST_SAMPLES 960
|
||||
|
||||
/* must have
|
||||
* GROUP_AV_AUDIO_ITERATIONS - NUM_AV_GROUP_TOX >= 2^n >= GROUP_JBUF_SIZE
|
||||
* for some n, to give messages time to be relayed and to let the jitter
|
||||
* buffers fill up. */
|
||||
#define GROUP_AV_AUDIO_ITERATIONS (8 + NUM_AV_GROUP_TOX)
|
||||
|
||||
static bool test_audio(Tox **toxes, State *state, const bool *disabled, bool quiet)
|
||||
{
|
||||
if (!quiet) {
|
||||
printf("testing sending and receiving audio\n");
|
||||
}
|
||||
|
||||
int16_t PCM[GROUP_AV_TEST_SAMPLES];
|
||||
|
||||
reset_received_audio(toxes, state);
|
||||
|
||||
for (uint32_t n = 0; n < GROUP_AV_AUDIO_ITERATIONS; n++) {
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
if (disabled[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toxav_group_send_audio(toxes[i], 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) != 0) {
|
||||
if (!quiet) {
|
||||
ck_abort_msg("#%u failed to send audio", state[i].index);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
|
||||
if (all_got_audio(state, disabled)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!quiet) {
|
||||
ck_abort_msg("group failed to receive audio");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void test_eventual_audio(Tox **toxes, State *state, const bool *disabled, uint64_t timeout)
|
||||
{
|
||||
uint64_t start = state[0].clock;
|
||||
|
||||
while (state[0].clock < start + timeout) {
|
||||
if (test_audio(toxes, state, disabled, true)
|
||||
&& test_audio(toxes, state, disabled, true)) {
|
||||
printf("audio test successful after %d seconds\n", (int)((state[0].clock - start) / 1000));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("audio seems not to be getting through: testing again with errors.\n");
|
||||
test_audio(toxes, state, disabled, false);
|
||||
}
|
||||
|
||||
static void do_audio(Tox **toxes, State *state, uint32_t iterations)
|
||||
{
|
||||
int16_t PCM[GROUP_AV_TEST_SAMPLES];
|
||||
printf("running audio for %u iterations\n", iterations);
|
||||
|
||||
for (uint32_t f = 0; f < iterations; ++f) {
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
ck_assert_msg(toxav_group_send_audio(toxes[i], 0, PCM, GROUP_AV_TEST_SAMPLES, 1, 48000) == 0,
|
||||
"#%u failed to send audio", state[i].index);
|
||||
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should agree with value in groupav.c
|
||||
#define GROUP_JBUF_DEAD_SECONDS 4
|
||||
|
||||
#define JITTER_SETTLE_TIME (GROUP_JBUF_DEAD_SECONDS*1000 + NUM_AV_GROUP_TOX*ITERATION_INTERVAL*(GROUP_AV_AUDIO_ITERATIONS+1))
|
||||
|
||||
static void run_conference_tests(Tox **toxes, State *state)
|
||||
{
|
||||
bool disabled[NUM_AV_GROUP_TOX] = {0};
|
||||
|
||||
test_audio(toxes, state, disabled, false);
|
||||
|
||||
/* have everyone send audio for a bit so we can test that the audio
|
||||
* sequnums dropping to 0 on restart isn't a problem */
|
||||
do_audio(toxes, state, 20);
|
||||
|
||||
printf("letting random toxes timeout\n");
|
||||
bool disconnected[NUM_AV_GROUP_TOX] = {0};
|
||||
bool restarting[NUM_AV_GROUP_TOX] = {0};
|
||||
|
||||
ck_assert(NUM_AV_DISCONNECT < NUM_AV_GROUP_TOX);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_DISCONNECT; ++i) {
|
||||
uint32_t disconnect = random_false_index(disconnected, NUM_AV_GROUP_TOX);
|
||||
disconnected[disconnect] = true;
|
||||
|
||||
if (i < NUM_AV_DISCONNECT / 2) {
|
||||
restarting[disconnect] = true;
|
||||
printf("Restarting #%u\n", state[disconnect].index);
|
||||
} else {
|
||||
printf("Disconnecting #%u\n", state[disconnect].index);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *save[NUM_AV_GROUP_TOX];
|
||||
size_t save_size[NUM_AV_GROUP_TOX];
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
if (restarting[i]) {
|
||||
save_size[i] = tox_get_savedata_size(toxes[i]);
|
||||
ck_assert_msg(save_size[i] != 0, "save is invalid size %u", (unsigned)save_size[i]);
|
||||
save[i] = (uint8_t *)malloc(save_size[i]);
|
||||
ck_assert_msg(save[i] != nullptr, "malloc failed");
|
||||
tox_get_savedata(toxes[i], save[i]);
|
||||
tox_kill(toxes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
disconnect_toxes(NUM_AV_GROUP_TOX, toxes, state, disconnected, restarting);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
if (restarting[i]) {
|
||||
struct Tox_Options *const options = tox_options_new(nullptr);
|
||||
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||
tox_options_set_savedata_data(options, save[i], save_size[i]);
|
||||
toxes[i] = tox_new_log(options, nullptr, &state[i].index);
|
||||
tox_options_free(options);
|
||||
free(save[i]);
|
||||
|
||||
set_mono_time_callback(toxes[i], &state[i]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("reconnecting toxes\n");
|
||||
|
||||
do {
|
||||
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
} while (!all_connected_to_group(NUM_AV_GROUP_TOX, toxes));
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
if (restarting[i]) {
|
||||
ck_assert_msg(toxav_groupchat_enable_av(toxes[i], 0, audio_callback, &state[i]) == 0,
|
||||
"#%u failed to re-enable av", state[i].index);
|
||||
}
|
||||
}
|
||||
|
||||
printf("testing audio\n");
|
||||
|
||||
/* Allow time for the jitter buffers to reset and for the group to become
|
||||
* connected enough for lossy messages to get through
|
||||
* (all_connected_to_group() only checks lossless connectivity, which is a
|
||||
* looser condition). */
|
||||
test_eventual_audio(toxes, state, disabled, JITTER_SETTLE_TIME + NUM_AV_GROUP_TOX * 1000);
|
||||
|
||||
printf("testing disabling av\n");
|
||||
|
||||
ck_assert(NUM_AV_DISABLE < NUM_AV_GROUP_TOX);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) {
|
||||
uint32_t disable = random_false_index(disabled, NUM_AV_GROUP_TOX);
|
||||
disabled[disable] = true;
|
||||
printf("Disabling #%u\n", state[disable].index);
|
||||
ck_assert_msg(toxav_groupchat_enable_av(toxes[disable], 0, audio_callback, &state[disable]) != 0,
|
||||
"#%u could enable already enabled av!", state[i].index);
|
||||
ck_assert_msg(toxav_groupchat_disable_av(toxes[disable], 0) == 0,
|
||||
"#%u failed to disable av", state[i].index);
|
||||
}
|
||||
|
||||
// Run test without error to clear out messages from now-disabled peers.
|
||||
test_audio(toxes, state, disabled, true);
|
||||
|
||||
printf("testing audio with some peers having disabled their av\n");
|
||||
test_audio(toxes, state, disabled, false);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_DISABLE; ++i) {
|
||||
if (!disabled[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
disabled[i] = false;
|
||||
ck_assert_msg(toxav_groupchat_disable_av(toxes[i], 0) != 0,
|
||||
"#%u could disable already disabled av!", state[i].index);
|
||||
ck_assert_msg(toxav_groupchat_enable_av(toxes[i], 0, audio_callback, &state[i]) == 0,
|
||||
"#%u failed to re-enable av", state[i].index);
|
||||
}
|
||||
|
||||
printf("testing audio after re-enabling all av\n");
|
||||
test_eventual_audio(toxes, state, disabled, JITTER_SETTLE_TIME);
|
||||
}
|
||||
|
||||
static void test_groupav(Tox **toxes, State *state)
|
||||
{
|
||||
const time_t test_start_time = time(nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
tox_callback_self_connection_status(toxes[i], &handle_self_connection_status);
|
||||
tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status);
|
||||
tox_callback_conference_invite(toxes[i], &handle_conference_invite);
|
||||
tox_callback_conference_connected(toxes[i], &handle_conference_connected);
|
||||
}
|
||||
|
||||
ck_assert_msg(toxav_add_av_groupchat(toxes[0], audio_callback, &state[0]) != UINT32_MAX, "failed to create group");
|
||||
printf("tox #%u: inviting its first friend\n", state[0].index);
|
||||
ck_assert_msg(tox_conference_invite(toxes[0], 0, 0, nullptr) != 0, "failed to invite friend");
|
||||
state[0].invited_next = true;
|
||||
|
||||
|
||||
printf("waiting for invitations to be made\n");
|
||||
uint32_t invited_count = 0;
|
||||
|
||||
do {
|
||||
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
|
||||
invited_count = 0;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
invited_count += state[i].invited_next;
|
||||
}
|
||||
} while (invited_count != NUM_AV_GROUP_TOX - 1);
|
||||
|
||||
uint64_t pregroup_clock = state[0].clock;
|
||||
printf("waiting for all toxes to be in the group\n");
|
||||
uint32_t fully_connected_count = 0;
|
||||
|
||||
do {
|
||||
fully_connected_count = 0;
|
||||
iterate_all_wait(NUM_AV_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
|
||||
for (uint32_t i = 0; i < NUM_AV_GROUP_TOX; ++i) {
|
||||
Tox_Err_Conference_Peer_Query err;
|
||||
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err);
|
||||
|
||||
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||
peer_count = 0;
|
||||
}
|
||||
|
||||
fully_connected_count += peer_count == NUM_AV_GROUP_TOX;
|
||||
}
|
||||
} while (fully_connected_count != NUM_AV_GROUP_TOX);
|
||||
|
||||
printf("group connected, took %d seconds\n", (int)((state[0].clock - pregroup_clock) / 1000));
|
||||
|
||||
run_conference_tests(toxes, state);
|
||||
|
||||
printf("test_many_group succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
run_auto_test(NUM_AV_GROUP_TOX, test_groupav, true);
|
||||
return 0;
|
||||
}
|
|
@ -8,11 +8,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../testing/misc_tools.h"
|
||||
#include "../toxcore/crypto_core.h"
|
||||
#include "../toxcore/tox.h"
|
||||
#include "../toxcore/util.h"
|
||||
#include "check_compat.h"
|
||||
|
||||
#define NUM_GROUP_TOX 16
|
||||
|
@ -91,7 +88,7 @@ static void handle_conference_connected(
|
|||
state->invited_next = true;
|
||||
}
|
||||
|
||||
static uint16_t num_recv;
|
||||
static uint32_t num_recv;
|
||||
|
||||
static void handle_conference_message(
|
||||
Tox *tox, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
|
||||
|
@ -102,15 +99,21 @@ static void handle_conference_message(
|
|||
}
|
||||
}
|
||||
|
||||
static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes, int disconnected_count,
|
||||
static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes,
|
||||
bool *disconnected)
|
||||
{
|
||||
uint32_t num_disconnected = 0;
|
||||
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
num_disconnected += disconnected[i];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < tox_count; i++) {
|
||||
if (disconnected[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - NUM_DISCONNECT) {
|
||||
if (tox_conference_peer_count(toxes[i], 0, nullptr) > tox_count - num_disconnected) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +121,36 @@ static bool toxes_are_disconnected_from_group(uint32_t tox_count, Tox **toxes, i
|
|||
return true;
|
||||
}
|
||||
|
||||
static void disconnect_toxes(uint32_t tox_count, Tox **toxes, State *state,
|
||||
const bool *disconnect, const bool *exclude)
|
||||
{
|
||||
/* Fake a network outage for a set of peers D by iterating only the other
|
||||
* peers D' until the connections time out according to D', then iterating
|
||||
* only D until the connections time out according to D. */
|
||||
|
||||
VLA(bool, disconnect_now, tox_count);
|
||||
bool invert = false;
|
||||
|
||||
do {
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
disconnect_now[i] = exclude[i] || (invert ^ disconnect[i]);
|
||||
}
|
||||
|
||||
do {
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
if (!disconnect_now[i]) {
|
||||
tox_iterate(toxes[i], &state[i]);
|
||||
state[i].clock += 1000;
|
||||
}
|
||||
}
|
||||
|
||||
c_sleep(20);
|
||||
} while (!toxes_are_disconnected_from_group(tox_count, toxes, disconnect_now));
|
||||
|
||||
invert = !invert;
|
||||
} while (invert);
|
||||
}
|
||||
|
||||
static bool all_connected_to_group(uint32_t tox_count, Tox **toxes)
|
||||
{
|
||||
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)
|
|||
|
||||
static bool names_propagated(uint32_t tox_count, Tox **toxes, State *state)
|
||||
{
|
||||
for (uint16_t i = 0; i < tox_count; ++i) {
|
||||
for (uint16_t j = 0; j < tox_count; ++j) {
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
for (uint32_t j = 0; j < tox_count; ++j) {
|
||||
const size_t len = tox_conference_peer_get_name_size(toxes[i], 0, j, nullptr);
|
||||
|
||||
if (len != NAMELEN) {
|
||||
|
@ -145,9 +178,10 @@ static bool names_propagated(uint32_t tox_count, Tox **toxes, State *state)
|
|||
}
|
||||
|
||||
|
||||
/* returns a random index at which a list of booleans is false
|
||||
/**
|
||||
* returns a random index at which a list of booleans is false
|
||||
* (some such index is required to exist)
|
||||
* */
|
||||
*/
|
||||
static uint32_t random_false_index(bool *list, const uint32_t length)
|
||||
{
|
||||
uint32_t index;
|
||||
|
@ -171,7 +205,7 @@ static void run_conference_tests(Tox **toxes, State *state)
|
|||
|
||||
ck_assert(NUM_DISCONNECT < NUM_GROUP_TOX);
|
||||
|
||||
for (uint16_t i = 0; i < NUM_DISCONNECT; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_DISCONNECT; ++i) {
|
||||
uint32_t disconnect = random_false_index(disconnected, NUM_GROUP_TOX);
|
||||
disconnected[disconnect] = true;
|
||||
|
||||
|
@ -186,7 +220,7 @@ static void run_conference_tests(Tox **toxes, State *state)
|
|||
uint8_t *save[NUM_GROUP_TOX];
|
||||
size_t save_size[NUM_GROUP_TOX];
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
if (restarting[i]) {
|
||||
save_size[i] = tox_get_savedata_size(toxes[i]);
|
||||
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)
|
|||
}
|
||||
}
|
||||
|
||||
do {
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
if (!disconnected[i]) {
|
||||
tox_iterate(toxes[i], &state[i]);
|
||||
state[i].clock += 1000;
|
||||
}
|
||||
}
|
||||
disconnect_toxes(NUM_GROUP_TOX, toxes, state, disconnected, restarting);
|
||||
|
||||
c_sleep(20);
|
||||
} while (!toxes_are_disconnected_from_group(NUM_GROUP_TOX, toxes, NUM_DISCONNECT, disconnected));
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
if (restarting[i]) {
|
||||
struct Tox_Options *const options = tox_options_new(nullptr);
|
||||
tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||
|
@ -216,13 +241,15 @@ static void run_conference_tests(Tox **toxes, State *state)
|
|||
toxes[i] = tox_new_log(options, nullptr, &state[i].index);
|
||||
tox_options_free(options);
|
||||
free(save[i]);
|
||||
|
||||
set_mono_time_callback(toxes[i], &state[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (check_name_change_propagation) {
|
||||
printf("changing names\n");
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
char name[NAMELEN + 1];
|
||||
snprintf(name, NAMELEN + 1, NEW_NAME_FORMAT_STR, state[i].index);
|
||||
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)
|
|||
|
||||
printf("running conference tests\n");
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
tox_callback_conference_message(toxes[i], &handle_conference_message);
|
||||
|
||||
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
|
@ -259,8 +286,8 @@ static void run_conference_tests(Tox **toxes, State *state)
|
|||
ck_assert_msg(num_recv == NUM_GROUP_TOX, "failed to recv group messages");
|
||||
|
||||
if (check_name_change_propagation) {
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint16_t j = 0; j < NUM_GROUP_TOX; ++j) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t j = 0; j < NUM_GROUP_TOX; ++j) {
|
||||
uint8_t name[NAMELEN];
|
||||
tox_conference_peer_get_name(toxes[i], 0, j, name, nullptr);
|
||||
/* Note the toxes will have been reordered */
|
||||
|
@ -270,14 +297,14 @@ static void run_conference_tests(Tox **toxes, State *state)
|
|||
}
|
||||
}
|
||||
|
||||
for (uint16_t k = NUM_GROUP_TOX; k != 0 ; --k) {
|
||||
for (uint32_t k = NUM_GROUP_TOX; k != 0 ; --k) {
|
||||
tox_conference_delete(toxes[k - 1], 0, nullptr);
|
||||
|
||||
for (uint8_t j = 0; j < 10 || j < NUM_GROUP_TOX; ++j) {
|
||||
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < k - 1; ++i) {
|
||||
for (uint32_t i = 0; i < k - 1; ++i) {
|
||||
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr);
|
||||
ck_assert_msg(peer_count == (k - 1), "\n\tBad number of group peers (post check)."
|
||||
"\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)
|
|||
{
|
||||
const time_t test_start_time = time(nullptr);
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
tox_callback_self_connection_status(toxes[i], &handle_self_connection_status);
|
||||
tox_callback_friend_connection_status(toxes[i], &handle_friend_connection_status);
|
||||
tox_callback_conference_invite(toxes[i], &handle_conference_invite);
|
||||
|
@ -310,21 +337,21 @@ static void test_many_group(Tox **toxes, State *state)
|
|||
|
||||
|
||||
printf("waiting for invitations to be made\n");
|
||||
uint16_t invited_count = 0;
|
||||
uint32_t invited_count = 0;
|
||||
|
||||
do {
|
||||
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
|
||||
invited_count = 0;
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
invited_count += state[i].invited_next;
|
||||
}
|
||||
} while (invited_count != NUM_GROUP_TOX - 1);
|
||||
|
||||
uint64_t pregroup_clock = state[0].clock;
|
||||
printf("waiting for all toxes to be in the group\n");
|
||||
uint16_t fully_connected_count = 0;
|
||||
uint32_t fully_connected_count = 0;
|
||||
|
||||
do {
|
||||
fully_connected_count = 0;
|
||||
|
@ -332,7 +359,7 @@ static void test_many_group(Tox **toxes, State *state)
|
|||
|
||||
iterate_all_wait(NUM_GROUP_TOX, toxes, state, ITERATION_INTERVAL);
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
Tox_Err_Conference_Peer_Query err;
|
||||
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, &err);
|
||||
|
||||
|
@ -353,7 +380,7 @@ static void test_many_group(Tox **toxes, State *state)
|
|||
fflush(stdout);
|
||||
} while (fully_connected_count != NUM_GROUP_TOX);
|
||||
|
||||
for (uint16_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
for (uint32_t i = 0; i < NUM_GROUP_TOX; ++i) {
|
||||
uint32_t peer_count = tox_conference_peer_count(toxes[i], 0, nullptr);
|
||||
|
||||
ck_assert_msg(peer_count == NUM_GROUP_TOX, "\n\tBad number of group peers (pre check)."
|
||||
|
|
|
@ -48,6 +48,15 @@ static uint64_t get_state_clock_callback(Mono_Time *mono_time, void *user_data)
|
|||
return state->clock;
|
||||
}
|
||||
|
||||
static void set_mono_time_callback(Tox *tox, State *state)
|
||||
{
|
||||
// TODO(iphydf): Don't rely on toxcore internals.
|
||||
Mono_Time *mono_time = ((Messenger *)tox)->mono_time;
|
||||
|
||||
state->clock = current_time_monotonic(mono_time);
|
||||
mono_time_set_current_time_callback(mono_time, get_state_clock_callback, state);
|
||||
}
|
||||
|
||||
static void run_auto_test(uint32_t tox_count, void test(Tox **toxes, State *state), bool chain)
|
||||
{
|
||||
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
|
|||
toxes[i] = tox_new_log(nullptr, nullptr, &state[i].index);
|
||||
ck_assert_msg(toxes[i], "failed to create %u tox instances", i + 1);
|
||||
|
||||
// TODO(iphydf): Don't rely on toxcore internals.
|
||||
Mono_Time *mono_time = (*(Messenger **)toxes[i])->mono_time;
|
||||
|
||||
state[i].clock = current_time_monotonic(mono_time);
|
||||
mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &state[i]);
|
||||
set_mono_time_callback(toxes[i], &state[i]);
|
||||
}
|
||||
|
||||
if (chain) {
|
||||
|
|
|
@ -433,14 +433,19 @@ static int handle_group_audio_packet(void *object, uint32_t groupnumber, uint32_
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Convert groupchat to an A/V groupchat.
|
||||
/* Enable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
static int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
|
||||
audio_data_cb *audio_callback, void *userdata)
|
||||
int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
|
||||
audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
if (group_get_type(g_c, groupnumber) != GROUPCHAT_TYPE_AV
|
||||
|| group_get_object(g_c, groupnumber) != nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Group_AV *group_av = new_group_av(log, tox, g_c, audio_callback, userdata);
|
||||
|
||||
if (group_av == nullptr) {
|
||||
|
@ -455,10 +460,52 @@ static int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, ui
|
|||
return -1;
|
||||
}
|
||||
|
||||
int numpeers = group_number_peers(g_c, groupnumber, false);
|
||||
|
||||
for (uint32_t i = 0; i < numpeers; ++i) {
|
||||
group_av_peer_new(group_av, groupnumber, i);
|
||||
}
|
||||
|
||||
group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
int groupchat_disable_av(Group_Chats *g_c, uint32_t groupnumber)
|
||||
{
|
||||
if (group_get_type(g_c, groupnumber) != GROUPCHAT_TYPE_AV) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
|
||||
|
||||
if (group_av == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int numpeers = group_number_peers(g_c, groupnumber, false);
|
||||
|
||||
for (uint32_t i = 0; i < numpeers; ++i) {
|
||||
group_av_peer_delete(group_av, groupnumber, group_peer_get_object(g_c, groupnumber, i));
|
||||
group_peer_set_object(g_c, groupnumber, i, nullptr);
|
||||
}
|
||||
|
||||
kill_group_av(group_av);
|
||||
|
||||
if (group_set_object(g_c, groupnumber, nullptr) == -1
|
||||
|| callback_groupchat_peer_new(g_c, groupnumber, nullptr) == -1
|
||||
|| callback_groupchat_peer_delete(g_c, groupnumber, nullptr) == -1
|
||||
|| callback_groupchat_delete(g_c, groupnumber, nullptr) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a new toxav group.
|
||||
*
|
||||
* return group number on success.
|
||||
|
|
|
@ -59,5 +59,19 @@ int join_av_groupchat(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t fr
|
|||
int group_send_audio(Group_Chats *g_c, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate);
|
||||
|
||||
/* Enable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
int groupchat_enable_av(const Logger *log, Tox *tox, Group_Chats *g_c, uint32_t groupnumber,
|
||||
audio_data_cb *audio_callback, void *userdata);
|
||||
|
||||
/* Disable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
int groupchat_disable_av(Group_Chats *g_c, uint32_t groupnumber);
|
||||
|
||||
#endif // C_TOXCORE_TOXAV_GROUPAV_H
|
||||
|
|
|
@ -654,6 +654,27 @@ int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data
|
|||
int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate);
|
||||
|
||||
/* Enable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*
|
||||
* Audio data callback format (same as the one for toxav_add_av_groupchat()):
|
||||
* 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)
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
|
||||
*/
|
||||
int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber,
|
||||
void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
|
||||
void *userdata);
|
||||
|
||||
/* Disable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -782,6 +782,27 @@ int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data
|
|||
int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||
uint32_t sample_rate);
|
||||
|
||||
/* Enable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*
|
||||
* Audio data callback format (same as the one for toxav_add_av_groupchat()):
|
||||
* 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)
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
|
||||
*/
|
||||
int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber,
|
||||
void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
|
||||
void *userdata);
|
||||
|
||||
/* Disable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -80,3 +80,32 @@ int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, u
|
|||
Messenger *m = *(Messenger **)tox;
|
||||
return group_send_audio(m->conferences_object, groupnumber, pcm, samples, channels, sample_rate);
|
||||
}
|
||||
|
||||
/* Enable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*
|
||||
* Audio data callback format (same as the one for toxav_add_av_groupchat()):
|
||||
* 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)
|
||||
*
|
||||
* Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
|
||||
*/
|
||||
int toxav_groupchat_enable_av(Tox *tox, uint32_t groupnumber, audio_data_cb *audio_callback, void *userdata)
|
||||
{
|
||||
// TODO(iphydf): Don't rely on toxcore internals.
|
||||
Messenger *m = *(Messenger **)tox;
|
||||
return groupchat_enable_av(m->log, tox, m->conferences_object, groupnumber, audio_callback, userdata);
|
||||
}
|
||||
|
||||
/* Disable A/V in a groupchat.
|
||||
*
|
||||
* return 0 on success.
|
||||
* return -1 on failure.
|
||||
*/
|
||||
int toxav_groupchat_disable_av(Tox *tox, uint32_t groupnumber)
|
||||
{
|
||||
// TODO(iphydf): Don't rely on toxcore internals.
|
||||
Messenger *m = *(Messenger **)tox;
|
||||
return groupchat_disable_av(m->conferences_object, groupnumber);
|
||||
}
|
||||
|
|
|
@ -539,9 +539,7 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
|
|||
|
||||
++g->numpeers;
|
||||
|
||||
if (!delete_frozen(g, frozen_index)) {
|
||||
return -1;
|
||||
}
|
||||
delete_frozen(g, frozen_index);
|
||||
|
||||
if (g_c->peer_list_changed_callback) {
|
||||
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
|
|||
|
||||
g->frozen = temp;
|
||||
g->frozen[g->numfrozen] = g->group[peer_index];
|
||||
g->frozen[g->numfrozen].object = nullptr;
|
||||
++g->numfrozen;
|
||||
|
||||
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,
|
|||
|
||||
}
|
||||
|
||||
/* Does this group type make use of lossy packets? */
|
||||
static bool type_uses_lossy(uint8_t type)
|
||||
{
|
||||
return (type == GROUPCHAT_TYPE_AV);
|
||||
}
|
||||
|
||||
static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
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
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!type_uses_lossy(g->type)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int index = friend_in_close(g, friendcon_id);
|
||||
|
||||
if (index == -1) {
|
||||
|
@ -2883,6 +2892,8 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
|
|||
++lossy_data;
|
||||
--lossy_length;
|
||||
|
||||
send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
|
||||
|
||||
if (g_c->lossy_packethandlers[message_id].function) {
|
||||
if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object,
|
||||
lossy_data, lossy_length) == -1) {
|
||||
|
@ -2892,7 +2903,6 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
|
|||
return -1;
|
||||
}
|
||||
|
||||
send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2934,7 +2944,7 @@ int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peer
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return the object tide to the group chat previously set by group_set_object.
|
||||
/* Return the object tied to the group chat previously set by group_set_object.
|
||||
*
|
||||
* return NULL on failure.
|
||||
* return object on success.
|
||||
|
@ -2950,7 +2960,7 @@ void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber)
|
|||
return g->object;
|
||||
}
|
||||
|
||||
/* Return the object tide to the group chat peer previously set by group_peer_set_object.
|
||||
/* Return the object tied to the group chat peer previously set by group_peer_set_object.
|
||||
*
|
||||
* return NULL on failure.
|
||||
* return object on success.
|
||||
|
|
Loading…
Reference in New Issue
Block a user