mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Merge branch 'mannol1-Multicalls' into multi-av
This commit is contained in:
commit
82e38883a2
|
@ -3,7 +3,6 @@ if BUILD_TESTS
|
||||||
TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
|
TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
|
||||||
check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
|
check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
|
||||||
|
|
||||||
|
|
||||||
AUTOTEST_CFLAGS = \
|
AUTOTEST_CFLAGS = \
|
||||||
$(LIBSODIUM_CFLAGS) \
|
$(LIBSODIUM_CFLAGS) \
|
||||||
$(NACL_CFLAGS) \
|
$(NACL_CFLAGS) \
|
||||||
|
@ -19,9 +18,10 @@ AUTOTEST_LDADD = \
|
||||||
$(CHECK_LIBS)
|
$(CHECK_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if BUILD_AV
|
if BUILD_AV
|
||||||
TESTS += toxav_basic_test
|
TESTS += toxav_basic_test toxav_many_test
|
||||||
check_PROGRAMS += toxav_basic_test
|
check_PROGRAMS += toxav_basic_test toxav_many_test
|
||||||
AUTOTEST_LDADD += libtoxav.la
|
AUTOTEST_LDADD += libtoxav.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -74,12 +74,20 @@ tox_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||||
tox_test_LDADD = $(AUTOTEST_LDADD)
|
tox_test_LDADD = $(AUTOTEST_LDADD)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if BUILD_AV
|
if BUILD_AV
|
||||||
toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c
|
toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c
|
||||||
|
|
||||||
toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||||
|
|
||||||
toxav_basic_test_LDADD = $(AUTOTEST_LDADD)
|
toxav_basic_test_LDADD = $(AUTOTEST_LDADD)
|
||||||
|
|
||||||
|
|
||||||
|
toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c
|
||||||
|
|
||||||
|
toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||||
|
|
||||||
|
toxav_many_test_LDADD = $(AUTOTEST_LDADD)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -235,6 +235,7 @@ START_TEST(test_few_clients)
|
||||||
uint8_t *f_data = malloc(fpiece_size);
|
uint8_t *f_data = malloc(fpiece_size);
|
||||||
uint8_t num = 0;
|
uint8_t num = 0;
|
||||||
memset(f_data, num, fpiece_size);
|
memset(f_data, num, fpiece_size);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
file_sent = 0;
|
file_sent = 0;
|
||||||
tox_do(tox1);
|
tox_do(tox1);
|
||||||
|
@ -247,6 +248,7 @@ START_TEST(test_few_clients)
|
||||||
sendf_ok = 0;
|
sendf_ok = 0;
|
||||||
tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0);
|
tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
++num;
|
++num;
|
||||||
memset(f_data, num, fpiece_size);
|
memset(f_data, num, fpiece_size);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "../toxcore/tox.h"
|
#include "../toxcore/tox.h"
|
||||||
|
#include "../toxcore/logger.h"
|
||||||
|
#include "../toxcore/crypto_core.h"
|
||||||
#include "../toxav/toxav.h"
|
#include "../toxav/toxav.h"
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
||||||
|
@ -22,6 +24,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum _CallStatus {
|
typedef enum _CallStatus {
|
||||||
none,
|
none,
|
||||||
InCall,
|
InCall,
|
||||||
|
@ -36,6 +39,7 @@ typedef struct _Party {
|
||||||
CallStatus status;
|
CallStatus status;
|
||||||
ToxAv *av;
|
ToxAv *av;
|
||||||
time_t *CallStarted;
|
time_t *CallStarted;
|
||||||
|
int call_index;
|
||||||
} Party;
|
} Party;
|
||||||
|
|
||||||
typedef struct _Status {
|
typedef struct _Status {
|
||||||
|
@ -43,44 +47,46 @@ typedef struct _Status {
|
||||||
Party Bob;
|
Party Bob;
|
||||||
} Status;
|
} Status;
|
||||||
|
|
||||||
|
/* My default settings */
|
||||||
|
static ToxAvCodecSettings muhcaps;
|
||||||
|
|
||||||
void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
|
void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
|
||||||
{
|
{
|
||||||
if (length == 15 && memcmp("ILIKESMALLTITS", data, 15) == 0) {
|
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
||||||
tox_add_friend_norequest(m, public_key);
|
tox_add_friend_norequest(m, public_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void callback_recv_invite ( void *_arg )
|
void callback_recv_invite ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Bob always receives invite */
|
/* Bob always receives invite */
|
||||||
cast->Bob.status = Ringing;
|
cast->Bob.status = Ringing;
|
||||||
|
cast->Bob.call_index = call_index;
|
||||||
}
|
}
|
||||||
void callback_recv_ringing ( void *_arg )
|
void callback_recv_ringing ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Alice always sends invite */
|
/* Alice always sends invite */
|
||||||
cast->Alice.status = Ringing;
|
cast->Alice.status = Ringing;
|
||||||
}
|
}
|
||||||
void callback_recv_starting ( void *_arg )
|
void callback_recv_starting ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Alice always sends invite */
|
/* Alice always sends invite */
|
||||||
printf("Call started on Alice side...\n");
|
printf("Call started on Alice side...\n");
|
||||||
cast->Alice.status = InCall;
|
cast->Alice.status = InCall;
|
||||||
toxav_prepare_transmission(cast->Alice.av, 1);
|
toxav_prepare_transmission(cast->Alice.av, call_index, &muhcaps, 1);
|
||||||
}
|
}
|
||||||
void callback_recv_ending ( void *_arg )
|
void callback_recv_ending ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ( cast->Alice.status == Rejected) {
|
if ( cast->Alice.status == Rejected) {
|
||||||
printf ( "Call ended for Bob!\n" );
|
printf ( "Call ended for Bob!\n" );
|
||||||
cast->Bob.status = Ended;
|
cast->Bob.status = Ended;
|
||||||
|
@ -90,28 +96,28 @@ void callback_recv_ending ( void *_arg )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_recv_error ( void *_arg )
|
void callback_recv_error ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
ck_assert_msg(0, "AV internal error");
|
ck_assert_msg(0, "AV internal error");
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_call_started ( void *_arg )
|
void callback_call_started ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Alice always sends invite */
|
/* Alice always sends invite */
|
||||||
printf("Call started on Bob side...\n");
|
printf("Call started on Bob side...\n");
|
||||||
cast->Bob.status = InCall;
|
cast->Bob.status = InCall;
|
||||||
toxav_prepare_transmission(cast->Bob.av, 1);
|
toxav_prepare_transmission(cast->Bob.av, call_index, &muhcaps, 1);
|
||||||
}
|
}
|
||||||
void callback_call_canceled ( void *_arg )
|
void callback_call_canceled ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
printf ( "Call Canceled for Bob!\n" );
|
printf ( "Call Canceled for Bob!\n" );
|
||||||
cast->Bob.status = Cancel;
|
cast->Bob.status = Cancel;
|
||||||
}
|
}
|
||||||
void callback_call_rejected ( void *_arg )
|
void callback_call_rejected ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
@ -120,7 +126,7 @@ void callback_call_rejected ( void *_arg )
|
||||||
/* If Bob rejects, call is ended for alice and she sends ending */
|
/* If Bob rejects, call is ended for alice and she sends ending */
|
||||||
cast->Alice.status = Rejected;
|
cast->Alice.status = Rejected;
|
||||||
}
|
}
|
||||||
void callback_call_ended ( void *_arg )
|
void callback_call_ended ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
@ -128,7 +134,7 @@ void callback_call_ended ( void *_arg )
|
||||||
cast->Bob.status = Ended;
|
cast->Bob.status = Ended;
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_requ_timeout ( void *_arg )
|
void callback_requ_timeout ( int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
ck_assert_msg(0, "No answer!");
|
ck_assert_msg(0, "No answer!");
|
||||||
}
|
}
|
||||||
|
@ -142,9 +148,9 @@ void callback_requ_timeout ( void *_arg )
|
||||||
tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \
|
tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \
|
||||||
switch ( step ) {\
|
switch ( step ) {\
|
||||||
case 0: /* Alice */ printf("Alice is calling...\n");\
|
case 0: /* Alice */ printf("Alice is calling...\n");\
|
||||||
toxav_call(status_control.Alice.av, 0, AliceCallType, 10); step++; break;\
|
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, AliceCallType, 10); step++; break;\
|
||||||
case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\
|
case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\
|
||||||
cur_time = time(NULL); toxav_answer(status_control.Bob.av, BobCallType); step++; } break; \
|
cur_time = time(NULL); toxav_answer(status_control.Bob.av, status_control.Bob.call_index, BobCallType); step++; } break; \
|
||||||
case 2: /* Rtp transmission */ \
|
case 2: /* Rtp transmission */ \
|
||||||
if (status_control.Bob.status == InCall && status_control.Alice.status == InCall)
|
if (status_control.Bob.status == InCall && status_control.Alice.status == InCall)
|
||||||
|
|
||||||
|
@ -153,7 +159,8 @@ void callback_requ_timeout ( void *_arg )
|
||||||
case 3: /* Wait for Both to have status ended */\
|
case 3: /* Wait for Both to have status ended */\
|
||||||
if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n");
|
if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n");
|
||||||
|
|
||||||
START_TEST(test_AV)
|
START_TEST(test_AV_flows)
|
||||||
|
// int test_AV_flows()
|
||||||
{
|
{
|
||||||
long long unsigned int cur_time = time(NULL);
|
long long unsigned int cur_time = time(NULL);
|
||||||
Tox *bootstrap_node = tox_new(0);
|
Tox *bootstrap_node = tox_new(0);
|
||||||
|
@ -166,7 +173,7 @@ START_TEST(test_AV)
|
||||||
tox_callback_friend_request(Alice, accept_friend_request, &to_compare);
|
tox_callback_friend_request(Alice, accept_friend_request, &to_compare);
|
||||||
uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
|
uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
|
||||||
tox_get_address(Alice, address);
|
tox_get_address(Alice, address);
|
||||||
int test = tox_add_friend(Bob, address, (uint8_t *)"ILIKESMALLTITS", 15);
|
int test = tox_add_friend(Bob, address, (uint8_t *)"gentoo", 7);
|
||||||
|
|
||||||
ck_assert_msg(test == 0, "Failed to add friend error code: %i", test);
|
ck_assert_msg(test == 0, "Failed to add friend error code: %i", test);
|
||||||
|
|
||||||
|
@ -191,15 +198,14 @@ START_TEST(test_AV)
|
||||||
|
|
||||||
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
||||||
|
|
||||||
ToxAvCodecSettings muhcaps = av_DefaultSettings;
|
muhcaps = av_DefaultSettings;
|
||||||
muhcaps.video_height = muhcaps.video_width = 128;
|
muhcaps.video_height = muhcaps.video_width = 128;
|
||||||
|
|
||||||
Status status_control = {
|
Status status_control = {
|
||||||
{none, toxav_new(Alice, &muhcaps), NULL},
|
{none, toxav_new(Alice, 1), NULL, -1},
|
||||||
{none, toxav_new(Bob, &muhcaps), NULL},
|
{none, toxav_new(Bob, 1), NULL, -1},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
|
ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,8 +223,13 @@ START_TEST(test_AV)
|
||||||
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
|
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
|
||||||
|
|
||||||
|
|
||||||
|
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
||||||
|
int16_t sample_payload[frame_size];
|
||||||
|
randombytes_salsa20_random_buf(sample_payload, sizeof(int16_t) * frame_size);
|
||||||
|
|
||||||
|
uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
|
||||||
|
int payload_size;
|
||||||
|
|
||||||
int16_t sample_payload[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
|
||||||
vpx_image_t *sample_image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, 128, 128, 1);
|
vpx_image_t *sample_image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, 128, 128, 1);
|
||||||
|
|
||||||
memcpy(sample_image->planes[VPX_PLANE_Y], sample_payload, 10);
|
memcpy(sample_image->planes[VPX_PLANE_Y], sample_payload, 10);
|
||||||
|
@ -233,25 +244,40 @@ START_TEST(test_AV)
|
||||||
/*
|
/*
|
||||||
* Call with audio only on both sides. Alice calls Bob.
|
* Call with audio only on both sides. Alice calls Bob.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
|
CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
|
||||||
/* Both send */
|
/* Both send */
|
||||||
toxav_send_audio(status_control.Alice.av, sample_payload, 10);
|
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
|
||||||
toxav_send_audio(status_control.Bob.av, sample_payload, 10);
|
1000, sample_payload, frame_size);
|
||||||
|
|
||||||
|
if ( payload_size < 0 ) {
|
||||||
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
|
||||||
|
|
||||||
|
payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
|
||||||
|
sample_payload, frame_size);
|
||||||
|
|
||||||
|
if ( payload_size < 0 ) {
|
||||||
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
|
||||||
|
|
||||||
/* Both receive */
|
/* Both receive */
|
||||||
int16_t storage[10];
|
int16_t storage[frame_size];
|
||||||
int recved;
|
int recved;
|
||||||
|
|
||||||
/* Payload from Alice */
|
/* Payload from Bob */
|
||||||
recved = toxav_recv_audio(status_control.Alice.av, 10, storage);
|
recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
|
||||||
|
|
||||||
if ( recved ) {
|
if ( recved ) {
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
||||||
memset(storage, 0, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Payload from Bob */
|
recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
|
||||||
recved = toxav_recv_audio(status_control.Bob.av, 10, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
if ( recved ) {
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
||||||
|
@ -259,11 +285,11 @@ START_TEST(test_AV)
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
toxav_kill_transmission(status_control.Alice.av);
|
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
toxav_kill_transmission(status_control.Bob.av);
|
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
/* Call over Alice hangs up */
|
||||||
toxav_hangup(status_control.Alice.av);
|
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TERMINATE_SCOPE()
|
TERMINATE_SCOPE()
|
||||||
|
@ -274,38 +300,52 @@ START_TEST(test_AV)
|
||||||
*/
|
*/
|
||||||
CALL_AND_START_LOOP(TypeAudio, TypeVideo) {
|
CALL_AND_START_LOOP(TypeAudio, TypeVideo) {
|
||||||
/* Both send */
|
/* Both send */
|
||||||
toxav_send_audio(status_control.Alice.av, sample_payload, 10);
|
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
|
||||||
|
1000, sample_payload, frame_size);
|
||||||
|
|
||||||
toxav_send_audio(status_control.Bob.av, sample_payload, 10);
|
if ( payload_size < 0 ) {
|
||||||
toxav_send_video(status_control.Bob.av, sample_image);
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
|
||||||
|
|
||||||
|
payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
|
||||||
|
sample_payload, frame_size);
|
||||||
|
|
||||||
|
if ( payload_size < 0 ) {
|
||||||
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
|
||||||
|
// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
|
||||||
|
|
||||||
/* Both receive */
|
/* Both receive */
|
||||||
int16_t storage[10];
|
int16_t storage[frame_size];
|
||||||
vpx_image_t *video_storage;
|
vpx_image_t *video_storage;
|
||||||
int recved;
|
int recved;
|
||||||
|
|
||||||
/* Payload from Bob */
|
/* Payload from Bob */
|
||||||
recved = toxav_recv_audio(status_control.Alice.av, 10, storage);
|
recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
|
||||||
|
|
||||||
if ( recved ) {
|
if ( recved ) {
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
||||||
memset(storage, 0, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Video payload */
|
/* Video payload */
|
||||||
toxav_recv_video(status_control.Alice.av, &video_storage);
|
// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
|
||||||
|
//
|
||||||
if ( video_storage ) {
|
// if ( video_storage ) {
|
||||||
/*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
||||||
memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
||||||
memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
|
// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
|
||||||
}
|
// vpx_img_free(video_storage);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Payload from Alice */
|
/* Payload from Alice */
|
||||||
recved = toxav_recv_audio(status_control.Bob.av, 10, storage);
|
recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
|
||||||
|
|
||||||
if ( recved ) {
|
if ( recved ) {
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
||||||
|
@ -313,11 +353,11 @@ START_TEST(test_AV)
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
toxav_kill_transmission(status_control.Alice.av);
|
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
toxav_kill_transmission(status_control.Bob.av);
|
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
/* Call over Alice hangs up */
|
||||||
toxav_hangup(status_control.Alice.av);
|
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TERMINATE_SCOPE()
|
TERMINATE_SCOPE()
|
||||||
|
@ -328,61 +368,78 @@ START_TEST(test_AV)
|
||||||
*/
|
*/
|
||||||
CALL_AND_START_LOOP(TypeVideo, TypeVideo) {
|
CALL_AND_START_LOOP(TypeVideo, TypeVideo) {
|
||||||
/* Both send */
|
/* Both send */
|
||||||
toxav_send_audio(status_control.Alice.av, sample_payload, 10);
|
|
||||||
toxav_send_video(status_control.Alice.av, sample_image);
|
|
||||||
|
|
||||||
toxav_send_audio(status_control.Bob.av, sample_payload, 10);
|
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload,
|
||||||
toxav_send_video(status_control.Bob.av, sample_image);
|
1000, sample_payload, frame_size);
|
||||||
|
|
||||||
|
if ( payload_size < 0 ) {
|
||||||
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size);
|
||||||
|
|
||||||
|
payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000,
|
||||||
|
sample_payload, frame_size);
|
||||||
|
|
||||||
|
if ( payload_size < 0 ) {
|
||||||
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
|
||||||
|
|
||||||
|
// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image);
|
||||||
|
// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
|
||||||
|
|
||||||
/* Both receive */
|
/* Both receive */
|
||||||
int16_t storage[10];
|
int16_t storage[frame_size];
|
||||||
vpx_image_t *video_storage;
|
vpx_image_t *video_storage;
|
||||||
int recved;
|
int recved;
|
||||||
|
|
||||||
/* Payload from Bob */
|
/* Payload from Bob */
|
||||||
recved = toxav_recv_audio(status_control.Alice.av, 10, storage);
|
recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
|
||||||
|
|
||||||
if ( recved ) {
|
if ( recved ) {
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
||||||
memset(storage, 0, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Video payload */
|
/* Video payload */
|
||||||
toxav_recv_video(status_control.Alice.av, &video_storage);
|
// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
|
||||||
|
//
|
||||||
if ( video_storage ) {
|
// if ( video_storage ) {
|
||||||
/*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
||||||
memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
||||||
memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
|
// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
|
||||||
}
|
// vpx_img_free(video_storage);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Payload from Alice */
|
/* Payload from Alice */
|
||||||
recved = toxav_recv_audio(status_control.Bob.av, 10, storage);
|
recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
|
||||||
|
|
||||||
if ( recved ) {
|
if ( recved ) {
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Video payload */
|
/* Video payload */
|
||||||
toxav_recv_video(status_control.Bob.av, &video_storage);
|
// toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage);
|
||||||
|
//
|
||||||
if ( video_storage ) {
|
// if ( video_storage ) {
|
||||||
/*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
||||||
memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
||||||
memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/
|
// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/
|
||||||
}
|
// vpx_img_free(video_storage);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
toxav_kill_transmission(status_control.Alice.av);
|
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
toxav_kill_transmission(status_control.Bob.av);
|
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
/* Call over Alice hangs up */
|
||||||
toxav_hangup(status_control.Alice.av);
|
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TERMINATE_SCOPE()
|
TERMINATE_SCOPE()
|
||||||
|
@ -408,15 +465,14 @@ START_TEST(test_AV)
|
||||||
switch ( step ) {
|
switch ( step ) {
|
||||||
case 0: /* Alice */
|
case 0: /* Alice */
|
||||||
printf("Alice is calling...\n");
|
printf("Alice is calling...\n");
|
||||||
toxav_call(status_control.Alice.av, 0, TypeAudio, 10);
|
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
|
||||||
step++;
|
step++;
|
||||||
break;
|
break;
|
||||||
\
|
|
||||||
|
|
||||||
case 1: /* Bob */
|
case 1: /* Bob */
|
||||||
if (status_control.Bob.status == Ringing) {
|
if (status_control.Bob.status == Ringing) {
|
||||||
printf("Bob rejects...\n");
|
printf("Bob rejects...\n");
|
||||||
toxav_reject(status_control.Bob.av, "Who likes D's anyway?");
|
toxav_reject(status_control.Bob.av, status_control.Bob.call_index, "Who likes D's anyway?");
|
||||||
step++;
|
step++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +506,7 @@ START_TEST(test_AV)
|
||||||
switch ( step ) {
|
switch ( step ) {
|
||||||
case 0: /* Alice */
|
case 0: /* Alice */
|
||||||
printf("Alice is calling...\n");
|
printf("Alice is calling...\n");
|
||||||
toxav_call(status_control.Alice.av, 0, TypeAudio, 10);
|
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
|
||||||
step++;
|
step++;
|
||||||
break;
|
break;
|
||||||
\
|
\
|
||||||
|
@ -458,14 +514,14 @@ START_TEST(test_AV)
|
||||||
case 1: /* Alice again */
|
case 1: /* Alice again */
|
||||||
if (status_control.Bob.status == Ringing) {
|
if (status_control.Bob.status == Ringing) {
|
||||||
printf("Alice cancels...\n");
|
printf("Alice cancels...\n");
|
||||||
toxav_cancel(status_control.Alice.av, 0, "Who likes D's anyway?");
|
toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?");
|
||||||
step++;
|
step++;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* Wait for Both to have status ended */
|
case 2: /* Wait for Both to have status ended */
|
||||||
if (status_control.Alice.status == Ended && status_control.Bob.status == Cancel) running = 0;
|
if (status_control.Bob.status == Cancel) running = 0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -484,15 +540,19 @@ END_TEST
|
||||||
/*************************************************************************************************/
|
/*************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************************************/
|
||||||
|
|
||||||
|
/*************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
Suite *tox_suite(void)
|
Suite *tox_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("ToxAV");
|
Suite *s = suite_create("ToxAV");
|
||||||
|
|
||||||
TCase *tc_av = tcase_create("A/V");
|
TCase *tc_av_flows = tcase_create("AV_flows");
|
||||||
tcase_add_test(tc_av, test_AV);
|
tcase_add_test(tc_av_flows, test_AV_flows);
|
||||||
tcase_set_timeout(tc_av, 100); /* Timeout on 100 too much? */
|
tcase_set_timeout(tc_av_flows, 200);
|
||||||
suite_add_tcase(s, tc_av);
|
suite_add_tcase(s, tc_av_flows);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -509,4 +569,6 @@ int main(int argc, char *argv[])
|
||||||
srunner_free(test_runner);
|
srunner_free(test_runner);
|
||||||
|
|
||||||
return number_failed;
|
return number_failed;
|
||||||
|
|
||||||
|
// return test_AV_flows();
|
||||||
}
|
}
|
||||||
|
|
406
auto_tests/toxav_many_test.c
Normal file
406
auto_tests/toxav_many_test.c
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <check.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "../toxcore/tox.h"
|
||||||
|
#include "../toxcore/logger.h"
|
||||||
|
#include "../toxcore/crypto_core.h"
|
||||||
|
#include "../toxav/toxav.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
||||||
|
#define c_sleep(x) Sleep(1*x)
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#define c_sleep(x) usleep(1000*x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum _CallStatus {
|
||||||
|
none,
|
||||||
|
InCall,
|
||||||
|
Ringing,
|
||||||
|
Ended,
|
||||||
|
Rejected,
|
||||||
|
Cancel
|
||||||
|
|
||||||
|
} CallStatus;
|
||||||
|
|
||||||
|
typedef struct _Party {
|
||||||
|
CallStatus status;
|
||||||
|
ToxAv *av;
|
||||||
|
int id;
|
||||||
|
} Party;
|
||||||
|
|
||||||
|
typedef struct _ACall {
|
||||||
|
pthread_t tid;
|
||||||
|
|
||||||
|
Party Caller;
|
||||||
|
Party Callee;
|
||||||
|
} ACall;
|
||||||
|
|
||||||
|
typedef struct _Status {
|
||||||
|
ACall calls[3]; /* Make 3 calls for this test */
|
||||||
|
} Status;
|
||||||
|
|
||||||
|
void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
|
||||||
|
{
|
||||||
|
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
||||||
|
tox_add_friend_norequest(m, public_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
void callback_recv_invite ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Callee.status = Ringing;*/
|
||||||
|
}
|
||||||
|
void callback_recv_ringing ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Caller.status = Ringing;
|
||||||
|
}
|
||||||
|
void callback_recv_starting ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Caller.status = InCall;
|
||||||
|
}
|
||||||
|
void callback_recv_ending ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Caller.status = Ended;
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_recv_error ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
ck_assert_msg(0, "AV internal error");
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_call_started ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Callee.status = InCall;*/
|
||||||
|
}
|
||||||
|
void callback_call_canceled ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Callee.status = Cancel;*/
|
||||||
|
}
|
||||||
|
void callback_call_rejected ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Caller.status = Rejected;
|
||||||
|
}
|
||||||
|
void callback_call_ended ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
cast->calls[call_index].Callee.status = Ended;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_requ_timeout ( int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
ck_assert_msg(0, "No answer!");
|
||||||
|
}
|
||||||
|
/*************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
void *in_thread_call (void *arg)
|
||||||
|
{
|
||||||
|
#define call_print(call, what, args...) printf("[%d] " what "\n", call, ##args)
|
||||||
|
|
||||||
|
ACall *this_call = arg;
|
||||||
|
uint64_t start = 0;
|
||||||
|
int step = 0, running = 1;
|
||||||
|
int call_idx;
|
||||||
|
|
||||||
|
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
||||||
|
int16_t sample_payload[frame_size];
|
||||||
|
randombytes_salsa20_random_buf(sample_payload, sizeof(int16_t) * frame_size);
|
||||||
|
|
||||||
|
uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
|
||||||
|
while (running) {
|
||||||
|
|
||||||
|
switch ( step ) {
|
||||||
|
case 0: /* CALLER */
|
||||||
|
toxav_call(this_call->Caller.av, &call_idx, this_call->Callee.id, TypeVideo, 10);
|
||||||
|
call_print(call_idx, "Calling ...");
|
||||||
|
step++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* CALLEE */
|
||||||
|
if (this_call->Caller.status == Ringing) {
|
||||||
|
call_print(call_idx, "Callee answers ...");
|
||||||
|
toxav_answer(this_call->Callee.av, 0, TypeVideo);
|
||||||
|
step++;
|
||||||
|
start = time(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* Rtp transmission */
|
||||||
|
if (this_call->Caller.status == InCall) { /* I think this is okay */
|
||||||
|
call_print(call_idx, "Sending rtp ...");
|
||||||
|
|
||||||
|
ToxAvCodecSettings cast = av_DefaultSettings;
|
||||||
|
|
||||||
|
c_sleep(1000); /* We have race condition here */
|
||||||
|
toxav_prepare_transmission(this_call->Callee.av, 0, &cast, 1);
|
||||||
|
toxav_prepare_transmission(this_call->Caller.av, call_idx, &cast, 1);
|
||||||
|
|
||||||
|
int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, RTP_PAYLOAD_SIZE,
|
||||||
|
sample_payload, frame_size);
|
||||||
|
|
||||||
|
if ( payload_size < 0 ) {
|
||||||
|
ck_assert_msg ( 0, "Failed to encode payload" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (time(NULL) - start < 10) { /* 10 seconds */
|
||||||
|
/* Both send */
|
||||||
|
toxav_send_audio(this_call->Caller.av, call_idx, prepared_payload, payload_size);
|
||||||
|
|
||||||
|
toxav_send_audio(this_call->Callee.av, 0, prepared_payload, payload_size);
|
||||||
|
|
||||||
|
/* Both receive */
|
||||||
|
int16_t storage[RTP_PAYLOAD_SIZE];
|
||||||
|
int recved;
|
||||||
|
|
||||||
|
/* Payload from CALLER */
|
||||||
|
recved = toxav_recv_audio(this_call->Callee.av, 0, frame_size, storage);
|
||||||
|
|
||||||
|
if ( recved ) {
|
||||||
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLER is invalid");*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Payload from CALLEE */
|
||||||
|
recved = toxav_recv_audio(this_call->Caller.av, call_idx, frame_size, storage);
|
||||||
|
|
||||||
|
if ( recved ) {
|
||||||
|
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLEE is invalid");*/
|
||||||
|
}
|
||||||
|
|
||||||
|
c_sleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
step++; /* This terminates the loop */
|
||||||
|
|
||||||
|
toxav_kill_transmission(this_call->Callee.av, 0);
|
||||||
|
toxav_kill_transmission(this_call->Caller.av, call_idx);
|
||||||
|
|
||||||
|
/* Call over CALLER hangs up */
|
||||||
|
toxav_hangup(this_call->Caller.av, call_idx);
|
||||||
|
call_print(call_idx, "Hanging up ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /* Wait for Both to have status ended */
|
||||||
|
if (this_call->Caller.status == Ended) {
|
||||||
|
c_sleep(1000); /* race condition */
|
||||||
|
this_call->Callee.status == Ended;
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
c_sleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
call_print(call_idx, "Call ended successfully!");
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST(test_AV_three_calls)
|
||||||
|
// void test_AV_three_calls()
|
||||||
|
{
|
||||||
|
long long unsigned int cur_time = time(NULL);
|
||||||
|
Tox *bootstrap_node = tox_new(0);
|
||||||
|
Tox *caller = tox_new(0);
|
||||||
|
Tox *callees[3] = {
|
||||||
|
tox_new(0),
|
||||||
|
tox_new(0),
|
||||||
|
tox_new(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ck_assert_msg(bootstrap_node != NULL, "Failed to create bootstrap node");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (; i < 3; i ++) {
|
||||||
|
ck_assert_msg(callees[i] != NULL, "Failed to create 3 tox instances");
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < 3; i ++ ) {
|
||||||
|
uint32_t to_compare = 974536;
|
||||||
|
tox_callback_friend_request(callees[i], accept_friend_request, &to_compare);
|
||||||
|
uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
|
||||||
|
tox_get_address(callees[i], address);
|
||||||
|
|
||||||
|
int test = tox_add_friend(caller, address, (uint8_t *)"gentoo", 7);
|
||||||
|
ck_assert_msg( test == i, "Failed to add friend error code: %i", test);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t off = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
tox_do(bootstrap_node);
|
||||||
|
tox_do(caller);
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i ++) {
|
||||||
|
tox_do(callees[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (tox_isconnected(bootstrap_node) &&
|
||||||
|
tox_isconnected(caller) &&
|
||||||
|
tox_isconnected(callees[0]) &&
|
||||||
|
tox_isconnected(callees[1]) &&
|
||||||
|
tox_isconnected(callees[2]) && off) {
|
||||||
|
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
|
||||||
|
off = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (tox_get_friend_connection_status(caller, 0) == 1 &&
|
||||||
|
tox_get_friend_connection_status(caller, 1) == 1 &&
|
||||||
|
tox_get_friend_connection_status(caller, 2) == 1 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
c_sleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
||||||
|
|
||||||
|
ToxAv *uniqcallerav = toxav_new(caller, 3);
|
||||||
|
|
||||||
|
Status status_control = {
|
||||||
|
0,
|
||||||
|
{none, uniqcallerav, 0},
|
||||||
|
{none, toxav_new(callees[0], 1), 0},
|
||||||
|
|
||||||
|
0,
|
||||||
|
{none, uniqcallerav},
|
||||||
|
{none, toxav_new(callees[1], 1), 1},
|
||||||
|
|
||||||
|
0,
|
||||||
|
{none, uniqcallerav},
|
||||||
|
{none, toxav_new(callees[2], 1), 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
|
||||||
|
|
||||||
|
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
|
||||||
|
|
||||||
|
toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
|
||||||
|
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for ( i = 0; i < 3; i++ )
|
||||||
|
pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]);
|
||||||
|
|
||||||
|
|
||||||
|
/* Now start 3 calls and they'll run for 10 s */
|
||||||
|
|
||||||
|
for ( i = 0; i < 3; i++ )
|
||||||
|
pthread_detach(status_control.calls[i].tid);
|
||||||
|
|
||||||
|
while (
|
||||||
|
status_control.calls[0].Callee.status != Ended && status_control.calls[0].Caller.status != Ended &&
|
||||||
|
status_control.calls[1].Callee.status != Ended && status_control.calls[1].Caller.status != Ended &&
|
||||||
|
status_control.calls[2].Callee.status != Ended && status_control.calls[2].Caller.status != Ended
|
||||||
|
) {
|
||||||
|
tox_do(bootstrap_node);
|
||||||
|
tox_do(caller);
|
||||||
|
tox_do(callees[0]);
|
||||||
|
tox_do(callees[1]);
|
||||||
|
tox_do(callees[2]);
|
||||||
|
c_sleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_kill(status_control.calls[0].Caller.av);
|
||||||
|
toxav_kill(status_control.calls[0].Callee.av);
|
||||||
|
toxav_kill(status_control.calls[1].Callee.av);
|
||||||
|
toxav_kill(status_control.calls[2].Callee.av);
|
||||||
|
|
||||||
|
tox_kill(bootstrap_node);
|
||||||
|
tox_kill(caller);
|
||||||
|
|
||||||
|
for ( i = 0; i < 3; i ++)
|
||||||
|
tox_kill(callees[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Suite *tox_suite(void)
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("ToxAV");
|
||||||
|
|
||||||
|
TCase *tc_av_three_calls = tcase_create("AV_three_calls");
|
||||||
|
tcase_add_test(tc_av_three_calls, test_AV_three_calls);
|
||||||
|
tcase_set_timeout(tc_av_three_calls, 150);
|
||||||
|
suite_add_tcase(s, tc_av_three_calls);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Suite *tox = tox_suite();
|
||||||
|
SRunner *test_runner = srunner_create(tox);
|
||||||
|
|
||||||
|
setbuf(stdout, NULL);
|
||||||
|
|
||||||
|
srunner_run_all(test_runner, CK_NORMAL);
|
||||||
|
int number_failed = srunner_ntests_failed(test_runner);
|
||||||
|
|
||||||
|
srunner_free(test_runner);
|
||||||
|
|
||||||
|
return number_failed;
|
||||||
|
|
||||||
|
// test_AV_three_calls();
|
||||||
|
//
|
||||||
|
// return 0;
|
||||||
|
}
|
141
configure.ac
141
configure.ac
|
@ -31,9 +31,11 @@ BUILD_DHT_BOOTSTRAP_DAEMON="no"
|
||||||
BUILD_NTOX="no"
|
BUILD_NTOX="no"
|
||||||
BUILD_TESTS="yes"
|
BUILD_TESTS="yes"
|
||||||
BUILD_AV="yes"
|
BUILD_AV="yes"
|
||||||
BUILD_PHONE="no"
|
|
||||||
BUILD_TESTING="yes"
|
BUILD_TESTING="yes"
|
||||||
|
|
||||||
|
LOGGING="no"
|
||||||
|
LOGGING_OUTNAM="libtoxcore.log"
|
||||||
|
|
||||||
NCURSES_FOUND="no"
|
NCURSES_FOUND="no"
|
||||||
LIBCONFIG_FOUND="no"
|
LIBCONFIG_FOUND="no"
|
||||||
LIBCHECK_FOUND="no"
|
LIBCHECK_FOUND="no"
|
||||||
|
@ -80,26 +82,63 @@ AC_ARG_ENABLE([randombytes-stir],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([logging],
|
||||||
PKG_PROG_PKG_CONFIG
|
[AC_HELP_STRING([--enable-logging], [enable logging (default: auto)]) ],
|
||||||
|
|
||||||
AC_ARG_ENABLE([phone],
|
|
||||||
[AC_HELP_STRING([--enable-phone], [build test phone (default: auto)]) ],
|
|
||||||
[
|
[
|
||||||
if test "x$enableval" = "xno"; then
|
if test "x$enableval" = "xyes"; then
|
||||||
BUILD_PHONE="no"
|
LOGGING="yes"
|
||||||
elif test "x$enableval" = "xyes"; then
|
|
||||||
BUILD_PHONE="yes"
|
AC_DEFINE([LOGGING], [], [If logging enabled])
|
||||||
|
AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value])
|
||||||
|
AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$LOGGING_OUTNAM"], [Output of logger])
|
||||||
fi
|
fi
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_ARG_WITH(logger-level,
|
||||||
|
AC_HELP_STRING([--with-logger-level=LEVEL],
|
||||||
|
[Logger levels: INFO; DEBUG; WARNING; ERROR ]),
|
||||||
|
[
|
||||||
|
if test "x$LOGGING" = "xno"; then
|
||||||
|
AC_MSG_WARN([Logging disabled!])
|
||||||
|
else
|
||||||
|
if test "x$withval" = "xINFO"; then
|
||||||
|
AC_DEFINE([LOGGER_LEVEL], [INFO], [LoggerLevel value])
|
||||||
|
|
||||||
|
elif test "x$withval" = "xDEBUG"; then
|
||||||
|
AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value])
|
||||||
|
|
||||||
|
elif test "x$withval" = "xWARNING"; then
|
||||||
|
AC_DEFINE([LOGGER_LEVEL], [WARNING], [LoggerLevel value])
|
||||||
|
|
||||||
|
elif test "x$withval" = "xERROR"; then
|
||||||
|
AC_DEFINE([LOGGER_LEVEL], [ERROR], [LoggerLevel value])
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG'])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_ARG_WITH(logger-path,
|
||||||
|
AC_HELP_STRING([--with-logger-path=DIR],
|
||||||
|
[Path of logger output]),
|
||||||
|
[
|
||||||
|
if test "x$LOGGING" = "xno"; then
|
||||||
|
AC_MSG_WARN([Logging disabled!])
|
||||||
|
else
|
||||||
|
AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$withval""/""$LOGGING_OUTNAM"], [Output of logger])
|
||||||
|
fi
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
AC_ARG_ENABLE([av],
|
AC_ARG_ENABLE([av],
|
||||||
[AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ],
|
[AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ],
|
||||||
[
|
[
|
||||||
if test "x$enableval" = "xno"; then
|
if test "x$enableval" = "xno"; then
|
||||||
BUILD_AV="no"
|
BUILD_AV="no"
|
||||||
BUILD_PHONE="no"
|
|
||||||
elif test "x$enableval" = "xyes"; then
|
elif test "x$enableval" = "xyes"; then
|
||||||
BUILD_AV="yes"
|
BUILD_AV="yes"
|
||||||
fi
|
fi
|
||||||
|
@ -421,94 +460,16 @@ if test "x$BUILD_AV" = "xyes"; then
|
||||||
[
|
[
|
||||||
AC_MSG_WARN([disabling AV support: required pthread library not found])
|
AC_MSG_WARN([disabling AV support: required pthread library not found])
|
||||||
BUILD_AV="no"
|
BUILD_AV="no"
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([AVFORMAT], [libavformat],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $AVFORMAT_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([AVCODEC], [libavcodec],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $AVCODEC_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([AVUTIL], [libavutil],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $AVUTIL_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([AVDEVICE], [libavdevice],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $AVDEVICE_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([SWSCALE], [libswscale],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $SWSCALE_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([SDL], [sdl],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $SDL_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_PHONE" = "xyes"; then
|
|
||||||
PKG_CHECK_MODULES([OPENAL], [openal],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
AC_MSG_WARN([disabling phone $OPENAL_PKG_ERRORS])
|
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
#If all dependencies are here add support video define for phone.c
|
|
||||||
if test "x$BUILD_PHONE" == "xyes"; then
|
|
||||||
#Set FFMpeg define
|
|
||||||
AC_DEFINE([TOX_FFMPEG], [1], [Support video])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$BUILD_AV" = "xyes"; then
|
if test "x$BUILD_AV" = "xyes"; then
|
||||||
PKG_CHECK_MODULES([OPUS], [opus],
|
PKG_CHECK_MODULES([OPUS], [opus],
|
||||||
[],
|
[],
|
||||||
[
|
[
|
||||||
AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS])
|
AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS])
|
||||||
BUILD_AV="no"
|
BUILD_AV="no"
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
@ -519,7 +480,6 @@ if test "x$BUILD_AV" = "xyes"; then
|
||||||
[
|
[
|
||||||
AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS])
|
AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS])
|
||||||
BUILD_AV="no"
|
BUILD_AV="no"
|
||||||
BUILD_PHONE="no"
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
@ -693,7 +653,6 @@ AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" =
|
||||||
AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes")
|
AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes")
|
||||||
AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes")
|
AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes")
|
||||||
AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")
|
AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")
|
||||||
AM_CONDITIONAL(BUILD_PHONE, test "x$BUILD_PHONE" = "xyes")
|
|
||||||
AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes")
|
AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes")
|
||||||
AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes")
|
AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes")
|
||||||
|
|
||||||
|
|
|
@ -34,45 +34,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
|
||||||
$(PTHREAD_LIBS) \
|
$(PTHREAD_LIBS) \
|
||||||
$(AV_LIBS)
|
$(AV_LIBS)
|
||||||
|
|
||||||
|
endif
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if BUILD_PHONE
|
|
||||||
|
|
||||||
|
|
||||||
noinst_PROGRAMS += phone
|
|
||||||
|
|
||||||
phone_SOURCES = ../toxav/phone.c
|
|
||||||
|
|
||||||
phone_CFLAGS = -I../toxcore \
|
|
||||||
-I../toxav \
|
|
||||||
$(AVFORMAT_CFLAGS) \
|
|
||||||
$(AVCODEC_CFLAGS) \
|
|
||||||
$(AVUTIL_CFLAGS) \
|
|
||||||
$(AVDEVICE_CFLAGS) \
|
|
||||||
$(SWSCALE_CFLAGS) \
|
|
||||||
$(SDL_CFLAGS) \
|
|
||||||
$(OPENAL_CFLAGS)
|
|
||||||
|
|
||||||
phone_LDADD = libtoxav.la \
|
|
||||||
libtoxcore.la \
|
|
||||||
$(AVFORMAT_LIBS) \
|
|
||||||
$(AVCODEC_LIBS) \
|
|
||||||
$(AVUTIL_LIBS) \
|
|
||||||
$(AVDEVICE_LIBS) \
|
|
||||||
$(SWSCALE_LIBS) \
|
|
||||||
$(SDL_LIBS) \
|
|
||||||
$(OPENAL_LIBS) \
|
|
||||||
$(OPUS_LIBS) \
|
|
||||||
$(VPX_LIBS)\
|
|
||||||
$(PTHREAD_LIBS)\
|
|
||||||
$(NACL_OBJECTS) \
|
|
||||||
$(NACL_LIBS)
|
|
||||||
|
|
||||||
|
|
||||||
endif
|
|
146
toxav/media.c
146
toxav/media.c
|
@ -26,6 +26,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include "../toxcore/logger.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -34,40 +36,31 @@
|
||||||
#include "rtp.h"
|
#include "rtp.h"
|
||||||
#include "media.h"
|
#include "media.h"
|
||||||
|
|
||||||
struct jitter_buffer {
|
int empty_queue(JitterBuffer *q)
|
||||||
RTPMessage **queue;
|
|
||||||
uint16_t capacity;
|
|
||||||
uint16_t size;
|
|
||||||
uint16_t front;
|
|
||||||
uint16_t rear;
|
|
||||||
uint8_t queue_ready;
|
|
||||||
uint16_t current_id;
|
|
||||||
uint32_t current_ts;
|
|
||||||
uint8_t id_set;
|
|
||||||
};
|
|
||||||
|
|
||||||
int empty_queue(struct jitter_buffer *q)
|
|
||||||
{
|
{
|
||||||
while (q->size > 0) {
|
while (q->size > 0) {
|
||||||
rtp_free_msg(NULL, q->queue[q->front]);
|
rtp_free_msg(NULL, q->queue[q->front]);
|
||||||
q->front++;
|
q->front++;
|
||||||
|
|
||||||
if (q->front == q->capacity)
|
if (q->front == q->capacity)
|
||||||
q->front = 0;
|
q->front = 0;
|
||||||
|
|
||||||
q->size--;
|
q->size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
q->id_set = 0;
|
q->id_set = 0;
|
||||||
q->queue_ready = 0;
|
q->queue_ready = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct jitter_buffer *create_queue(int capacity)
|
JitterBuffer *create_queue(int capacity)
|
||||||
{
|
{
|
||||||
struct jitter_buffer *q;
|
JitterBuffer *q;
|
||||||
q = calloc(sizeof(struct jitter_buffer), 1);
|
|
||||||
q->queue = calloc(sizeof(RTPMessage *), capacity);
|
if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL;
|
||||||
|
|
||||||
|
if (!(q->queue = calloc(sizeof(RTPMessage *), capacity))) return NULL;
|
||||||
|
|
||||||
q->size = 0;
|
q->size = 0;
|
||||||
q->capacity = capacity;
|
q->capacity = capacity;
|
||||||
q->front = 0;
|
q->front = 0;
|
||||||
|
@ -79,17 +72,17 @@ struct jitter_buffer *create_queue(int capacity)
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns 1 if 'a' has a higher sequence number than 'b' */
|
void terminate_queue(JitterBuffer *q)
|
||||||
uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
|
|
||||||
{
|
{
|
||||||
/* TODO: There is already this kind of function in toxrtp.c.
|
empty_queue(q);
|
||||||
* Maybe merge?
|
free(q->queue);
|
||||||
*/
|
free(q);
|
||||||
return (sn_a > sn_b || ts_a > ts_b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define sequnum_older(sn_a, sn_b, ts_a, ts_b) (sn_a > sn_b || ts_a > ts_b)
|
||||||
|
|
||||||
/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
|
/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
|
||||||
RTPMessage *dequeue(struct jitter_buffer *q, int *success)
|
RTPMessage *dequeue(JitterBuffer *q, int *success)
|
||||||
{
|
{
|
||||||
if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */
|
if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */
|
||||||
q->queue_ready = 0;
|
q->queue_ready = 0;
|
||||||
|
@ -112,14 +105,13 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
|
||||||
q->current_id = next_id;
|
q->current_id = next_id;
|
||||||
q->current_ts = next_ts;
|
q->current_ts = next_ts;
|
||||||
} else {
|
} else {
|
||||||
if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) {
|
if (sequnum_older(next_id, q->current_id, next_ts, q->current_ts)) {
|
||||||
/*printf("nextid: %d current: %d\n", next_id, q->current_id);*/
|
LOGGER_DEBUG("nextid: %d current: %d\n", next_id, q->current_id);
|
||||||
q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
|
q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
|
||||||
*success = 2; /* tell the decoder the packet is lost */
|
*success = 2; /* tell the decoder the packet is lost */
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
/* packet too old */
|
LOGGER_DEBUG("Packet too old");
|
||||||
/*printf("packet too old\n");*/
|
|
||||||
*success = 0;
|
*success = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -139,12 +131,11 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int queue(struct jitter_buffer *q, RTPMessage *pk)
|
void queue(JitterBuffer *q, RTPMessage *pk)
|
||||||
{
|
{
|
||||||
if (q->size == q->capacity) { /* Full, empty queue */
|
if (q->size == q->capacity) { /* Full, empty queue */
|
||||||
|
LOGGER_DEBUG("Queue full s(%d) c(%d), emptying...", q->size, q->capacity);
|
||||||
empty_queue(q);
|
empty_queue(q);
|
||||||
/*rtp_free_msg(NULL, pk);*/
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q->size > 8)
|
if (q->size > 8)
|
||||||
|
@ -169,13 +160,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
b += q->capacity;
|
b += q->capacity;
|
||||||
|
|
||||||
if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum,
|
if (sequnum_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum,
|
||||||
q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) {
|
q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) {
|
||||||
RTPMessage *temp;
|
RTPMessage *temp;
|
||||||
temp = q->queue[a];
|
temp = q->queue[a];
|
||||||
q->queue[a] = q->queue[b];
|
q->queue[a] = q->queue[b];
|
||||||
q->queue[b] = temp;
|
q->queue[b] = temp;
|
||||||
/*printf("had to swap\n");*/
|
LOGGER_DEBUG("Had to swap");
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -185,19 +176,15 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
|
||||||
if (a < 0)
|
if (a < 0)
|
||||||
a += q->capacity;
|
a += q->capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pk)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int init_video_decoder(CodecState *cs)
|
int init_video_decoder(CodecState *cs)
|
||||||
{
|
{
|
||||||
if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0,
|
int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION);
|
||||||
VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) {
|
|
||||||
/*fprintf(stderr, "Init video_decoder failed!\n");*/
|
if ( rc != VPX_CODEC_OK) {
|
||||||
|
LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +197,7 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
|
||||||
cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
|
cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
|
||||||
|
|
||||||
if ( rc != OPUS_OK ) {
|
if ( rc != OPUS_OK ) {
|
||||||
/*fprintf(stderr, "Error while starting audio decoder!\n");*/
|
LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,10 +208,10 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
|
||||||
int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate)
|
int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate)
|
||||||
{
|
{
|
||||||
vpx_codec_enc_cfg_t cfg;
|
vpx_codec_enc_cfg_t cfg;
|
||||||
int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
|
int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
|
||||||
|
|
||||||
if (res) {
|
if (rc) {
|
||||||
/*fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res));*/
|
LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,9 +219,10 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
|
||||||
cfg.g_w = width;
|
cfg.g_w = width;
|
||||||
cfg.g_h = height;
|
cfg.g_h = height;
|
||||||
|
|
||||||
if (vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0,
|
rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
|
||||||
VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) {
|
|
||||||
/*fprintf(stderr, "Failed to initialize encoder\n");*/
|
if ( rc != VPX_CODEC_OK) {
|
||||||
|
LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,13 +231,30 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
|
||||||
|
|
||||||
int init_audio_encoder(CodecState *cs, uint32_t audio_channels)
|
int init_audio_encoder(CodecState *cs, uint32_t audio_channels)
|
||||||
{
|
{
|
||||||
int err = OPUS_OK;
|
int rc = OPUS_OK;
|
||||||
cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err);
|
cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc);
|
||||||
err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
|
|
||||||
err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
|
if ( rc != OPUS_OK ) {
|
||||||
|
LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
|
||||||
|
|
||||||
|
if ( rc != OPUS_OK ) {
|
||||||
|
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
|
||||||
|
|
||||||
|
if ( rc != OPUS_OK ) {
|
||||||
|
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return err == OPUS_OK ? 0 : -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,7 +267,8 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
|
||||||
uint32_t video_bitrate )
|
uint32_t video_bitrate )
|
||||||
{
|
{
|
||||||
CodecState *retu = calloc(sizeof(CodecState), 1);
|
CodecState *retu = calloc(sizeof(CodecState), 1);
|
||||||
assert(retu);
|
|
||||||
|
if (!retu) return NULL;
|
||||||
|
|
||||||
retu->audio_bitrate = audio_bitrate;
|
retu->audio_bitrate = audio_bitrate;
|
||||||
retu->audio_sample_rate = audio_sample_rate;
|
retu->audio_sample_rate = audio_sample_rate;
|
||||||
|
@ -271,8 +277,7 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
|
||||||
if (!video_width || !video_height) { /* Disable video */
|
if (!video_width || !video_height) { /* Disable video */
|
||||||
/*video_width = 320;
|
/*video_width = 320;
|
||||||
video_height = 240; */
|
video_height = 240; */
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0;
|
retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0;
|
||||||
retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
|
retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
|
||||||
}
|
}
|
||||||
|
@ -280,24 +285,29 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
|
||||||
retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0;
|
retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0;
|
||||||
retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0;
|
retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0;
|
||||||
|
|
||||||
|
if ( retu->capabilities == 0 ) { /* everything failed */
|
||||||
|
free (retu);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return retu;
|
return retu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void codec_terminate_session ( CodecState *cs )
|
void codec_terminate_session ( CodecState *cs )
|
||||||
{
|
{
|
||||||
if ( cs->audio_encoder )
|
if ( cs->audio_encoder )
|
||||||
opus_encoder_destroy(cs->audio_encoder);
|
opus_encoder_destroy(cs->audio_encoder);
|
||||||
|
|
||||||
if ( cs->audio_decoder )
|
|
||||||
opus_decoder_destroy(cs->audio_decoder);
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Terminate video
|
if ( cs->audio_decoder )
|
||||||
* Do what???
|
opus_decoder_destroy(cs->audio_decoder);
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: Terminate video
|
||||||
|
* Do what?
|
||||||
*/
|
*/
|
||||||
if ( cs->capabilities & v_decoding )
|
if ( cs->capabilities & v_decoding )
|
||||||
vpx_codec_destroy(&cs->v_decoder);
|
vpx_codec_destroy(&cs->v_decoder);
|
||||||
|
|
||||||
if ( cs->capabilities & v_encoding )
|
if ( cs->capabilities & v_encoding )
|
||||||
vpx_codec_destroy(&cs->v_encoder);
|
vpx_codec_destroy(&cs->v_encoder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,7 @@
|
||||||
/* Audio encoding/decoding */
|
/* Audio encoding/decoding */
|
||||||
#include <opus.h>
|
#include <opus.h>
|
||||||
|
|
||||||
typedef enum _Capabilities
|
typedef enum _Capabilities {
|
||||||
{
|
|
||||||
none,
|
none,
|
||||||
a_encoding = 1 << 0,
|
a_encoding = 1 << 0,
|
||||||
a_decoding = 1 << 1,
|
a_decoding = 1 << 1,
|
||||||
|
@ -65,13 +64,26 @@ typedef struct _CodecState {
|
||||||
OpusDecoder *audio_decoder;
|
OpusDecoder *audio_decoder;
|
||||||
|
|
||||||
uint64_t capabilities; /* supports*/
|
uint64_t capabilities; /* supports*/
|
||||||
|
|
||||||
} CodecState;
|
} CodecState;
|
||||||
|
|
||||||
struct jitter_buffer *create_queue(int capacity);
|
|
||||||
|
|
||||||
int queue(struct jitter_buffer *q, RTPMessage *pk);
|
typedef struct _JitterBuffer {
|
||||||
RTPMessage *dequeue(struct jitter_buffer *q, int *success);
|
RTPMessage **queue;
|
||||||
|
uint16_t capacity;
|
||||||
|
uint16_t size;
|
||||||
|
uint16_t front;
|
||||||
|
uint16_t rear;
|
||||||
|
uint8_t queue_ready;
|
||||||
|
uint16_t current_id;
|
||||||
|
uint32_t current_ts;
|
||||||
|
uint8_t id_set;
|
||||||
|
} JitterBuffer;
|
||||||
|
|
||||||
|
JitterBuffer *create_queue(int capacity);
|
||||||
|
void terminate_queue(JitterBuffer *q);
|
||||||
|
void queue(JitterBuffer *q, RTPMessage *pk);
|
||||||
|
RTPMessage *dequeue(JitterBuffer *q, int *success);
|
||||||
|
|
||||||
|
|
||||||
CodecState *codec_init_session ( uint32_t audio_bitrate,
|
CodecState *codec_init_session ( uint32_t audio_bitrate,
|
||||||
|
|
947
toxav/msi.c
Executable file → Normal file
947
toxav/msi.c
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
67
toxav/msi.h
Executable file → Normal file
67
toxav/msi.h
Executable file → Normal file
|
@ -33,7 +33,7 @@
|
||||||
#define CALL_ID_LEN 12
|
#define CALL_ID_LEN 12
|
||||||
|
|
||||||
|
|
||||||
typedef void ( *MSICallback ) ( void *arg );
|
typedef void ( *MSICallback ) ( int32_t, void *arg );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,32 +62,33 @@ typedef enum {
|
||||||
* @brief The call struct.
|
* @brief The call struct.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef struct _MSICall { /* Call info structure */
|
typedef struct _MSICall { /* Call info structure */
|
||||||
MSICallState state;
|
struct _MSISession *session; /* Session pointer */
|
||||||
|
|
||||||
MSICallType type_local; /* Type of payload user is ending */
|
MSICallState state;
|
||||||
MSICallType *type_peer; /* Type of payload others are sending */
|
|
||||||
|
|
||||||
uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
|
MSICallType type_local; /* Type of payload user is ending */
|
||||||
|
MSICallType *type_peer; /* Type of payload others are sending */
|
||||||
|
|
||||||
uint8_t *key_local; /* The key for encryption */
|
uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
|
||||||
uint8_t *key_peer; /* The key for decryption */
|
|
||||||
|
|
||||||
uint8_t *nonce_local; /* Local nonce */
|
uint8_t *key_local; /* The key for encryption */
|
||||||
uint8_t *nonce_peer; /* Peer nonce */
|
uint8_t *key_peer; /* The key for decryption */
|
||||||
|
|
||||||
int ringing_tout_ms; /* Ringing timeout in ms */
|
uint8_t *nonce_local; /* Local nonce */
|
||||||
|
uint8_t *nonce_peer; /* Peer nonce */
|
||||||
|
|
||||||
int request_timer_id; /* Timer id for outgoing request/action */
|
int ringing_tout_ms; /* Ringing timeout in ms */
|
||||||
int ringing_timer_id; /* Timer id for ringing timeout */
|
|
||||||
|
|
||||||
pthread_mutex_t mutex; /* It's to be assumed that call will have
|
int request_timer_id; /* Timer id for outgoing request/action */
|
||||||
* separate thread so add mutex
|
int ringing_timer_id; /* Timer id for ringing timeout */
|
||||||
*/
|
|
||||||
uint32_t *peers;
|
|
||||||
uint16_t peer_count;
|
|
||||||
|
|
||||||
|
|
||||||
|
pthread_mutex_t mutex; /* */
|
||||||
|
uint32_t *peers;
|
||||||
|
uint16_t peer_count;
|
||||||
|
|
||||||
|
int32_t call_idx; /* Index of this call in MSISession */
|
||||||
} MSICall;
|
} MSICall;
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,8 +98,9 @@ typedef struct _MSICall { /* Call info structure */
|
||||||
*/
|
*/
|
||||||
typedef struct _MSISession {
|
typedef struct _MSISession {
|
||||||
|
|
||||||
/* Call handler */
|
/* Call handlers */
|
||||||
struct _MSICall *call;
|
struct _MSICall **calls;
|
||||||
|
int32_t max_calls;
|
||||||
|
|
||||||
int last_error_id; /* Determine the last error */
|
int last_error_id; /* Determine the last error */
|
||||||
const uint8_t *last_error_str;
|
const uint8_t *last_error_str;
|
||||||
|
@ -109,7 +111,7 @@ typedef struct _MSISession {
|
||||||
uint32_t frequ;
|
uint32_t frequ;
|
||||||
uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
|
uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
|
||||||
|
|
||||||
|
pthread_mutex_t mutex;
|
||||||
} MSISession;
|
} MSISession;
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,17 +146,18 @@ typedef enum {
|
||||||
* @param id The id.
|
* @param id The id.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdata);
|
void msi_register_callback(MSICallback callback, MSICallbackID id, void *userdata);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the control session.
|
* @brief Start the control session.
|
||||||
*
|
*
|
||||||
* @param messenger Tox* object.
|
* @param messenger Tox* object.
|
||||||
|
* @param max_calls Amount of calls possible
|
||||||
* @return MSISession* The created session.
|
* @return MSISession* The created session.
|
||||||
* @retval NULL Error occurred.
|
* @retval NULL Error occurred.
|
||||||
*/
|
*/
|
||||||
MSISession *msi_init_session ( Messenger *messenger );
|
MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,62 +173,68 @@ int msi_terminate_session ( MSISession *session );
|
||||||
* @brief Send invite request to friend_id.
|
* @brief Send invite request to friend_id.
|
||||||
*
|
*
|
||||||
* @param session Control session.
|
* @param session Control session.
|
||||||
|
* @param call_index Set to new call index.
|
||||||
* @param call_type Type of the call. Audio or Video(both audio and video)
|
* @param call_type Type of the call. Audio or Video(both audio and video)
|
||||||
* @param rngsec Ringing timeout.
|
* @param rngsec Ringing timeout.
|
||||||
* @param friend_id The friend.
|
* @param friend_id The friend.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id );
|
int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Hangup active call.
|
* @brief Hangup active call.
|
||||||
*
|
*
|
||||||
* @param session Control session.
|
* @param session Control session.
|
||||||
|
* @param call_index To which call is this action handled.
|
||||||
* @return int
|
* @return int
|
||||||
* @retval -1 Error occurred.
|
* @retval -1 Error occurred.
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
*/
|
*/
|
||||||
int msi_hangup ( MSISession *session );
|
int msi_hangup ( MSISession *session, int32_t call_index );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Answer active call request.
|
* @brief Answer active call request.
|
||||||
*
|
*
|
||||||
* @param session Control session.
|
* @param session Control session.
|
||||||
|
* @param call_index To which call is this action handled.
|
||||||
* @param call_type Answer with Audio or Video(both).
|
* @param call_type Answer with Audio or Video(both).
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int msi_answer ( MSISession *session, MSICallType call_type );
|
int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cancel request.
|
* @brief Cancel request.
|
||||||
*
|
*
|
||||||
* @param session Control session.
|
* @param session Control session.
|
||||||
|
* @param call_index To which call is this action handled.
|
||||||
* @param peer To which peer.
|
* @param peer To which peer.
|
||||||
* @param reason Set optional reason header. Pass NULL if none.
|
* @param reason Set optional reason header. Pass NULL if none.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int msi_cancel ( MSISession* session, uint32_t peer, const char* reason );
|
int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reject request.
|
* @brief Reject request.
|
||||||
*
|
*
|
||||||
* @param session Control session.
|
* @param session Control session.
|
||||||
|
* @param call_index To which call is this action handled.
|
||||||
* @param reason Set optional reason header. Pass NULL if none.
|
* @param reason Set optional reason header. Pass NULL if none.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int msi_reject ( MSISession *session, const uint8_t *reason );
|
int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Terminate the current call.
|
* @brief Terminate the current call.
|
||||||
*
|
*
|
||||||
* @param session Control session.
|
* @param session Control session.
|
||||||
|
* @param call_index To which call is this action handled.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int msi_stopcall ( MSISession *session );
|
int msi_stopcall ( MSISession *session, int32_t call_index );
|
||||||
|
|
||||||
#endif /* __TOXMSI */
|
#endif /* __TOXMSI */
|
||||||
|
|
1460
toxav/phone.c
1460
toxav/phone.c
File diff suppressed because it is too large
Load Diff
161
toxav/rtp.c
Executable file → Normal file
161
toxav/rtp.c
Executable file → Normal file
|
@ -25,6 +25,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include "../toxcore/logger.h"
|
||||||
|
|
||||||
#include "rtp.h"
|
#include "rtp.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -227,6 +229,7 @@ static const uint32_t payload_table[] = {
|
||||||
RTPHeader *extract_header ( const uint8_t *payload, int length )
|
RTPHeader *extract_header ( const uint8_t *payload, int length )
|
||||||
{
|
{
|
||||||
if ( !payload || !length ) {
|
if ( !payload || !length ) {
|
||||||
|
LOGGER_WARNING("No payload to extract!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +248,7 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
|
||||||
|
|
||||||
if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) {
|
if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) {
|
||||||
/* Deallocate */
|
/* Deallocate */
|
||||||
|
LOGGER_WARNING("Invalid version!");
|
||||||
free(_retu);
|
free(_retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -258,12 +262,13 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
|
||||||
|
|
||||||
if ( length < _length ) {
|
if ( length < _length ) {
|
||||||
/* Deallocate */
|
/* Deallocate */
|
||||||
|
LOGGER_WARNING("Length invalid!");
|
||||||
free(_retu);
|
free(_retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(_retu->csrc, 0, 16 * sizeof (uint32_t));
|
memset(_retu->csrc, 0, 16 * sizeof (uint32_t));
|
||||||
|
|
||||||
_retu->marker_payloadt = *_it;
|
_retu->marker_payloadt = *_it;
|
||||||
++_it;
|
++_it;
|
||||||
_retu->length = _length;
|
_retu->length = _length;
|
||||||
|
@ -304,6 +309,7 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
|
||||||
|
|
||||||
|
|
||||||
if ( length < ( _ext_length * sizeof(uint32_t) ) ) {
|
if ( length < ( _ext_length * sizeof(uint32_t) ) ) {
|
||||||
|
LOGGER_WARNING("Length invalid!");
|
||||||
free(_retu);
|
free(_retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -415,9 +421,9 @@ RTPHeader *build_header ( RTPSession *session )
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for ( i = 0; i < session->cc; i++ )
|
for ( i = 0; i < session->cc; i++ )
|
||||||
_retu->csrc[i] = session->csrc[i];
|
_retu->csrc[i] = session->csrc[i];
|
||||||
|
|
||||||
_retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
|
_retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
|
||||||
|
|
||||||
return _retu;
|
return _retu;
|
||||||
|
@ -443,6 +449,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
|
||||||
_retu->header = extract_header ( data, length ); /* It allocates memory and all */
|
_retu->header = extract_header ( data, length ); /* It allocates memory and all */
|
||||||
|
|
||||||
if ( !_retu->header ) {
|
if ( !_retu->header ) {
|
||||||
|
LOGGER_WARNING("Header failed to extract!");
|
||||||
free(_retu);
|
free(_retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -461,6 +468,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
|
||||||
_retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
_retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
||||||
_from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
_from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
||||||
} else { /* Error */
|
} else { /* Error */
|
||||||
|
LOGGER_WARNING("Ext Header failed to extract!");
|
||||||
rtp_free_msg(NULL, _retu);
|
rtp_free_msg(NULL, _retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -471,6 +479,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
|
||||||
if ( length - _from_pos <= MAX_RTP_SIZE )
|
if ( length - _from_pos <= MAX_RTP_SIZE )
|
||||||
memcpy ( _retu->data, data + _from_pos, length - _from_pos );
|
memcpy ( _retu->data, data + _from_pos, length - _from_pos );
|
||||||
else {
|
else {
|
||||||
|
LOGGER_WARNING("Invalid length!");
|
||||||
rtp_free_msg(NULL, _retu);
|
rtp_free_msg(NULL, _retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -496,8 +505,15 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
|
||||||
RTPSession *_session = object;
|
RTPSession *_session = object;
|
||||||
RTPMessage *_msg;
|
RTPMessage *_msg;
|
||||||
|
|
||||||
if ( !_session || length < 13 + crypto_box_MACBYTES) /* 12 is the minimum length for rtp + desc. byte */
|
if ( !_session || length < 13 + crypto_box_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */
|
||||||
|
LOGGER_WARNING("No session or invalid length of received buffer!");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _session->queue_limit <= _session->queue_size ) {
|
||||||
|
LOGGER_WARNING("Queue limit reached!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t _plain[MAX_UDP_PACKET_SIZE];
|
uint8_t _plain[MAX_UDP_PACKET_SIZE];
|
||||||
|
|
||||||
|
@ -524,7 +540,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
|
||||||
_decrypted_length = decrypt_data_symmetric(
|
_decrypted_length = decrypt_data_symmetric(
|
||||||
(uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain );
|
(uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain );
|
||||||
|
|
||||||
if ( _decrypted_length == -1 ) return -1; /* This packet is not encrypted properly */
|
if ( _decrypted_length == -1 ) {
|
||||||
|
LOGGER_WARNING("Packet not ecrypted properly!");
|
||||||
|
return -1; /* This packet is not encrypted properly */
|
||||||
|
}
|
||||||
|
|
||||||
/* Otherwise, if decryption is ok with new cycle, set new cycle
|
/* Otherwise, if decryption is ok with new cycle, set new cycle
|
||||||
*/
|
*/
|
||||||
|
@ -533,7 +552,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
|
||||||
_decrypted_length = decrypt_data_symmetric(
|
_decrypted_length = decrypt_data_symmetric(
|
||||||
(uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
|
(uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
|
||||||
|
|
||||||
if ( _decrypted_length == -1 ) return -1; /* This is just an error */
|
if ( _decrypted_length == -1 ) {
|
||||||
|
LOGGER_WARNING("Error decrypting!");
|
||||||
|
return -1; /* This is just an error */
|
||||||
|
}
|
||||||
|
|
||||||
/* A new cycle setting. */
|
/* A new cycle setting. */
|
||||||
memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES);
|
memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES);
|
||||||
|
@ -543,7 +565,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
|
||||||
|
|
||||||
_msg = msg_parse ( _sequnum, _plain, _decrypted_length );
|
_msg = msg_parse ( _sequnum, _plain, _decrypted_length );
|
||||||
|
|
||||||
if ( !_msg ) return -1;
|
if ( !_msg ) {
|
||||||
|
LOGGER_WARNING("Could not parse message!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if message came in late */
|
/* Check if message came in late */
|
||||||
if ( check_late_message(_session, _msg) < 0 ) { /* Not late */
|
if ( check_late_message(_session, _msg) < 0 ) { /* Not late */
|
||||||
|
@ -560,6 +585,8 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
|
||||||
_session->last_msg = _session->oldest_msg = _msg;
|
_session->last_msg = _session->oldest_msg = _msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_session->queue_size++;
|
||||||
|
|
||||||
pthread_mutex_unlock(&_session->mutex);
|
pthread_mutex_unlock(&_session->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -579,8 +606,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
|
||||||
*/
|
*/
|
||||||
RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length )
|
RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length )
|
||||||
{
|
{
|
||||||
if ( !session )
|
if ( !session ) {
|
||||||
|
LOGGER_WARNING("No session!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *_from_pos;
|
uint8_t *_from_pos;
|
||||||
RTPMessage *_retu = calloc(1, sizeof (RTPMessage));
|
RTPMessage *_retu = calloc(1, sizeof (RTPMessage));
|
||||||
|
@ -619,36 +648,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* PUBLIC API FUNCTIONS IMPLEMENTATIONS
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************
|
|
||||||
********************************************************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Release all messages held by session.
|
* @brief Release all messages held by session.
|
||||||
*
|
*
|
||||||
|
@ -660,6 +659,7 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
|
||||||
int rtp_release_session_recv ( RTPSession *session )
|
int rtp_release_session_recv ( RTPSession *session )
|
||||||
{
|
{
|
||||||
if ( !session ) {
|
if ( !session ) {
|
||||||
|
LOGGER_WARNING("No session!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,6 +673,7 @@ int rtp_release_session_recv ( RTPSession *session )
|
||||||
}
|
}
|
||||||
|
|
||||||
session->last_msg = session->oldest_msg = NULL;
|
session->last_msg = session->oldest_msg = NULL;
|
||||||
|
session->queue_size = 0;
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
pthread_mutex_unlock(&session->mutex);
|
||||||
|
|
||||||
|
@ -680,6 +681,31 @@ int rtp_release_session_recv ( RTPSession *session )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Call this to change queue limit
|
||||||
|
*
|
||||||
|
* @param session The session
|
||||||
|
* @param limit new limit
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void rtp_queue_adjust_limit(RTPSession *session, uint64_t limit)
|
||||||
|
{
|
||||||
|
RTPMessage *_tmp, * _it;
|
||||||
|
pthread_mutex_lock(&session->mutex);
|
||||||
|
|
||||||
|
for ( _it = session->oldest_msg; session->queue_size > limit; _it = _tmp ) {
|
||||||
|
_tmp = _it->next;
|
||||||
|
rtp_free_msg( session, _it);
|
||||||
|
session->queue_size --;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->oldest_msg = _it;
|
||||||
|
session->queue_limit = limit;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&session->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets oldest message in the list.
|
* @brief Gets oldest message in the list.
|
||||||
*
|
*
|
||||||
|
@ -689,21 +715,32 @@ int rtp_release_session_recv ( RTPSession *session )
|
||||||
*/
|
*/
|
||||||
RTPMessage *rtp_recv_msg ( RTPSession *session )
|
RTPMessage *rtp_recv_msg ( RTPSession *session )
|
||||||
{
|
{
|
||||||
if ( !session )
|
if ( !session ) {
|
||||||
|
LOGGER_WARNING("No session!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
RTPMessage *_retu = session->oldest_msg;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&session->mutex);
|
pthread_mutex_lock(&session->mutex);
|
||||||
|
|
||||||
if ( _retu )
|
if ( session->queue_size == 0 ) {
|
||||||
session->oldest_msg = _retu->next;
|
pthread_mutex_unlock(&session->mutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RTPMessage *_retu = session->oldest_msg;
|
||||||
|
|
||||||
|
/*if (_retu)*/
|
||||||
|
session->oldest_msg = _retu->next;
|
||||||
|
|
||||||
if ( !session->oldest_msg )
|
if ( !session->oldest_msg )
|
||||||
session->last_msg = NULL;
|
session->last_msg = NULL;
|
||||||
|
|
||||||
|
session->queue_size --;
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
pthread_mutex_unlock(&session->mutex);
|
||||||
|
|
||||||
|
|
||||||
return _retu;
|
return _retu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,7 +760,10 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
|
||||||
{
|
{
|
||||||
RTPMessage *msg = rtp_new_message (session, data, length);
|
RTPMessage *msg = rtp_new_message (session, data, length);
|
||||||
|
|
||||||
if ( !msg ) return -1;
|
if ( !msg ) {
|
||||||
|
LOGGER_WARNING("No session!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t _send_data [ MAX_UDP_PACKET_SIZE ];
|
uint8_t _send_data [ MAX_UDP_PACKET_SIZE ];
|
||||||
|
|
||||||
|
@ -738,15 +778,13 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
|
||||||
int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/
|
int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/
|
||||||
(uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 );
|
(uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 );
|
||||||
|
|
||||||
int full_length = encrypted_length + 3;
|
|
||||||
|
|
||||||
_send_data[1] = msg->data[0];
|
_send_data[1] = msg->data[0];
|
||||||
_send_data[2] = msg->data[1];
|
_send_data[2] = msg->data[1];
|
||||||
|
|
||||||
|
|
||||||
/*if ( full_length != sendpacket ( messenger->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {*/
|
if ( -1 == send_custom_lossy_packet(messenger, session->dest, _send_data, encrypted_length + 3) ) {
|
||||||
if ( 0 != send_custom_lossy_packet(messenger, session->dest, _send_data, full_length) ) {
|
LOGGER_WARNING("Failed to send full packet! std error: %s", strerror(errno));
|
||||||
/*fprintf(stderr, "Rtp error: %s\n", strerror(errno));*/
|
|
||||||
rtp_free_msg ( session, msg );
|
rtp_free_msg ( session, msg );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -761,6 +799,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
|
||||||
}
|
}
|
||||||
|
|
||||||
rtp_free_msg ( session, msg );
|
rtp_free_msg ( session, msg );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,13 +856,15 @@ RTPSession *rtp_init_session ( int payload_type,
|
||||||
RTPSession *_retu = calloc(1, sizeof(RTPSession));
|
RTPSession *_retu = calloc(1, sizeof(RTPSession));
|
||||||
assert(_retu);
|
assert(_retu);
|
||||||
|
|
||||||
/*networking_registerhandler(messenger->net, payload_type, rtp_handle_packet, _retu);*/
|
if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ||
|
||||||
if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ) {
|
!encrypt_key || !decrypt_key || !encrypt_nonce || !decrypt_nonce) {
|
||||||
/*fprintf(stderr, "Error setting custom register handler for rtp session\n");*/
|
LOGGER_ERROR("Error setting custom register handler for rtp session");
|
||||||
free(_retu);
|
free(_retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num);
|
||||||
|
|
||||||
_retu->version = RTP_VERSION; /* It's always 2 */
|
_retu->version = RTP_VERSION; /* It's always 2 */
|
||||||
_retu->padding = 0; /* If some additional data is needed about the packet */
|
_retu->padding = 0; /* If some additional data is needed about the packet */
|
||||||
_retu->extension = 0; /* If extension to header is needed */
|
_retu->extension = 0; /* If extension to header is needed */
|
||||||
|
@ -838,8 +879,6 @@ RTPSession *rtp_init_session ( int payload_type,
|
||||||
_retu->rsequnum = _retu->sequnum = 1;
|
_retu->rsequnum = _retu->sequnum = 1;
|
||||||
|
|
||||||
_retu->ext_header = NULL; /* When needed allocate */
|
_retu->ext_header = NULL; /* When needed allocate */
|
||||||
_retu->framerate = -1;
|
|
||||||
_retu->resolution = -1;
|
|
||||||
|
|
||||||
_retu->encrypt_key = encrypt_key;
|
_retu->encrypt_key = encrypt_key;
|
||||||
_retu->decrypt_key = decrypt_key;
|
_retu->decrypt_key = decrypt_key;
|
||||||
|
@ -865,6 +904,8 @@ RTPSession *rtp_init_session ( int payload_type,
|
||||||
_retu->prefix = payload_type;
|
_retu->prefix = payload_type;
|
||||||
|
|
||||||
_retu->oldest_msg = _retu->last_msg = NULL;
|
_retu->oldest_msg = _retu->last_msg = NULL;
|
||||||
|
_retu->queue_limit = 100; /* Default */
|
||||||
|
_retu->queue_size = 0;
|
||||||
|
|
||||||
pthread_mutex_init(&_retu->mutex, NULL);
|
pthread_mutex_init(&_retu->mutex, NULL);
|
||||||
/*
|
/*
|
||||||
|
@ -885,15 +926,17 @@ RTPSession *rtp_init_session ( int payload_type,
|
||||||
*/
|
*/
|
||||||
int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
|
int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
|
||||||
{
|
{
|
||||||
if ( !session )
|
if ( !session ) {
|
||||||
|
LOGGER_WARNING("No session!");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
|
custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
|
||||||
|
|
||||||
rtp_release_session_recv(session);
|
rtp_release_session_recv(session);
|
||||||
|
|
||||||
pthread_mutex_lock(&session->mutex);
|
pthread_mutex_lock(&session->mutex);
|
||||||
|
|
||||||
free ( session->ext_header );
|
free ( session->ext_header );
|
||||||
free ( session->csrc );
|
free ( session->csrc );
|
||||||
free ( session->decrypt_nonce );
|
free ( session->decrypt_nonce );
|
||||||
|
@ -901,7 +944,7 @@ int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
|
||||||
free ( session->nonce_cycle );
|
free ( session->nonce_cycle );
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
pthread_mutex_unlock(&session->mutex);
|
||||||
|
|
||||||
pthread_mutex_destroy(&session->mutex);
|
pthread_mutex_destroy(&session->mutex);
|
||||||
|
|
||||||
/* And finally free session */
|
/* And finally free session */
|
||||||
|
|
18
toxav/rtp.h
Executable file → Normal file
18
toxav/rtp.h
Executable file → Normal file
|
@ -107,10 +107,6 @@ typedef struct _RTPSession {
|
||||||
*/
|
*/
|
||||||
RTPExtHeader *ext_header;
|
RTPExtHeader *ext_header;
|
||||||
|
|
||||||
/* External header identifiers */
|
|
||||||
int resolution;
|
|
||||||
int framerate;
|
|
||||||
|
|
||||||
|
|
||||||
/* Since these are only references of the
|
/* Since these are only references of the
|
||||||
* call structure don't allocate or free
|
* call structure don't allocate or free
|
||||||
|
@ -126,6 +122,9 @@ typedef struct _RTPSession {
|
||||||
RTPMessage *oldest_msg;
|
RTPMessage *oldest_msg;
|
||||||
RTPMessage *last_msg; /* tail */
|
RTPMessage *last_msg; /* tail */
|
||||||
|
|
||||||
|
uint64_t queue_limit;/* Default 100; modify per thy liking */
|
||||||
|
uint64_t queue_size; /* currently holding << messages */
|
||||||
|
|
||||||
/* Msg prefix for core to know when recving */
|
/* Msg prefix for core to know when recving */
|
||||||
uint8_t prefix;
|
uint8_t prefix;
|
||||||
|
|
||||||
|
@ -146,6 +145,15 @@ typedef struct _RTPSession {
|
||||||
int rtp_release_session_recv ( RTPSession *session );
|
int rtp_release_session_recv ( RTPSession *session );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Call this to change queue limit
|
||||||
|
*
|
||||||
|
* @param session The session
|
||||||
|
* @param limit new limit
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void rtp_queue_adjust_limit ( RTPSession *session, uint64_t limit );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get's oldest message in the list.
|
* @brief Get's oldest message in the list.
|
||||||
*
|
*
|
||||||
|
@ -194,7 +202,7 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
|
||||||
* @retval NULL Error occurred.
|
* @retval NULL Error occurred.
|
||||||
*/
|
*/
|
||||||
RTPSession *rtp_init_session ( int payload_type,
|
RTPSession *rtp_init_session ( int payload_type,
|
||||||
Messenger *messenger,
|
Messenger *messenger,
|
||||||
int friend_num,
|
int friend_num,
|
||||||
const uint8_t *encrypt_key,
|
const uint8_t *encrypt_key,
|
||||||
const uint8_t *decrypt_key,
|
const uint8_t *decrypt_key,
|
||||||
|
|
449
toxav/toxav.c
Executable file → Normal file
449
toxav/toxav.c
Executable file → Normal file
|
@ -25,15 +25,20 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
|
||||||
|
#define _GNU_SOURCE /* implicit declaration warning */
|
||||||
|
|
||||||
#include "rtp.h"
|
#include "rtp.h"
|
||||||
#include "media.h"
|
#include "media.h"
|
||||||
#include "msi.h"
|
#include "msi.h"
|
||||||
|
#include "toxav.h"
|
||||||
|
|
||||||
|
#include "../toxcore/logger.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "toxav.h"
|
|
||||||
|
|
||||||
/* Assume 60 fps*/
|
/* Assume 60 fps*/
|
||||||
#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000)
|
#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000)
|
||||||
|
@ -43,26 +48,39 @@
|
||||||
|
|
||||||
static const uint8_t audio_index = 0, video_index = 1;
|
static const uint8_t audio_index = 0, video_index = 1;
|
||||||
|
|
||||||
|
typedef struct _CallSpecific {
|
||||||
|
RTPSession *crtps[2]; /** Audio is first and video is second */
|
||||||
|
CodecState *cs;/** Each call have its own encoders and decoders.
|
||||||
|
* You can, but don't have to, reuse encoders for
|
||||||
|
* multiple calls. If you choose to reuse encoders,
|
||||||
|
* make sure to also reuse encoded payload for every call.
|
||||||
|
* Decoders have to be unique for each call. FIXME: Now add refcounted encoders and
|
||||||
|
* reuse them really.
|
||||||
|
*/
|
||||||
|
JitterBuffer *j_buf; /** Jitter buffer for audio */
|
||||||
|
} CallSpecific;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ts_closing,
|
|
||||||
ts_running,
|
|
||||||
ts_closed
|
|
||||||
|
|
||||||
} ThreadState;
|
|
||||||
|
|
||||||
struct _ToxAv {
|
struct _ToxAv {
|
||||||
Messenger *messenger;
|
Messenger *messenger;
|
||||||
|
|
||||||
MSISession *msi_session; /** Main msi session */
|
MSISession *msi_session; /** Main msi session */
|
||||||
|
CallSpecific *calls; /** Per-call params */
|
||||||
RTPSession *rtp_sessions[2]; /* Audio is first and video is second */
|
uint32_t max_calls;
|
||||||
|
|
||||||
struct jitter_buffer *j_buf;
|
|
||||||
CodecState *cs;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ToxAvCodecSettings av_DefaultSettings = {
|
||||||
|
1000000,
|
||||||
|
800,
|
||||||
|
600,
|
||||||
|
|
||||||
|
64000,
|
||||||
|
20,
|
||||||
|
48000,
|
||||||
|
1,
|
||||||
|
20
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start new A/V session. There can only be one session at the time. If you register more
|
* @brief Start new A/V session. There can only be one session at the time. If you register more
|
||||||
* it will result in undefined behaviour.
|
* it will result in undefined behaviour.
|
||||||
|
@ -74,30 +92,22 @@ struct _ToxAv {
|
||||||
* @return ToxAv*
|
* @return ToxAv*
|
||||||
* @retval NULL On error.
|
* @retval NULL On error.
|
||||||
*/
|
*/
|
||||||
ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings)
|
ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
|
||||||
{
|
{
|
||||||
ToxAv *av = calloc ( sizeof(ToxAv), 1);
|
ToxAv *av = calloc ( sizeof(ToxAv), 1);
|
||||||
|
|
||||||
if (av == NULL)
|
if (av == NULL) {
|
||||||
|
LOGGER_WARNING("Allocation failed!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
av->messenger = (Messenger *)messenger;
|
av->messenger = (Messenger *)messenger;
|
||||||
|
|
||||||
av->msi_session = msi_init_session(av->messenger);
|
av->msi_session = msi_init_session(av->messenger, max_calls);
|
||||||
av->msi_session->agent_handler = av;
|
av->msi_session->agent_handler = av;
|
||||||
|
|
||||||
av->rtp_sessions[0] = av->rtp_sessions [1] = NULL;
|
av->calls = calloc(sizeof(CallSpecific), max_calls);
|
||||||
|
av->max_calls = max_calls;
|
||||||
/* NOTE: This should be user defined or? */
|
|
||||||
av->j_buf = create_queue(codec_settings->jbuf_capacity);
|
|
||||||
|
|
||||||
av->cs = codec_init_session(codec_settings->audio_bitrate,
|
|
||||||
codec_settings->audio_frame_duration,
|
|
||||||
codec_settings->audio_sample_rate,
|
|
||||||
codec_settings->audio_channels,
|
|
||||||
codec_settings->video_width,
|
|
||||||
codec_settings->video_height,
|
|
||||||
codec_settings->video_bitrate);
|
|
||||||
|
|
||||||
return av;
|
return av;
|
||||||
}
|
}
|
||||||
|
@ -112,16 +122,24 @@ void toxav_kill ( ToxAv *av )
|
||||||
{
|
{
|
||||||
msi_terminate_session(av->msi_session);
|
msi_terminate_session(av->msi_session);
|
||||||
|
|
||||||
if ( av->rtp_sessions[audio_index] ) {
|
int i = 0;
|
||||||
rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle);
|
|
||||||
|
for (; i < av->max_calls; i ++) {
|
||||||
|
if ( av->calls[i].crtps[audio_index] )
|
||||||
|
rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle);
|
||||||
|
|
||||||
|
|
||||||
|
if ( av->calls[i].crtps[video_index] )
|
||||||
|
rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ( av->calls[i].j_buf ) terminate_queue(av->calls[i].j_buf);
|
||||||
|
|
||||||
|
if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( av->rtp_sessions[video_index] ) {
|
free(av->calls);
|
||||||
rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
codec_terminate_session(av->cs);
|
|
||||||
|
|
||||||
free(av);
|
free(av);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +150,7 @@ void toxav_kill ( ToxAv *av )
|
||||||
* @param id One of the ToxAvCallbackID values
|
* @param id One of the ToxAvCallbackID values
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void* userdata )
|
void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
|
||||||
{
|
{
|
||||||
msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata);
|
msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata);
|
||||||
}
|
}
|
||||||
|
@ -148,13 +166,9 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds )
|
int toxav_call (ToxAv *av, int32_t *call_index, int user, ToxAvCallType call_type, int ringing_seconds )
|
||||||
{
|
{
|
||||||
if ( av->msi_session->call ) {
|
return msi_invite(av->msi_session, call_index, call_type, ringing_seconds * 1000, user);
|
||||||
return ErrorAlreadyInCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,17 +179,17 @@ int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_second
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_hangup ( ToxAv *av )
|
int toxav_hangup ( ToxAv *av, int32_t call_index )
|
||||||
{
|
{
|
||||||
if ( !av->msi_session->call ) {
|
if ( !av->msi_session->calls[call_index] ) {
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( av->msi_session->call->state != call_active ) {
|
if ( av->msi_session->calls[call_index]->state != call_active ) {
|
||||||
return ErrorInvalidState;
|
return ErrorInvalidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msi_hangup(av->msi_session);
|
return msi_hangup(av->msi_session, call_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,17 +201,17 @@ int toxav_hangup ( ToxAv *av )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_answer ( ToxAv *av, ToxAvCallType call_type )
|
int toxav_answer ( ToxAv *av, int32_t call_index, ToxAvCallType call_type )
|
||||||
{
|
{
|
||||||
if ( !av->msi_session->call ) {
|
if ( !av->msi_session->calls[call_index] ) {
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( av->msi_session->call->state != call_starting ) {
|
if ( av->msi_session->calls[call_index]->state != call_starting ) {
|
||||||
return ErrorInvalidState;
|
return ErrorInvalidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msi_answer(av->msi_session, call_type);
|
return msi_answer(av->msi_session, call_index, call_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,17 +223,17 @@ int toxav_answer ( ToxAv *av, ToxAvCallType call_type )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_reject ( ToxAv *av, const char *reason )
|
int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
|
||||||
{
|
{
|
||||||
if ( !av->msi_session->call ) {
|
if ( !av->msi_session->calls[call_index] ) {
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( av->msi_session->call->state != call_starting ) {
|
if ( av->msi_session->calls[call_index]->state != call_starting ) {
|
||||||
return ErrorInvalidState;
|
return ErrorInvalidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msi_reject(av->msi_session, (const uint8_t *) reason);
|
return msi_reject(av->msi_session, call_index, (const uint8_t *) reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,13 +246,13 @@ int toxav_reject ( ToxAv *av, const char *reason )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_cancel ( ToxAv *av, int peer_id, const char *reason )
|
int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
|
||||||
{
|
{
|
||||||
if ( !av->msi_session->call ) {
|
if ( !av->msi_session->calls[call_index] ) {
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msi_cancel(av->msi_session, peer_id, reason);
|
return msi_cancel(av->msi_session, call_index, peer_id, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -249,13 +263,13 @@ int toxav_cancel ( ToxAv *av, int peer_id, const char *reason )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_stop_call ( ToxAv *av )
|
int toxav_stop_call ( ToxAv *av, int32_t call_index )
|
||||||
{
|
{
|
||||||
if ( !av->msi_session->call ) {
|
if ( !av->msi_session->calls[call_index] ) {
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msi_stopcall(av->msi_session);
|
return msi_stopcall(av->msi_session, call_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -266,48 +280,61 @@ int toxav_stop_call ( ToxAv *av )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_prepare_transmission ( ToxAv* av, int support_video )
|
int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
|
||||||
{
|
{
|
||||||
assert(av->msi_session);
|
if ( !av->msi_session || av->msi_session->max_calls <= call_index || !av->msi_session->calls[call_index] ) {
|
||||||
|
/*fprintf(stderr, "Error while starting audio RTP session: invalid call!\n");*/
|
||||||
if ( !av->msi_session || !av->msi_session->call ) {
|
return ErrorInternal;
|
||||||
return ErrorNoCall;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
av->rtp_sessions[audio_index] = rtp_init_session(
|
CallSpecific *call = &av->calls[call_index];
|
||||||
type_audio,
|
|
||||||
av->messenger,
|
call->crtps[audio_index] =
|
||||||
av->msi_session->call->peers[0],
|
rtp_init_session(
|
||||||
av->msi_session->call->key_peer,
|
type_audio,
|
||||||
av->msi_session->call->key_local,
|
av->messenger,
|
||||||
av->msi_session->call->nonce_peer,
|
av->msi_session->calls[call_index]->peers[0],
|
||||||
av->msi_session->call->nonce_local
|
av->msi_session->calls[call_index]->key_peer,
|
||||||
);
|
av->msi_session->calls[call_index]->key_local,
|
||||||
|
av->msi_session->calls[call_index]->nonce_peer,
|
||||||
|
av->msi_session->calls[call_index]->nonce_local);
|
||||||
|
|
||||||
|
|
||||||
if ( !av->rtp_sessions[audio_index] ) {
|
if ( !call->crtps[audio_index] ) {
|
||||||
fprintf(stderr, "Error while starting audio RTP session!\n");
|
/*fprintf(stderr, "Error while starting audio RTP session!\n");*/
|
||||||
return ErrorStartingAudioRtp;
|
return ErrorStartingAudioRtp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( support_video ) {
|
if ( support_video ) {
|
||||||
av->rtp_sessions[video_index] = rtp_init_session (
|
call->crtps[video_index] =
|
||||||
type_video,
|
rtp_init_session (
|
||||||
av->messenger,
|
type_video,
|
||||||
av->msi_session->call->peers[0],
|
av->messenger,
|
||||||
av->msi_session->call->key_peer,
|
av->msi_session->calls[call_index]->peers[0],
|
||||||
av->msi_session->call->key_local,
|
av->msi_session->calls[call_index]->key_peer,
|
||||||
av->msi_session->call->nonce_peer,
|
av->msi_session->calls[call_index]->key_local,
|
||||||
av->msi_session->call->nonce_local
|
av->msi_session->calls[call_index]->nonce_peer,
|
||||||
);
|
av->msi_session->calls[call_index]->nonce_local);
|
||||||
|
|
||||||
|
|
||||||
if ( !av->rtp_sessions[video_index] ) {
|
if ( !call->crtps[video_index] ) {
|
||||||
fprintf(stderr, "Error while starting video RTP session!\n");
|
/*fprintf(stderr, "Error while starting video RTP session!\n");*/
|
||||||
return ErrorStartingVideoRtp;
|
return ErrorStartingVideoRtp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ErrorNone;
|
|
||||||
|
if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) return ErrorInternal;
|
||||||
|
|
||||||
|
call->cs = codec_init_session(codec_settings->audio_bitrate,
|
||||||
|
codec_settings->audio_frame_duration,
|
||||||
|
codec_settings->audio_sample_rate,
|
||||||
|
codec_settings->audio_channels,
|
||||||
|
codec_settings->video_width,
|
||||||
|
codec_settings->video_height,
|
||||||
|
codec_settings->video_bitrate);
|
||||||
|
|
||||||
|
return call->cs ? ErrorNone : ErrorInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -318,22 +345,35 @@ int toxav_prepare_transmission ( ToxAv* av, int support_video )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_kill_transmission ( ToxAv *av )
|
int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
|
||||||
{
|
{
|
||||||
if ( av->rtp_sessions[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) {
|
CallSpecific *call = &av->calls[call_index];
|
||||||
fprintf(stderr, "Error while terminating audio RTP session!\n");
|
|
||||||
|
if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) {
|
||||||
|
/*fprintf(stderr, "Error while terminating audio RTP session!\n");*/
|
||||||
return ErrorTerminatingAudioRtp;
|
return ErrorTerminatingAudioRtp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( av->rtp_sessions[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) {
|
if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) {
|
||||||
fprintf(stderr, "Error while terminating video RTP session!\n");
|
/*fprintf(stderr, "Error while terminating video RTP session!\n");*/
|
||||||
return ErrorTerminatingVideoRtp;
|
return ErrorTerminatingVideoRtp;
|
||||||
}
|
}
|
||||||
|
|
||||||
av->rtp_sessions[audio_index] = NULL;
|
call->crtps[audio_index] = NULL;
|
||||||
av->rtp_sessions[video_index] = NULL;
|
call->crtps[video_index] = NULL;
|
||||||
|
|
||||||
|
if ( call->j_buf ) {
|
||||||
|
terminate_queue(call->j_buf);
|
||||||
|
call->j_buf = NULL;
|
||||||
|
LOGGER_DEBUG("Terminated j queue");
|
||||||
|
} else LOGGER_DEBUG("No j queue");
|
||||||
|
|
||||||
|
if ( call->cs ) {
|
||||||
|
codec_terminate_session(call->cs);
|
||||||
|
call->cs = NULL;
|
||||||
|
LOGGER_DEBUG("Terminated codec session");
|
||||||
|
} else LOGGER_DEBUG("No codec session");
|
||||||
|
|
||||||
return ErrorNone;
|
return ErrorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,10 +389,12 @@ int toxav_kill_transmission ( ToxAv *av )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval -1 Failure.
|
* @retval -1 Failure.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8_t *payload, uint16_t length )
|
inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
|
||||||
|
uint16_t length )
|
||||||
{
|
{
|
||||||
if ( av->rtp_sessions[type - TypeAudio] )
|
if ( av->calls[call_index].crtps[type - TypeAudio] )
|
||||||
return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length );
|
return rtp_send_msg ( av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload,
|
||||||
|
length );
|
||||||
else return -1;
|
else return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,31 +408,33 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8
|
||||||
* @retval ToxAvError On Error.
|
* @retval ToxAvError On Error.
|
||||||
* @retval >=0 Size of received payload.
|
* @retval >=0 Size of received payload.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *dest )
|
inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
|
||||||
{
|
{
|
||||||
if ( !dest ) return ErrorInternal;
|
if ( !dest ) return ErrorInternal;
|
||||||
|
|
||||||
if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession;
|
CallSpecific *call = &av->calls[call_index];
|
||||||
|
|
||||||
|
if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
|
||||||
|
|
||||||
RTPMessage *message;
|
RTPMessage *message;
|
||||||
|
|
||||||
if ( type == TypeAudio ) {
|
if ( type == TypeAudio ) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
message = rtp_recv_msg(av->rtp_sessions[audio_index]);
|
message = rtp_recv_msg(call->crtps[audio_index]);
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
/* push the packet into the queue */
|
/* push the packet into the queue */
|
||||||
queue(av->j_buf, message);
|
queue(call->j_buf, message);
|
||||||
}
|
}
|
||||||
} while (message);
|
} while (message);
|
||||||
|
|
||||||
int success = 0;
|
int success = 0;
|
||||||
message = dequeue(av->j_buf, &success);
|
message = dequeue(call->j_buf, &success);
|
||||||
|
|
||||||
if ( success == 2) return ErrorAudioPacketLost;
|
if ( success == 2) return ErrorAudioPacketLost;
|
||||||
} else {
|
} else {
|
||||||
message = rtp_recv_msg(av->rtp_sessions[video_index]);
|
message = rtp_recv_msg(call->crtps[video_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( message ) {
|
if ( message ) {
|
||||||
|
@ -415,30 +459,31 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On Error.
|
* @retval ToxAvError On Error.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
|
inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output)
|
||||||
{
|
{
|
||||||
if ( !output ) return ErrorInternal;
|
if ( !output ) return ErrorInternal;
|
||||||
|
|
||||||
uint8_t packet [RTP_PAYLOAD_SIZE];
|
uint8_t packet [RTP_PAYLOAD_SIZE];
|
||||||
int recved_size = 0;
|
int recved_size = 0;
|
||||||
int error;
|
int rc;
|
||||||
|
CallSpecific *call = &av->calls[call_index];
|
||||||
do {
|
|
||||||
recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet);
|
do {
|
||||||
|
recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet);
|
||||||
|
|
||||||
|
if (recved_size > 0 && ( rc = vpx_codec_decode(&call->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) {
|
||||||
|
/*fprintf(stderr, "Error decoding video: %s\n", vpx_codec_err_to_string(rc));*/
|
||||||
|
return ErrorInternal;
|
||||||
|
}
|
||||||
|
|
||||||
if (recved_size > 0 && ( error = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK)
|
|
||||||
fprintf(stderr, "Error decoding: %s\n", vpx_codec_err_to_string(error));
|
|
||||||
|
|
||||||
} while (recved_size > 0);
|
} while (recved_size > 0);
|
||||||
|
|
||||||
vpx_codec_iter_t iter = NULL;
|
vpx_codec_iter_t iter = NULL;
|
||||||
vpx_image_t *img;
|
vpx_image_t *img;
|
||||||
img = vpx_codec_get_frame(&av->cs->v_decoder, &iter);
|
img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
|
||||||
|
|
||||||
*output = img;
|
*output = img;
|
||||||
return 0;
|
return 0;
|
||||||
/* Yeah, i set output to be NULL if nothing received
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -450,30 +495,49 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
|
inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
|
||||||
{
|
{
|
||||||
if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) {
|
return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
|
||||||
fprintf(stderr, "Could not encode video frame\n");
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode video frame
|
||||||
|
*
|
||||||
|
* @param av Handler
|
||||||
|
* @param dest Where to
|
||||||
|
* @param dest_max Max size
|
||||||
|
* @param input What to encode
|
||||||
|
* @return int
|
||||||
|
* @retval ToxAvError On error.
|
||||||
|
* @retval >0 On success
|
||||||
|
*/
|
||||||
|
inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
|
||||||
|
{
|
||||||
|
CallSpecific *call = &av->calls[call_index];
|
||||||
|
|
||||||
|
int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
|
||||||
|
|
||||||
|
if ( rc != VPX_CODEC_OK) {
|
||||||
|
fprintf(stderr, "Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
++av->cs->frame_counter;
|
++call->cs->frame_counter;
|
||||||
|
|
||||||
vpx_codec_iter_t iter = NULL;
|
vpx_codec_iter_t iter = NULL;
|
||||||
const vpx_codec_cx_pkt_t *pkt;
|
const vpx_codec_cx_pkt_t *pkt;
|
||||||
int sent = 0;
|
int copied = 0;
|
||||||
|
|
||||||
while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) {
|
while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
|
||||||
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
||||||
if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1)
|
if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge;
|
||||||
++sent;
|
|
||||||
|
mempcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
|
||||||
|
copied += pkt->data.frame.sz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sent > 0)
|
return copied;
|
||||||
return 0;
|
|
||||||
|
|
||||||
return ErrorInternal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -488,25 +552,38 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
|
||||||
* @retval >=0 Size of received data in frames/samples.
|
* @retval >=0 Size of received data in frames/samples.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest )
|
inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
|
||||||
{
|
{
|
||||||
if ( !dest ) return ErrorInternal;
|
if ( !dest ) return ErrorInternal;
|
||||||
|
|
||||||
|
CallSpecific *call = &av->calls[call_index];
|
||||||
|
|
||||||
uint8_t packet [RTP_PAYLOAD_SIZE];
|
uint8_t packet [RTP_PAYLOAD_SIZE];
|
||||||
|
|
||||||
int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet);
|
int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
|
||||||
|
|
||||||
if ( recved_size == ErrorAudioPacketLost ) {
|
if ( recved_size == ErrorAudioPacketLost ) {
|
||||||
return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
|
int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
|
||||||
|
|
||||||
|
if ( dec_size < 0 ) {
|
||||||
|
LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
|
||||||
|
return ErrorInternal;
|
||||||
|
} else return dec_size;
|
||||||
|
|
||||||
} else if ( recved_size ) {
|
} else if ( recved_size ) {
|
||||||
return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
|
int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
|
||||||
|
|
||||||
|
if ( dec_size < 0 ) {
|
||||||
|
LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
|
||||||
|
return ErrorInternal;
|
||||||
|
} else return dec_size;
|
||||||
} else {
|
} else {
|
||||||
return 0; /* Nothing received */
|
return 0; /* Nothing received */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode and send audio frame.
|
* @brief Send audio frame.
|
||||||
*
|
*
|
||||||
* @param av Handler.
|
* @param av Handler.
|
||||||
* @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
|
* @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
|
||||||
|
@ -516,15 +593,34 @@ inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest )
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size)
|
inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
|
||||||
{
|
{
|
||||||
uint8_t temp_data[RTP_PAYLOAD_SIZE];
|
return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
|
||||||
int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data));
|
}
|
||||||
|
|
||||||
if (ret <= 0)
|
/**
|
||||||
|
* @brief Encode audio frame
|
||||||
|
*
|
||||||
|
* @param av Handler
|
||||||
|
* @param dest dest
|
||||||
|
* @param dest_max Max dest size
|
||||||
|
* @param frame The frame
|
||||||
|
* @param frame_size The frame size
|
||||||
|
* @return int
|
||||||
|
* @retval ToxAvError On error.
|
||||||
|
* @retval >0 On success
|
||||||
|
*/
|
||||||
|
inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max,
|
||||||
|
const int16_t *frame, int frame_size)
|
||||||
|
{
|
||||||
|
int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max);
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Failed to encode payload: %s\n", opus_strerror(rc));
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
|
}
|
||||||
|
|
||||||
return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret);
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -536,54 +632,85 @@ inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size)
|
||||||
* @retval ToxAvCallType On success.
|
* @retval ToxAvCallType On success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_get_peer_transmission_type ( ToxAv *av, int peer )
|
int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer )
|
||||||
{
|
{
|
||||||
assert(av->msi_session);
|
assert(av->msi_session);
|
||||||
|
|
||||||
if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer )
|
if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
|
|
||||||
return av->msi_session->call->type_peer[peer];
|
return av->msi_session->calls[call_index]->type_peer[peer];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get id of peer participating in conversation
|
* @brief Get id of peer participating in conversation
|
||||||
*
|
*
|
||||||
* @param av Handler
|
* @param av Handler
|
||||||
* @param peer peer index
|
* @param peer peer index
|
||||||
* @return int
|
* @return int
|
||||||
* @retval ToxAvError No peer id
|
* @retval ToxAvError No peer id
|
||||||
*/
|
*/
|
||||||
int toxav_get_peer_id ( ToxAv* av, int peer )
|
int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
|
||||||
{
|
{
|
||||||
assert(av->msi_session);
|
assert(av->msi_session);
|
||||||
|
|
||||||
if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer )
|
if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
|
|
||||||
return av->msi_session->call->peers[peer];
|
return av->msi_session->calls[call_index]->peers[peer];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Is certain capability supported
|
* @brief Is certain capability supported
|
||||||
*
|
*
|
||||||
* @param av Handler
|
* @param av Handler
|
||||||
* @return int
|
* @return int
|
||||||
* @retval 1 Yes.
|
* @retval 1 Yes.
|
||||||
* @retval 0 No.
|
* @retval 0 No.
|
||||||
*/
|
*/
|
||||||
inline__ int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability )
|
inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
|
||||||
{
|
{
|
||||||
return av->cs->capabilities & (Capabilities) capability;
|
return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0;
|
||||||
|
/* 0 is error here */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get messenger handle
|
* @brief Set queue limit
|
||||||
*
|
*
|
||||||
* @param av Handler.
|
* @param av Handler
|
||||||
* @return Tox*
|
* @param call_index index
|
||||||
|
* @param limit the limit
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
inline__ Tox* toxav_get_tox ( ToxAv* av )
|
inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
|
||||||
{
|
{
|
||||||
return (Tox*)av->messenger;
|
if ( av->calls[call_index].crtps[audio_index] )
|
||||||
|
rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
|
||||||
|
else
|
||||||
|
return ErrorNoRtpSession;
|
||||||
|
|
||||||
|
return ErrorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set queue limit
|
||||||
|
*
|
||||||
|
* @param av Handler
|
||||||
|
* @param call_index index
|
||||||
|
* @param limit the limit
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
|
||||||
|
{
|
||||||
|
if ( av->calls[call_index].crtps[video_index] )
|
||||||
|
rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
|
||||||
|
else
|
||||||
|
return ErrorNoRtpSession;
|
||||||
|
|
||||||
|
return ErrorNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline__ Tox *toxav_get_tox(ToxAv *av)
|
||||||
|
{
|
||||||
|
return (Tox *)av->messenger;
|
||||||
|
}
|
114
toxav/toxav.h
Executable file → Normal file
114
toxav/toxav.h
Executable file → Normal file
|
@ -29,7 +29,7 @@
|
||||||
/* vpx_image_t */
|
/* vpx_image_t */
|
||||||
#include <vpx/vpx_image.h>
|
#include <vpx/vpx_image.h>
|
||||||
|
|
||||||
typedef void ( *ToxAVCallback ) ( void *arg );
|
typedef void ( *ToxAVCallback ) ( int32_t, void *arg );
|
||||||
typedef struct _ToxAv ToxAv;
|
typedef struct _ToxAv ToxAv;
|
||||||
|
|
||||||
#ifndef __TOX_DEFINED__
|
#ifndef __TOX_DEFINED__
|
||||||
|
@ -67,7 +67,7 @@ typedef enum {
|
||||||
* @brief Call type identifier.
|
* @brief Call type identifier.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TypeAudio = 70,
|
TypeAudio = 192,
|
||||||
TypeVideo
|
TypeVideo
|
||||||
} ToxAvCallType;
|
} ToxAvCallType;
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ typedef enum {
|
||||||
ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
|
ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
|
||||||
ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */
|
ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */
|
||||||
ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */
|
ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */
|
||||||
|
ErrorPacketTooLarge = -11, /* Buffer exceeds size while encoding */
|
||||||
|
|
||||||
} ToxAvError;
|
} ToxAvError;
|
||||||
|
|
||||||
|
@ -110,26 +111,16 @@ typedef struct _ToxAvCodecSettings {
|
||||||
uint32_t video_bitrate; /* In bits/s */
|
uint32_t video_bitrate; /* In bits/s */
|
||||||
uint16_t video_width; /* In px */
|
uint16_t video_width; /* In px */
|
||||||
uint16_t video_height; /* In px */
|
uint16_t video_height; /* In px */
|
||||||
|
|
||||||
uint32_t audio_bitrate; /* In bits/s */
|
uint32_t audio_bitrate; /* In bits/s */
|
||||||
uint16_t audio_frame_duration; /* In ms */
|
uint16_t audio_frame_duration; /* In ms */
|
||||||
uint32_t audio_sample_rate; /* In Hz */
|
uint32_t audio_sample_rate; /* In Hz */
|
||||||
uint32_t audio_channels;
|
uint32_t audio_channels;
|
||||||
|
|
||||||
uint32_t jbuf_capacity; /* Size of jitter buffer */
|
uint32_t jbuf_capacity; /* Size of jitter buffer */
|
||||||
} ToxAvCodecSettings;
|
} ToxAvCodecSettings;
|
||||||
|
|
||||||
static const ToxAvCodecSettings av_DefaultSettings = {
|
extern const ToxAvCodecSettings av_DefaultSettings;
|
||||||
1000000,
|
|
||||||
800,
|
|
||||||
600,
|
|
||||||
|
|
||||||
64000,
|
|
||||||
20,
|
|
||||||
48000,
|
|
||||||
1,
|
|
||||||
20
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start new A/V session. There can only be one session at the time. If you register more
|
* @brief Start new A/V session. There can only be one session at the time. If you register more
|
||||||
|
@ -142,7 +133,7 @@ static const ToxAvCodecSettings av_DefaultSettings = {
|
||||||
* @return ToxAv*
|
* @return ToxAv*
|
||||||
* @retval NULL On error.
|
* @retval NULL On error.
|
||||||
*/
|
*/
|
||||||
ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings);
|
ToxAv *toxav_new(Tox *messenger, int32_t max_calls);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Remove A/V session.
|
* @brief Remove A/V session.
|
||||||
|
@ -172,7 +163,7 @@ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds);
|
int toxav_call(ToxAv *av, int32_t *call_index, int user, ToxAvCallType call_type, int ringing_seconds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Hangup active call.
|
* @brief Hangup active call.
|
||||||
|
@ -182,7 +173,7 @@ int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_hangup(ToxAv *av);
|
int toxav_hangup(ToxAv *av, int32_t call_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Answer incomming call.
|
* @brief Answer incomming call.
|
||||||
|
@ -193,7 +184,7 @@ int toxav_hangup(ToxAv *av);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_answer(ToxAv *av, ToxAvCallType call_type );
|
int toxav_answer(ToxAv *av, int32_t call_index, ToxAvCallType call_type );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reject incomming call.
|
* @brief Reject incomming call.
|
||||||
|
@ -204,7 +195,7 @@ int toxav_answer(ToxAv *av, ToxAvCallType call_type );
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_reject(ToxAv *av, const char *reason);
|
int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cancel outgoing request.
|
* @brief Cancel outgoing request.
|
||||||
|
@ -216,7 +207,7 @@ int toxav_reject(ToxAv *av, const char *reason);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_cancel(ToxAv* av, int peer_id, const char* reason);
|
int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
|
* @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
|
||||||
|
@ -226,7 +217,7 @@ int toxav_cancel(ToxAv* av, int peer_id, const char* reason);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_stop_call(ToxAv *av);
|
int toxav_stop_call(ToxAv *av, int32_t call_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Must be call before any RTP transmission occurs.
|
* @brief Must be call before any RTP transmission occurs.
|
||||||
|
@ -237,7 +228,7 @@ int toxav_stop_call(ToxAv *av);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_prepare_transmission(ToxAv *av, int support_video);
|
int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Call this at the end of the transmission.
|
* @brief Call this at the end of the transmission.
|
||||||
|
@ -247,7 +238,7 @@ int toxav_prepare_transmission(ToxAv *av, int support_video);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_kill_transmission(ToxAv *av);
|
int toxav_kill_transmission(ToxAv *av, int32_t call_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Receive decoded video packet.
|
* @brief Receive decoded video packet.
|
||||||
|
@ -258,7 +249,7 @@ int toxav_kill_transmission(ToxAv *av);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On Error.
|
* @retval ToxAvError On Error.
|
||||||
*/
|
*/
|
||||||
int toxav_recv_video ( ToxAv *av, vpx_image_t **output);
|
int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Receive decoded audio frame.
|
* @brief Receive decoded audio frame.
|
||||||
|
@ -272,21 +263,22 @@ int toxav_recv_video ( ToxAv *av, vpx_image_t **output);
|
||||||
* @retval >=0 Size of received data in frames/samples.
|
* @retval >=0 Size of received data in frames/samples.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest );
|
int toxav_recv_audio( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode and send video packet.
|
* @brief Encode and send video packet.
|
||||||
*
|
*
|
||||||
* @param av Handler.
|
* @param av Handler.
|
||||||
* @param input The packet.
|
* @param frame The encoded frame.
|
||||||
|
* @param frame_size The size of the encoded frame.
|
||||||
* @return int
|
* @return int
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_send_video ( ToxAv *av, vpx_image_t *input);
|
int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode and send audio frame.
|
* @brief Send audio frame.
|
||||||
*
|
*
|
||||||
* @param av Handler.
|
* @param av Handler.
|
||||||
* @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
|
* @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
|
||||||
|
@ -296,7 +288,35 @@ int toxav_send_video ( ToxAv *av, vpx_image_t *input);
|
||||||
* @retval 0 Success.
|
* @retval 0 Success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size);
|
int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode video frame
|
||||||
|
*
|
||||||
|
* @param av Handler
|
||||||
|
* @param dest Where to
|
||||||
|
* @param dest_max Max size
|
||||||
|
* @param input What to encode
|
||||||
|
* @return int
|
||||||
|
* @retval ToxAvError On error.
|
||||||
|
* @retval >0 On success
|
||||||
|
*/
|
||||||
|
int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode audio frame
|
||||||
|
*
|
||||||
|
* @param av Handler
|
||||||
|
* @param dest dest
|
||||||
|
* @param dest_max Max dest size
|
||||||
|
* @param frame The frame
|
||||||
|
* @param frame_size The frame size
|
||||||
|
* @return int
|
||||||
|
* @retval ToxAvError On error.
|
||||||
|
* @retval >0 On success
|
||||||
|
*/
|
||||||
|
int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame,
|
||||||
|
int frame_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get peer transmission type. It can either be audio or video.
|
* @brief Get peer transmission type. It can either be audio or video.
|
||||||
|
@ -307,34 +327,48 @@ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size);
|
||||||
* @retval ToxAvCallType On success.
|
* @retval ToxAvCallType On success.
|
||||||
* @retval ToxAvError On error.
|
* @retval ToxAvError On error.
|
||||||
*/
|
*/
|
||||||
int toxav_get_peer_transmission_type ( ToxAv *av, int peer );
|
int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get id of peer participating in conversation
|
* @brief Get id of peer participating in conversation
|
||||||
*
|
*
|
||||||
* @param av Handler
|
* @param av Handler
|
||||||
* @param peer peer index
|
* @param peer peer index
|
||||||
* @return int
|
* @return int
|
||||||
* @retval ToxAvError No peer id
|
* @retval ToxAvError No peer id
|
||||||
*/
|
*/
|
||||||
int toxav_get_peer_id ( ToxAv* av, int peer );
|
int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Is certain capability supported
|
* @brief Is certain capability supported
|
||||||
*
|
*
|
||||||
* @param av Handler
|
* @param av Handler
|
||||||
* @return int
|
* @return int
|
||||||
* @retval 1 Yes.
|
* @retval 1 Yes.
|
||||||
* @retval 0 No.
|
* @retval 0 No.
|
||||||
*/
|
*/
|
||||||
int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability );
|
int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get messenger handle
|
* @brief Set queue limit
|
||||||
*
|
*
|
||||||
* @param av Handler.
|
* @param av Handler
|
||||||
* @return Tox*
|
* @param call_index index
|
||||||
|
* @param limit the limit
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
Tox* toxav_get_tox ( ToxAv* av );
|
int toxav_set_audio_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set queue limit
|
||||||
|
*
|
||||||
|
* @param av Handler
|
||||||
|
* @param call_index index
|
||||||
|
* @param limit the limit
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
int toxav_set_video_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit );
|
||||||
|
|
||||||
|
|
||||||
|
Tox *toxav_get_tox(ToxAv *av);
|
||||||
#endif /* __TOXAV */
|
#endif /* __TOXAV */
|
|
@ -27,6 +27,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include "DHT.h"
|
#include "DHT.h"
|
||||||
|
|
||||||
#ifdef ENABLE_ASSOC_DHT
|
#ifdef ENABLE_ASSOC_DHT
|
||||||
|
@ -347,18 +349,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
|
||||||
/* Refresh the client timestamp. */
|
/* Refresh the client timestamp. */
|
||||||
if (ip_port.ip.family == AF_INET) {
|
if (ip_port.ip.family == AF_INET) {
|
||||||
|
|
||||||
#ifdef LOGGING
|
LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
|
||||||
|
LOGGER_INFO("coipil[%u]: switching ipv4 from %s:%u to %s:%u", i,
|
||||||
if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
|
ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port),
|
||||||
size_t x;
|
|
||||||
x = sprintf(logbuffer, "coipil[%u]: switching ipv4 from %s:%u ", i,
|
|
||||||
ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port));
|
|
||||||
sprintf(logbuffer + x, "to %s:%u\n",
|
|
||||||
ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
|
ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
|
if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -367,18 +363,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
|
||||||
list[i].assoc4.timestamp = temp_time;
|
list[i].assoc4.timestamp = temp_time;
|
||||||
} else if (ip_port.ip.family == AF_INET6) {
|
} else if (ip_port.ip.family == AF_INET6) {
|
||||||
|
|
||||||
#ifdef LOGGING
|
LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
|
||||||
|
LOGGER_INFO("coipil[%u]: switching ipv6 from %s:%u to %s:%u", i,
|
||||||
if (!ipport_equal(&list[i].assoc6.ip_port, &ip_port)) {
|
ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port),
|
||||||
size_t x;
|
|
||||||
x = sprintf(logbuffer, "coipil[%u]: switching ipv6 from %s:%u ", i,
|
|
||||||
ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port));
|
|
||||||
sprintf(logbuffer + x, "to %s:%u\n",
|
|
||||||
ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
|
ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
|
if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -400,10 +390,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
|
||||||
/* Initialize client timestamp. */
|
/* Initialize client timestamp. */
|
||||||
list[i].assoc4.timestamp = temp_time;
|
list[i].assoc4.timestamp = temp_time;
|
||||||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||||
#ifdef LOGGING
|
|
||||||
sprintf(logbuffer, "coipil[%u]: switching client_id (ipv4) \n", i);
|
LOGGER_DEBUG("coipil[%u]: switching client_id (ipv4)", i);
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
/* kill the other address, if it was set */
|
/* kill the other address, if it was set */
|
||||||
memset(&list[i].assoc6, 0, sizeof(list[i].assoc6));
|
memset(&list[i].assoc6, 0, sizeof(list[i].assoc6));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -411,10 +400,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
|
||||||
/* Initialize client timestamp. */
|
/* Initialize client timestamp. */
|
||||||
list[i].assoc6.timestamp = temp_time;
|
list[i].assoc6.timestamp = temp_time;
|
||||||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||||
#ifdef LOGGING
|
|
||||||
sprintf(logbuffer, "coipil[%u]: switching client_id (ipv6) \n", i);
|
LOGGER_DEBUG("coipil[%u]: switching client_id (ipv6)", i);
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
/* kill the other address, if it was set */
|
/* kill the other address, if it was set */
|
||||||
memset(&list[i].assoc4, 0, sizeof(list[i].assoc4));
|
memset(&list[i].assoc4, 0, sizeof(list[i].assoc4));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -602,18 +590,12 @@ int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_fa
|
||||||
uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);
|
uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);
|
||||||
|
|
||||||
if (!num_found) {
|
if (!num_found) {
|
||||||
#ifdef LOGGING
|
LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned zero nodes");
|
||||||
loglog("get_close_nodes(): Assoc_get_close_entries() returned zero nodes.\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
|
return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes",
|
||||||
sprintf(logbuffer, "get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes.\n",
|
request.count_good, num_found - request.count_good);
|
||||||
request.count_good, num_found - request.count_good);
|
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t i, num_returned = 0;
|
uint8_t i, num_returned = 0;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
|
||||||
../toxcore/assoc.c \
|
../toxcore/assoc.c \
|
||||||
../toxcore/onion.h \
|
../toxcore/onion.h \
|
||||||
../toxcore/onion.c \
|
../toxcore/onion.c \
|
||||||
|
../toxcore/logger.h \
|
||||||
|
../toxcore/logger.c \
|
||||||
../toxcore/onion_announce.h \
|
../toxcore/onion_announce.h \
|
||||||
../toxcore/onion_announce.c \
|
../toxcore/onion_announce.c \
|
||||||
../toxcore/onion_client.h \
|
../toxcore/onion_client.h \
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
#include "Messenger.h"
|
#include "Messenger.h"
|
||||||
#include "assoc.h"
|
#include "assoc.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
@ -2054,6 +2055,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
|
||||||
if (m->friend_action)
|
if (m->friend_action)
|
||||||
(*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata);
|
(*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata);
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2339,7 +2341,7 @@ void do_messenger(Messenger *m)
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
|
|
||||||
if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
|
if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
|
||||||
loglog(" = = = = = = = = \n");
|
|
||||||
#ifdef ENABLE_ASSOC_DHT
|
#ifdef ENABLE_ASSOC_DHT
|
||||||
Assoc_status(m->dht->assoc);
|
Assoc_status(m->dht->assoc);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2348,12 +2350,10 @@ void do_messenger(Messenger *m)
|
||||||
size_t c;
|
size_t c;
|
||||||
|
|
||||||
for (c = 0; c < m->numchats; c++) {
|
for (c = 0; c < m->numchats; c++) {
|
||||||
loglog("---------------- \n");
|
|
||||||
Assoc_status(m->chats[c]->assoc);
|
Assoc_status(m->chats[c]->assoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loglog(" = = = = = = = = \n");
|
|
||||||
|
|
||||||
lastdump = unix_time();
|
lastdump = unix_time();
|
||||||
uint32_t client, last_pinged;
|
uint32_t client, last_pinged;
|
||||||
|
@ -2370,14 +2370,12 @@ void do_messenger(Messenger *m)
|
||||||
if (last_pinged > 999)
|
if (last_pinged > 999)
|
||||||
last_pinged = 999;
|
last_pinged = 999;
|
||||||
|
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "C[%2u] %s:%u [%3u] %s\n",
|
LOGGER_INFO("C[%2u] %s:%u [%3u] %s",
|
||||||
client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port),
|
client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port),
|
||||||
last_pinged, ID2String(cptr->client_id));
|
last_pinged, ID2String(cptr->client_id));
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loglog(" = = = = = = = = \n");
|
|
||||||
|
|
||||||
uint32_t friend, dhtfriend;
|
uint32_t friend, dhtfriend;
|
||||||
|
|
||||||
|
@ -2405,9 +2403,7 @@ void do_messenger(Messenger *m)
|
||||||
dht2m[m2dht[friend]] = friend;
|
dht2m[m2dht[friend]] = friend;
|
||||||
|
|
||||||
if (m->numfriends != m->dht->num_friends) {
|
if (m->numfriends != m->dht->num_friends) {
|
||||||
sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n",
|
LOGGER_INFO("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends);
|
||||||
m->dht->num_friends, m->numfriends);
|
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ping_lastrecv;
|
uint32_t ping_lastrecv;
|
||||||
|
@ -2428,14 +2424,11 @@ void do_messenger(Messenger *m)
|
||||||
if (ping_lastrecv > 999)
|
if (ping_lastrecv > 999)
|
||||||
ping_lastrecv = 999;
|
ping_lastrecv = 999;
|
||||||
|
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "F[%2u:%2u] <%s> %02i [%03u] %s\n",
|
LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s",
|
||||||
dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id,
|
dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id,
|
||||||
ping_lastrecv, ID2String(msgfptr->client_id));
|
ping_lastrecv, ID2String(msgfptr->client_id));
|
||||||
loglog(logbuffer);
|
|
||||||
} else {
|
} else {
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "F[--:%2u] %s\n",
|
LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id));
|
||||||
friend, ID2String(dhtfptr->client_id));
|
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
|
for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
|
||||||
|
@ -2450,19 +2443,16 @@ void do_messenger(Messenger *m)
|
||||||
if (last_pinged > 999)
|
if (last_pinged > 999)
|
||||||
last_pinged = 999;
|
last_pinged = 999;
|
||||||
|
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "F[%2u] => C[%2u] %s:%u [%3u] %s\n",
|
LOGGER_INFO("F[%2u] => C[%2u] %s:%u [%3u] %s",
|
||||||
friend, client, ip_ntoa(&assoc->ip_port.ip),
|
friend, client, ip_ntoa(&assoc->ip_port.ip),
|
||||||
ntohs(assoc->ip_port.port), last_pinged,
|
ntohs(assoc->ip_port.port), last_pinged,
|
||||||
ID2String(cptr->client_id));
|
ID2String(cptr->client_id));
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loglog(" = = = = = = = = \n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* LOGGING */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
#include "DHT.h"
|
#include "DHT.h"
|
||||||
#include "assoc.h"
|
#include "assoc.h"
|
||||||
#include "ping.h"
|
#include "ping.h"
|
||||||
|
@ -523,9 +524,7 @@ static void client_id_self_update(Assoc *assoc)
|
||||||
assoc->self_hash = id_hash(assoc, assoc->self_client_id);
|
assoc->self_hash = id_hash(assoc, assoc->self_client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
LOGGER_DEBUG("id is now set, purging cache of self-references");
|
||||||
loglog("assoc: id is now set, purging cache of self-references...\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* if we already added some (or loaded some) entries,
|
/* if we already added some (or loaded some) entries,
|
||||||
* look and remove if we find a match
|
* look and remove if we find a match
|
||||||
|
@ -820,10 +819,8 @@ Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id)
|
||||||
entries_test = prime_upto_min9(entries_test - 1);
|
entries_test = prime_upto_min9(entries_test - 1);
|
||||||
|
|
||||||
if (entries_test != entries) {
|
if (entries_test != entries) {
|
||||||
#ifdef LOGGING
|
|
||||||
sprintf(logbuffer, "new_Assoc(): trimmed %i to %i.\n", (int)entries, (int)entries_test);
|
LOGGER_DEBUG("trimmed %i to %i.\n", (int)entries, (int)entries_test);
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
entries = (size_t)entries_test;
|
entries = (size_t)entries_test;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -872,7 +869,7 @@ void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *id)
|
||||||
|
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
static char *idpart2str(uint8_t *id, size_t len);
|
static char *idpart2str(uint8_t *id, size_t len);
|
||||||
#endif
|
#endif /* LOGGING */
|
||||||
|
|
||||||
/* refresh buckets */
|
/* refresh buckets */
|
||||||
void do_Assoc(Assoc *assoc, DHT *dht)
|
void do_Assoc(Assoc *assoc, DHT *dht)
|
||||||
|
@ -928,53 +925,31 @@ void do_Assoc(Assoc *assoc, DHT *dht)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
|
||||||
size_t total = 0, written = sprintf(logbuffer, "assoc: [%u] => ",
|
|
||||||
(uint32_t)(candidate % assoc->candidates_bucket_count));
|
|
||||||
|
|
||||||
if (written > 0)
|
|
||||||
total += written;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (seen) {
|
if (seen) {
|
||||||
IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6;
|
IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6;
|
||||||
#ifdef LOGGING
|
|
||||||
written = sprintf(logbuffer + total, " S[%s...] %s:%u", idpart2str(seen->client.client_id, 8),
|
|
||||||
ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port));
|
|
||||||
|
|
||||||
if (written > 0)
|
LOGGER_DEBUG("[%u] => S[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count),
|
||||||
total += written;
|
idpart2str(seen->client.client_id, 8), ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port));
|
||||||
|
|
||||||
#endif
|
|
||||||
DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id);
|
DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id);
|
||||||
seen->getnodes = unix_time();
|
seen->getnodes = unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heard && (heard != seen)) {
|
if (heard && (heard != seen)) {
|
||||||
IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6;
|
IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6;
|
||||||
#ifdef LOGGING
|
|
||||||
written = sprintf(logbuffer + total, " H[%s...] %s:%u", idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip),
|
|
||||||
htons(ipp->port));
|
|
||||||
|
|
||||||
if (written > 0)
|
LOGGER_DEBUG("[%u] => H[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count),
|
||||||
total += written;
|
idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip), htons(ipp->port));
|
||||||
|
|
||||||
#endif
|
|
||||||
DHT_getnodes(dht, ipp, heard->client.client_id, target_id);
|
DHT_getnodes(dht, ipp, heard->client.client_id, target_id);
|
||||||
heard->getnodes = unix_time();
|
heard->getnodes = unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
LOGGER_SCOPE (
|
||||||
|
|
||||||
if (!heard && !seen)
|
if ( !heard && !seen )
|
||||||
sprintf(logbuffer + total, "no nodes to talk to??\n");
|
LOGGER_DEBUG("[%u] => no nodes to talk to??", (uint32_t)(candidate % assoc->candidates_bucket_count));
|
||||||
else
|
);
|
||||||
/* for arcane reasons, sprintf(str, "\n") doesn't function */
|
|
||||||
sprintf(logbuffer + total, "%s", "\n");
|
|
||||||
|
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,11 +983,11 @@ static char *idpart2str(uint8_t *id, size_t len)
|
||||||
void Assoc_status(Assoc *assoc)
|
void Assoc_status(Assoc *assoc)
|
||||||
{
|
{
|
||||||
if (!assoc) {
|
if (!assoc) {
|
||||||
loglog("Assoc status: no assoc\n");
|
LOGGER_INFO("Assoc status: no assoc");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loglog("[b:p] hash => [id...] used, seen, heard\n");
|
LOGGER_INFO("[b:p] hash => [id...] used, seen, heard");
|
||||||
|
|
||||||
size_t bid, cid, total = 0;
|
size_t bid, cid, total = 0;
|
||||||
|
|
||||||
|
@ -1023,24 +998,23 @@ void Assoc_status(Assoc *assoc)
|
||||||
Client_entry *entry = &bucket->list[cid];
|
Client_entry *entry = &bucket->list[cid];
|
||||||
|
|
||||||
if (entry->hash) {
|
if (entry->hash) {
|
||||||
sprintf(logbuffer, "[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
|
|
||||||
(int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
|
|
||||||
entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
|
|
||||||
entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
|
|
||||||
entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
|
|
||||||
entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
|
|
||||||
entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
|
|
||||||
loglog(logbuffer);
|
|
||||||
total++;
|
total++;
|
||||||
|
|
||||||
|
LOGGER_INFO("[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
|
||||||
|
(int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
|
||||||
|
entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
|
||||||
|
entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
|
||||||
|
entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
|
||||||
|
entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
|
||||||
|
entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total) {
|
if (total) {
|
||||||
sprintf(logbuffer, "Total: %i entries, table usage %i%%.\n", (int)total,
|
LOGGER_INFO("Total: %i entries, table usage %i%%.\n", (int)total,
|
||||||
(int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size)));
|
(int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size)));
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* LOGGING */
|
||||||
|
|
|
@ -98,6 +98,6 @@ void kill_Assoc(Assoc *assoc);
|
||||||
|
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
void Assoc_status(Assoc *assoc);
|
void Assoc_status(Assoc *assoc);
|
||||||
#endif
|
#endif /* LOGGING */
|
||||||
|
|
||||||
#endif /* !__ASSOC_H__ */
|
#endif /* !__ASSOC_H__ */
|
||||||
|
|
153
toxcore/logger.c
Normal file
153
toxcore/logger.c
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/* logger.c
|
||||||
|
*
|
||||||
|
* Wrapping logger functions in nice macros
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Tox.
|
||||||
|
*
|
||||||
|
* Tox is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tox is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#ifdef LOGGING
|
||||||
|
|
||||||
|
#include "network.h" /* for time */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
||||||
|
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct logger_config {
|
||||||
|
FILE *log_file;
|
||||||
|
LoggerLevel level;
|
||||||
|
uint64_t start_time; /* Time when lib loaded */
|
||||||
|
}
|
||||||
|
logger = {
|
||||||
|
NULL,
|
||||||
|
DEBUG,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
void __attribute__((destructor)) terminate_logger()
|
||||||
|
{
|
||||||
|
if ( !logger.log_file ) return;
|
||||||
|
|
||||||
|
time_t tim = time(NULL);
|
||||||
|
|
||||||
|
logger_write(ERROR, "\n============== Closing logger [%u] ==============\n"
|
||||||
|
"Time: %s", logger_get_pid(), asctime(localtime(&tim)));
|
||||||
|
|
||||||
|
fclose(logger.log_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned logger_get_pid()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
||||||
|
GetCurrentProcessId();
|
||||||
|
#else
|
||||||
|
getpid();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *logger_stringify_level(LoggerLevel level)
|
||||||
|
{
|
||||||
|
static const char *strings [] = {
|
||||||
|
"INFO",
|
||||||
|
"DEBUG",
|
||||||
|
"WARNING",
|
||||||
|
"ERROR"
|
||||||
|
};
|
||||||
|
|
||||||
|
return strings[level];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int logger_init(const char *file_name, LoggerLevel level)
|
||||||
|
{
|
||||||
|
char *final_l = calloc(sizeof(char), strlen(file_name) + 32);
|
||||||
|
sprintf(final_l, "%s"/*.%u"*/, file_name, logger_get_pid());
|
||||||
|
|
||||||
|
if ( logger.log_file ) {
|
||||||
|
fprintf(stderr, "Error opening logger name: %s with level %d: file already opened!\n", final_l, level);
|
||||||
|
free (final_l);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log_file = fopen(final_l, "ab");
|
||||||
|
|
||||||
|
if ( logger.log_file == NULL ) {
|
||||||
|
fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, strerror(errno));
|
||||||
|
|
||||||
|
free (final_l);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
logger.level = level;
|
||||||
|
logger.start_time = current_time_monotonic();
|
||||||
|
|
||||||
|
|
||||||
|
time_t tim = time(NULL);
|
||||||
|
logger_write(ERROR, "\n============== Starting logger [%u] ==============\n"
|
||||||
|
"Time: %s", logger_get_pid(), asctime(localtime(&tim)));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
free (final_l);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void logger_write (LoggerLevel level, const char *format, ...)
|
||||||
|
{
|
||||||
|
if (logger.log_file == NULL) {
|
||||||
|
/*fprintf(stderr, "Logger file is NULL!\n");*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.level > level) return; /* Don't print some levels xuh */
|
||||||
|
|
||||||
|
va_list _arg;
|
||||||
|
va_start (_arg, format);
|
||||||
|
vfprintf (logger.log_file, format, _arg);
|
||||||
|
va_end (_arg);
|
||||||
|
|
||||||
|
fflush(logger.log_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *logger_timestr(char *dest, size_t max_size)
|
||||||
|
{
|
||||||
|
uint64_t diff = (current_time_monotonic() - logger.start_time); /* ms */
|
||||||
|
snprintf(dest, max_size, "%"PRIu64"", diff);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* LOGGING */
|
85
toxcore/logger.h
Normal file
85
toxcore/logger.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/* logger.h
|
||||||
|
*
|
||||||
|
* Wrapping logger functions in nice macros
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Tox.
|
||||||
|
*
|
||||||
|
* Tox is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tox is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __TOXLOGGER
|
||||||
|
#define __TOXLOGGER
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
// #define LOGGING
|
||||||
|
|
||||||
|
#ifdef LOGGING
|
||||||
|
|
||||||
|
typedef enum _LoggerLevel {
|
||||||
|
INFO,
|
||||||
|
DEBUG,
|
||||||
|
WARNING,
|
||||||
|
ERROR
|
||||||
|
} LoggerLevel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set 'level' as the lowest printable level
|
||||||
|
*/
|
||||||
|
int logger_init(const char *file_name, LoggerLevel level);
|
||||||
|
const char *logger_stringify_level(LoggerLevel level);
|
||||||
|
unsigned logger_get_pid();
|
||||||
|
void logger_write (LoggerLevel level, const char *format, ...);
|
||||||
|
char *logger_timestr (char *dest, size_t max_size);
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
||||||
|
#define _SFILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||||
|
#else
|
||||||
|
#define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WRITE_FORMAT(__LEVEL__, format) char __time__[20]; char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "\n[%u] [%s] [%s] [%s:%d %s()] %s", \
|
||||||
|
logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__, 20), _SFILE, __LINE__, __func__, format)
|
||||||
|
|
||||||
|
/* Use these macros */
|
||||||
|
|
||||||
|
#define LOGGER_INIT(name, level) logger_init(name, level);
|
||||||
|
#define LOGGER_INFO(format, ...) do { WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
|
||||||
|
#define LOGGER_DEBUG(format, ...) do { WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
|
||||||
|
#define LOGGER_WARNING(format, ...) do { WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
|
||||||
|
#define LOGGER_ERROR(format, ...) do { WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
|
||||||
|
|
||||||
|
/* To do some checks or similar only when logging use this */
|
||||||
|
#define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
#define LOGGER_INIT(name, level)
|
||||||
|
#define LOGGER_INFO(format, ...)
|
||||||
|
#define LOGGER_DEBUG(format, ...)
|
||||||
|
#define LOGGER_WARNING(format, ...)
|
||||||
|
#define LOGGER_ERROR(format, ...)
|
||||||
|
|
||||||
|
#define LOGGER_SCOPE(__SCOPE_DO__)
|
||||||
|
|
||||||
|
#endif /* LOGGING */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __TOXLOGGER */
|
|
@ -29,6 +29,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
|
#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -252,9 +254,29 @@ uint64_t current_time_monotonic(void)
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
/* In case no logging */
|
||||||
static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res);
|
#ifndef LOGGING
|
||||||
#endif
|
#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__)
|
||||||
|
#else
|
||||||
|
#define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0
|
||||||
|
#define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0
|
||||||
|
|
||||||
|
#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \
|
||||||
|
(__ip_port__) .ip; \
|
||||||
|
if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \
|
||||||
|
LOGGER_INFO("[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", \
|
||||||
|
__buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \
|
||||||
|
ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \
|
||||||
|
else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \
|
||||||
|
LOGGER_INFO("[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", \
|
||||||
|
__buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \
|
||||||
|
ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \
|
||||||
|
else /* empty or overwrite */ \
|
||||||
|
LOGGER_INFO("[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", \
|
||||||
|
__buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \
|
||||||
|
ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__));
|
||||||
|
|
||||||
|
#endif /* LOGGING */
|
||||||
|
|
||||||
/* Basic network functions:
|
/* Basic network functions:
|
||||||
* Function to send packet(data) of length length to ip_port.
|
* Function to send packet(data) of length length to ip_port.
|
||||||
|
@ -313,9 +335,9 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
|
int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
|
||||||
#ifdef LOGGING
|
|
||||||
loglogdata("O=>", data, length, &ip_port, res);
|
loglogdata("O=>", data, length, ip_port, res);
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((res >= 0) && ((uint32_t)res == length))
|
if ((res >= 0) && ((uint32_t)res == length))
|
||||||
net->send_fail_eagain = 0;
|
net->send_fail_eagain = 0;
|
||||||
|
@ -343,14 +365,10 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
|
||||||
int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
|
int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
|
||||||
|
|
||||||
if (fail_or_len < 0) {
|
if (fail_or_len < 0) {
|
||||||
#ifdef LOGGING
|
|
||||||
|
|
||||||
if ((fail_or_len < 0) && (errno != EWOULDBLOCK)) {
|
LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK))
|
||||||
sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno));
|
LOGGER_ERROR("Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); );
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
return -1; /* Nothing received. */
|
return -1; /* Nothing received. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,9 +393,7 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
|
||||||
} else
|
} else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
#ifdef LOGGING
|
loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, *ip_port, *length);
|
||||||
loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -400,10 +416,7 @@ void networking_poll(Networking_Core *net)
|
||||||
if (length < 1) continue;
|
if (length < 1) continue;
|
||||||
|
|
||||||
if (!(net->packethandlers[data[0]].function)) {
|
if (!(net->packethandlers[data[0]].function)) {
|
||||||
#ifdef LOGGING
|
LOGGER_WARNING("[%02u] -- Packet has no handler", data[0]);
|
||||||
sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]);
|
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,22 +519,15 @@ int networking_wait_execute(uint8_t *data, long seconds, long microseconds)
|
||||||
timeout.tv_usec = microseconds;
|
timeout.tv_usec = microseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGGING
|
|
||||||
errno = 0;
|
|
||||||
#endif
|
|
||||||
/* returns -1 on error, 0 on timeout, the socket on activity */
|
/* returns -1 on error, 0 on timeout, the socket on activity */
|
||||||
int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr);
|
int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr);
|
||||||
#ifdef LOGGING
|
|
||||||
|
|
||||||
/* only dump if not timeout */
|
LOGGER_SCOPE(
|
||||||
if (res) {
|
|
||||||
sprintf(logbuffer, "select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno,
|
|
||||||
strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds),
|
|
||||||
FD_ISSET(s->sock, &exceptfds));
|
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
if (res) LOGGER_INFO("select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno,
|
||||||
|
strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds),
|
||||||
|
FD_ISSET(s->sock, &exceptfds));
|
||||||
|
);
|
||||||
|
|
||||||
if (FD_ISSET(s->sock, &writefds)) {
|
if (FD_ISSET(s->sock, &writefds)) {
|
||||||
s->send_fail_reset = 1;
|
s->send_fail_reset = 1;
|
||||||
|
@ -681,18 +687,10 @@ Networking_Core *new_networking(IP ip, uint16_t port)
|
||||||
if (ip.family == AF_INET6) {
|
if (ip.family == AF_INET6) {
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
int is_dualstack =
|
int is_dualstack =
|
||||||
#endif
|
#endif /* LOGGING */
|
||||||
set_socket_dualstack(temp->sock);
|
set_socket_dualstack(temp->sock);
|
||||||
#ifdef LOGGING
|
LOGGER_DEBUG( "Dual-stack socket: %s",
|
||||||
|
is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses" );
|
||||||
if (is_dualstack) {
|
|
||||||
loglog("Dual-stack socket: enabled.\n");
|
|
||||||
} else {
|
|
||||||
loglog("Dual-stack socket: Failed to enable, won't be able to receive from/send to IPv4 addresses.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* multicast local nodes */
|
/* multicast local nodes */
|
||||||
struct ipv6_mreq mreq;
|
struct ipv6_mreq mreq;
|
||||||
memset(&mreq, 0, sizeof(mreq));
|
memset(&mreq, 0, sizeof(mreq));
|
||||||
|
@ -701,20 +699,12 @@ Networking_Core *new_networking(IP ip, uint16_t port)
|
||||||
mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
|
mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
|
||||||
mreq.ipv6mr_interface = 0;
|
mreq.ipv6mr_interface = 0;
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
errno = 0;
|
|
||||||
int res =
|
int res =
|
||||||
#endif
|
#endif /* LOGGING */
|
||||||
setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
|
setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
|
||||||
#ifdef LOGGING
|
|
||||||
|
|
||||||
if (res < 0) {
|
LOGGER_DEBUG(res < 0 ? "Failed to activate local multicast membership. (%u, %s)" :
|
||||||
sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
|
"Local multicast group FF02::1 joined successfully", errno, strerror(errno) );
|
||||||
errno, strerror(errno));
|
|
||||||
loglog(logbuffer);
|
|
||||||
} else
|
|
||||||
loglog("Local multicast group FF02::1 joined successfully.\n");
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a hanging program or a different user might block the standard port;
|
/* a hanging program or a different user might block the standard port;
|
||||||
|
@ -742,12 +732,8 @@ Networking_Core *new_networking(IP ip, uint16_t port)
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
temp->port = *portptr;
|
temp->port = *portptr;
|
||||||
#ifdef LOGGING
|
|
||||||
loginit(temp->port);
|
|
||||||
|
|
||||||
sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
|
LOGGER_DEBUG("Bound successfully to %s:%u", ip_ntoa(&ip), ntohs(temp->port));
|
||||||
loglog(logbuffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* errno isn't reset on success, only set on failure, the failed
|
/* errno isn't reset on success, only set on failure, the failed
|
||||||
* binds with parallel clients yield a -EPERM to the outside if
|
* binds with parallel clients yield a -EPERM to the outside if
|
||||||
|
@ -1114,31 +1100,3 @@ int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef LOGGING
|
|
||||||
static char errmsg_ok[3] = "OK";
|
|
||||||
static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
|
|
||||||
{
|
|
||||||
uint16_t port = ntohs(ip_port->port);
|
|
||||||
uint32_t data[2];
|
|
||||||
data[0] = buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0;
|
|
||||||
data[1] = buflen > 7 ? ntohl(*(uint32_t *)&buffer[5]) : 0;
|
|
||||||
|
|
||||||
/* Windows doesn't necessarily know %zu */
|
|
||||||
if (res < 0) {
|
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x\n",
|
|
||||||
buffer[0], message, (buflen < 999 ? (uint16_t)buflen : 999), 'E',
|
|
||||||
ip_ntoa(&ip_port->ip), port, errno, strerror(errno), data[0], data[1]);
|
|
||||||
} else if ((res > 0) && ((size_t)res <= buflen))
|
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x\n",
|
|
||||||
buffer[0], message, (res < 999 ? (size_t)res : 999), ((size_t)res < buflen ? '<' : '='),
|
|
||||||
ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]);
|
|
||||||
else /* empty or overwrite */
|
|
||||||
snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x\n",
|
|
||||||
buffer[0], message, (size_t)res, (!res ? '!' : '>'), buflen,
|
|
||||||
ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]);
|
|
||||||
|
|
||||||
logbuffer[sizeof(logbuffer) - 1] = 0;
|
|
||||||
loglog(logbuffer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Messenger.h"
|
#include "Messenger.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#define __TOX_DEFINED__
|
#define __TOX_DEFINED__
|
||||||
typedef struct Messenger Tox;
|
typedef struct Messenger Tox;
|
||||||
|
@ -788,6 +789,7 @@ int tox_isconnected(Tox *tox)
|
||||||
*/
|
*/
|
||||||
Tox *tox_new(uint8_t ipv6enabled)
|
Tox *tox_new(uint8_t ipv6enabled)
|
||||||
{
|
{
|
||||||
|
LOGGER_INIT(LOGGER_OUTPUT_FILE, LOGGER_LEVEL);
|
||||||
return new_messenger(ipv6enabled);
|
return new_messenger(ipv6enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,87 +133,3 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
|
||||||
|
|
||||||
return length == 0 ? 0 : -1;
|
return length == 0 ? 0 : -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef LOGGING
|
|
||||||
time_t starttime = 0;
|
|
||||||
size_t logbufferprelen = 0;
|
|
||||||
char *logbufferpredata = NULL;
|
|
||||||
char *logbufferprehead = NULL;
|
|
||||||
char logbuffer[512];
|
|
||||||
static FILE *logfile = NULL;
|
|
||||||
void loginit(uint16_t port)
|
|
||||||
{
|
|
||||||
if (logfile)
|
|
||||||
fclose(logfile);
|
|
||||||
|
|
||||||
if (!starttime) {
|
|
||||||
unix_time_update();
|
|
||||||
starttime = unix_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tm *tm = localtime(&starttime);
|
|
||||||
|
|
||||||
/* "%F %T" might not be Windows compatible */
|
|
||||||
if (strftime(logbuffer + 32, sizeof(logbuffer) - 32, "%F %T", tm))
|
|
||||||
sprintf(logbuffer, "%u-%s.log", ntohs(port), logbuffer + 32);
|
|
||||||
else
|
|
||||||
sprintf(logbuffer, "%u-%lu.log", ntohs(port), starttime);
|
|
||||||
|
|
||||||
logfile = fopen(logbuffer, "w");
|
|
||||||
|
|
||||||
if (logbufferpredata) {
|
|
||||||
if (logfile)
|
|
||||||
fprintf(logfile, "%s", logbufferpredata);
|
|
||||||
|
|
||||||
free(logbufferpredata);
|
|
||||||
logbufferpredata = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void loglog(char *text)
|
|
||||||
{
|
|
||||||
if (logfile) {
|
|
||||||
fprintf(logfile, "%4u %s", (uint32_t)(unix_time() - starttime), text);
|
|
||||||
fflush(logfile);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* log messages before file was opened: store */
|
|
||||||
|
|
||||||
size_t len = strlen(text);
|
|
||||||
|
|
||||||
if (!starttime) {
|
|
||||||
unix_time_update();
|
|
||||||
starttime = unix_time();
|
|
||||||
|
|
||||||
logbufferprelen = 1024 + len - (len % 1024);
|
|
||||||
logbufferpredata = malloc(logbufferprelen);
|
|
||||||
logbufferprehead = logbufferpredata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* loginit() called meanwhile? (but failed to open) */
|
|
||||||
if (!logbufferpredata)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (len + (logbufferprehead - logbufferpredata) + 16U < logbufferprelen) {
|
|
||||||
size_t logpos = logbufferprehead - logbufferpredata;
|
|
||||||
size_t lennew = logbufferprelen * 1.4;
|
|
||||||
logbufferpredata = realloc(logbufferpredata, lennew);
|
|
||||||
logbufferprehead = logbufferpredata + logpos;
|
|
||||||
logbufferprelen = lennew;
|
|
||||||
}
|
|
||||||
|
|
||||||
int written = sprintf(logbufferprehead, "%4u %s", (uint32_t)(unix_time() - starttime), text);
|
|
||||||
logbufferprehead += written;
|
|
||||||
}
|
|
||||||
|
|
||||||
void logexit()
|
|
||||||
{
|
|
||||||
if (logfile) {
|
|
||||||
fclose(logfile);
|
|
||||||
logfile = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -45,11 +45,4 @@ typedef int (*load_state_callback_func)(void *outer, uint8_t *data, uint32_t len
|
||||||
int load_state(load_state_callback_func load_state_callback, void *outer,
|
int load_state(load_state_callback_func load_state_callback, void *outer,
|
||||||
uint8_t *data, uint32_t length, uint16_t cookie_inner);
|
uint8_t *data, uint32_t length, uint16_t cookie_inner);
|
||||||
|
|
||||||
#ifdef LOGGING
|
|
||||||
extern char logbuffer[512];
|
|
||||||
void loginit(uint16_t port);
|
|
||||||
void loglog(char *text);
|
|
||||||
void logexit();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __UTIL_H__ */
|
#endif /* __UTIL_H__ */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user