mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Done
This commit is contained in:
parent
e4a020333d
commit
9bba7a0434
|
@ -21,8 +21,8 @@ AUTOTEST_LDADD = \
|
||||||
|
|
||||||
|
|
||||||
if BUILD_AV
|
if BUILD_AV
|
||||||
TESTS += toxav_basic_test toxav_many_test
|
TESTS += toxav_basic_test #toxav_many_test
|
||||||
check_PROGRAMS += toxav_basic_test toxav_many_test
|
check_PROGRAMS += toxav_basic_test #toxav_many_test
|
||||||
AUTOTEST_LDADD += libtoxav.la
|
AUTOTEST_LDADD += libtoxav.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -90,11 +90,11 @@ toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||||
toxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS)
|
toxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS)
|
||||||
|
|
||||||
|
|
||||||
toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c
|
#toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c
|
||||||
|
|
||||||
toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
#toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
||||||
|
|
||||||
toxav_many_test_LDADD = $(AUTOTEST_LDADD)
|
#toxav_many_test_LDADD = $(AUTOTEST_LDADD)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <vpx/vpx_image.h>
|
#include <vpx/vpx_image.h>
|
||||||
|
|
||||||
#include "../toxcore/tox.h"
|
#include "../toxcore/tox.h"
|
||||||
|
#include "../toxcore/util.h"
|
||||||
#include "../toxcore/logger.h"
|
#include "../toxcore/logger.h"
|
||||||
#include "../toxcore/crypto_core.h"
|
#include "../toxcore/crypto_core.h"
|
||||||
#include "../toxav/toxav.h"
|
#include "../toxav/toxav.h"
|
||||||
|
@ -28,600 +29,406 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define TEST_REGULAR_AV 1
|
||||||
|
#define TEST_REGULAR_A 1
|
||||||
|
#define TEST_REGULAR_V 1
|
||||||
|
#define TEST_REJECT 1
|
||||||
|
#define TEST_CANCEL 1
|
||||||
|
#define TEST_MUTE_UNMUTE 1
|
||||||
|
|
||||||
typedef enum _CallStatus {
|
|
||||||
none,
|
|
||||||
InCall,
|
|
||||||
Ringing,
|
|
||||||
Ended,
|
|
||||||
Rejected,
|
|
||||||
Canceled,
|
|
||||||
TimedOut
|
|
||||||
|
|
||||||
} CallStatus;
|
typedef struct {
|
||||||
|
bool incoming;
|
||||||
|
uint32_t state;
|
||||||
|
|
||||||
|
} CallControl;
|
||||||
|
|
||||||
typedef struct _Party {
|
|
||||||
CallStatus status;
|
|
||||||
ToxAv *av;
|
|
||||||
time_t *CallStarted;
|
|
||||||
int call_index;
|
|
||||||
} Party;
|
|
||||||
|
|
||||||
typedef struct _Status {
|
/**
|
||||||
Party Alice;
|
* Callbacks
|
||||||
Party Bob;
|
*/
|
||||||
} Status;
|
void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
||||||
|
{
|
||||||
/* My default settings */
|
printf("Handling CALL callback\n");
|
||||||
static ToxAvCSettings muhcaps;
|
((CallControl*)user_data)->incoming = true;
|
||||||
|
}
|
||||||
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
|
||||||
|
{
|
||||||
|
printf("Handling CALL STATE callback: %d\n", state);
|
||||||
|
((CallControl*)user_data)->state = state;
|
||||||
|
}
|
||||||
|
void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
|
uint16_t width, uint16_t height,
|
||||||
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
(void) av;
|
||||||
|
(void) friend_number;
|
||||||
|
(void) width;
|
||||||
|
(void) height;
|
||||||
|
(void) y;
|
||||||
|
(void) u;
|
||||||
|
(void) v;
|
||||||
|
(void) ystride;
|
||||||
|
(void) ustride;
|
||||||
|
(void) vstride;
|
||||||
|
(void) user_data;
|
||||||
|
}
|
||||||
|
void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
|
int16_t const *pcm,
|
||||||
|
size_t sample_count,
|
||||||
|
uint8_t channels,
|
||||||
|
uint32_t sampling_rate,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
(void) av;
|
||||||
|
(void) friend_number;
|
||||||
|
(void) pcm;
|
||||||
|
(void) sample_count;
|
||||||
|
(void) channels;
|
||||||
|
(void) sampling_rate;
|
||||||
|
(void) user_data;
|
||||||
|
}
|
||||||
|
void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
||||||
tox_friend_add_norequest(m, public_key, 0);
|
assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/**
|
||||||
void callback_recv_invite ( void *av, int32_t call_index, void *_arg )
|
* Iterate helper
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
// ...
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
/* Bob always receives invite */
|
|
||||||
cast->Bob.status = Ringing;
|
|
||||||
cast->Bob.call_index = call_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void callback_recv_ringing ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
/* Alice always sends invite */
|
|
||||||
cast->Alice.status = Ringing;
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void callback_call_started ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
printf("Call started on Alices side...\n");
|
|
||||||
cast->Alice.status = InCall;
|
|
||||||
toxav_prepare_transmission(av, call_index, 1);
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
printf("Call started on Bob side...\n");
|
|
||||||
cast->Bob.status = InCall;
|
|
||||||
toxav_prepare_transmission(av, call_index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void callback_call_canceled ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
// ...
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
printf ( "Call Canceled for Bob!\n" );
|
|
||||||
cast->Bob.status = Canceled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void callback_call_rejected ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
printf ( "Call rejected by Bob!\n"
|
|
||||||
"Call ended for Alice!\n" );
|
|
||||||
|
|
||||||
/* If Bob rejects, call is ended for alice and she sends ending */
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
cast->Alice.status = Rejected;
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
//... ignor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void callback_call_ended ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
printf ( "Call ended for Alice!\n" );
|
|
||||||
cast->Alice.status = Ended;
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
printf ( "Call ended for Bob!\n" );
|
|
||||||
cast->Bob.status = Ended;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_peer_cs_change ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
ToxAvCSettings csettings;
|
|
||||||
toxav_get_peer_csettings(av, call_index, 0, &csettings);
|
|
||||||
|
|
||||||
printf("Peer changing settings to: \n"
|
|
||||||
"Type: %u \n"
|
|
||||||
"Video bitrate: %u \n"
|
|
||||||
"Video height: %u \n"
|
|
||||||
"Video width: %u \n"
|
|
||||||
"Audio bitrate: %u \n"
|
|
||||||
"Audio framedur: %u \n"
|
|
||||||
"Audio sample rate: %u \n"
|
|
||||||
"Audio channels: %u \n",
|
|
||||||
csettings.call_type,
|
|
||||||
csettings.video_bitrate,
|
|
||||||
csettings.max_video_height,
|
|
||||||
csettings.max_video_width,
|
|
||||||
csettings.audio_bitrate,
|
|
||||||
csettings.audio_frame_duration,
|
|
||||||
csettings.audio_sample_rate,
|
|
||||||
csettings.audio_channels
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_self_cs_change ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
ToxAvCSettings csettings;
|
|
||||||
toxav_get_peer_csettings(av, call_index, 0, &csettings);
|
|
||||||
|
|
||||||
printf("Changed settings to: \n"
|
|
||||||
"Type: %u \n"
|
|
||||||
"Video bitrate: %u \n"
|
|
||||||
"Video height: %u \n"
|
|
||||||
"Video width: %u \n"
|
|
||||||
"Audio bitrate: %u \n"
|
|
||||||
"Audio framedur: %u \n"
|
|
||||||
"Audio sample rate: %u \n"
|
|
||||||
"Audio channels: %u \n",
|
|
||||||
csettings.call_type,
|
|
||||||
csettings.video_bitrate,
|
|
||||||
csettings.max_video_height,
|
|
||||||
csettings.max_video_width,
|
|
||||||
csettings.audio_bitrate,
|
|
||||||
csettings.audio_frame_duration,
|
|
||||||
csettings.audio_sample_rate,
|
|
||||||
csettings.audio_channels
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_requ_timeout ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
printf("Call timed-out!\n");
|
|
||||||
|
|
||||||
if (cast->Alice.av == av) {
|
|
||||||
cast->Alice.status = TimedOut;
|
|
||||||
} else if (cast->Bob.av == av) {
|
|
||||||
cast->Bob.status = TimedOut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_audio (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void callback_video (void *agent, int32_t call_idx, const vpx_image_t *img, void *data)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void register_callbacks(ToxAv *av, void *data)
|
|
||||||
{
|
|
||||||
toxav_register_callstate_callback(av, callback_call_started, av_OnStart, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_call_canceled, av_OnCancel, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_peer_cs_change, av_OnPeerCSChange, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_self_cs_change, av_OnSelfCSChange, data);
|
|
||||||
toxav_register_audio_callback(av, callback_audio, NULL);
|
|
||||||
toxav_register_video_callback(av, callback_video, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/* Alice calls bob and the call starts.
|
|
||||||
* What happens during the call is defined after. To quit the loop use: step++;
|
|
||||||
*/
|
*/
|
||||||
#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \
|
int iterate_tox(Tox* bootstrap, Tox* Alice, Tox* Bob)
|
||||||
{ int step = 0, running = 1; while (running) {\
|
{
|
||||||
tox_iterate(bootstrap_node); tox_iterate(Alice); tox_iterate(Bob); \
|
tox_iterate(bootstrap);
|
||||||
toxav_do(status_control.Bob.av); toxav_do(status_control.Alice.av); \
|
tox_iterate(Alice);
|
||||||
switch ( step ) {\
|
tox_iterate(Bob);
|
||||||
case 0: /* Alice */ printf("Alice is calling...\n");\
|
|
||||||
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10); step++; break;\
|
return MIN(tox_iteration_interval(Alice), tox_iteration_interval(Bob));
|
||||||
case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\
|
}
|
||||||
cur_time = time(NULL); toxav_answer(status_control.Bob.av, status_control.Bob.call_index, &muhcaps); step++; } break; \
|
|
||||||
case 2: /* Rtp transmission */ \
|
|
||||||
if (status_control.Bob.status == InCall && status_control.Alice.status == InCall)
|
|
||||||
|
|
||||||
|
|
||||||
#define TERMINATE_SCOPE() break;\
|
|
||||||
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");
|
|
||||||
|
|
||||||
START_TEST(test_AV_flows)
|
START_TEST(test_AV_flows)
|
||||||
{
|
{
|
||||||
|
Tox* Alice, *Bob, *bootstrap;
|
||||||
|
ToxAV* AliceAV, *BobAV;
|
||||||
|
|
||||||
|
CallControl AliceCC, BobCC;
|
||||||
|
|
||||||
|
{
|
||||||
|
TOX_ERR_NEW error;
|
||||||
|
|
||||||
|
bootstrap = tox_new(NULL, NULL, 0, &error);
|
||||||
|
assert(error == TOX_ERR_NEW_OK);
|
||||||
|
|
||||||
|
Alice = tox_new(NULL, NULL, 0, &error);
|
||||||
|
assert(error == TOX_ERR_NEW_OK);
|
||||||
|
|
||||||
|
Bob = tox_new(NULL, NULL, 0, &error);
|
||||||
|
assert(error == TOX_ERR_NEW_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Created 3 instances of Tox\n");
|
||||||
|
printf("Preparing network...\n");
|
||||||
long long unsigned int cur_time = time(NULL);
|
long long unsigned int cur_time = time(NULL);
|
||||||
Tox *bootstrap_node = tox_new(0, 0, 0, 0);
|
|
||||||
Tox *Alice = tox_new(0, 0, 0, 0);
|
|
||||||
Tox *Bob = tox_new(0, 0, 0, 0);
|
|
||||||
|
|
||||||
ck_assert_msg(bootstrap_node || Alice || Bob, "Failed to create 3 tox instances");
|
|
||||||
|
|
||||||
uint32_t to_compare = 974536;
|
uint32_t to_compare = 974536;
|
||||||
tox_callback_friend_request(Alice, accept_friend_request, &to_compare);
|
|
||||||
uint8_t address[TOX_ADDRESS_SIZE];
|
uint8_t address[TOX_ADDRESS_SIZE];
|
||||||
|
|
||||||
|
tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);
|
||||||
tox_self_get_address(Alice, address);
|
tox_self_get_address(Alice, address);
|
||||||
uint32_t test = tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, 0);
|
|
||||||
|
|
||||||
ck_assert_msg(test == 0, "Failed to add friend error code: %i", test);
|
assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
|
||||||
|
|
||||||
uint8_t off = 1;
|
uint8_t off = 1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
tox_iterate(bootstrap_node);
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
tox_iterate(Alice);
|
|
||||||
tox_iterate(Bob);
|
if (tox_self_get_connection_status(bootstrap) &&
|
||||||
|
tox_self_get_connection_status(Alice) &&
|
||||||
if (tox_self_get_connection_status(bootstrap_node) && tox_self_get_connection_status(Alice)
|
tox_self_get_connection_status(Bob) && off) {
|
||||||
&& tox_self_get_connection_status(Bob)
|
|
||||||
&& off) {
|
|
||||||
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
|
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
|
||||||
off = 0;
|
off = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_friend_get_connection_status(Alice, 0, 0) && tox_friend_get_connection_status(Bob, 0, 0))
|
if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&
|
||||||
|
tox_friend_get_connection_status(Bob, 0, NULL) == TOX_CONNECTION_UDP)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
c_sleep(20);
|
c_sleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
|
||||||
|
|
||||||
muhcaps = av_DefaultSettings;
|
|
||||||
muhcaps.max_video_height = muhcaps.max_video_width = 128;
|
|
||||||
|
|
||||||
Status status_control = {
|
|
||||||
{none, toxav_new(Alice, 1), NULL, -1},
|
|
||||||
{none, toxav_new(Bob, 1), NULL, -1},
|
|
||||||
};
|
|
||||||
|
|
||||||
ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
|
|
||||||
|
|
||||||
|
|
||||||
register_callbacks(status_control.Alice.av, &status_control);
|
|
||||||
register_callbacks(status_control.Bob.av, &status_control);
|
|
||||||
|
|
||||||
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
|
||||||
int16_t sample_payload[frame_size];
|
|
||||||
randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);
|
|
||||||
|
|
||||||
uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
|
|
||||||
int payload_size;
|
|
||||||
|
|
||||||
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_U], sample_payload, 10);
|
|
||||||
memcpy(sample_image->planes[VPX_PLANE_V], sample_payload, 10);
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
* Successful flows (when call starts)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call with audio only on both sides. Alice calls Bob.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
|
|
||||||
/* Both send */
|
|
||||||
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.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.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);
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
|
||||||
step++; /* This terminates the loop */
|
|
||||||
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
|
||||||
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TERMINATE_SCOPE()
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call with audio on both sides and video on one side. Alice calls Bob.
|
|
||||||
*/
|
|
||||||
CALL_AND_START_LOOP(TypeAudio, TypeVideo) {
|
|
||||||
/* Both send */
|
|
||||||
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.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.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);
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
|
||||||
step++; /* This terminates the loop */
|
|
||||||
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
|
||||||
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TERMINATE_SCOPE()
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call with audio and video on both sides. Alice calls Bob.
|
|
||||||
*/
|
|
||||||
CALL_AND_START_LOOP(TypeVideo, TypeVideo) {
|
|
||||||
/* Both send */
|
|
||||||
|
|
||||||
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.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.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);
|
|
||||||
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
|
||||||
step++; /* This terminates the loop */
|
|
||||||
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
|
||||||
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TERMINATE_SCOPE()
|
|
||||||
|
|
||||||
|
|
||||||
uint64_t times_they_are_a_changin = time(NULL);
|
|
||||||
/* Media change */
|
|
||||||
CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
|
|
||||||
/* Both send */
|
|
||||||
payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.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.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);
|
|
||||||
|
|
||||||
/* Wait 2 seconds and change transmission type */
|
|
||||||
if (time(NULL) - times_they_are_a_changin > 2) {
|
|
||||||
times_they_are_a_changin = time(NULL);
|
|
||||||
muhcaps.audio_bitrate ++;
|
|
||||||
toxav_change_settings(status_control.Alice.av, status_control.Alice.call_index, &muhcaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
|
||||||
step++; /* This terminates the loop */
|
|
||||||
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
|
|
||||||
|
|
||||||
/* Call over Alice hangs up */
|
|
||||||
toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TERMINATE_SCOPE()
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
* Other flows
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call and reject
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
int step = 0;
|
TOXAV_ERR_NEW error;
|
||||||
int running = 1;
|
AliceAV = toxav_new(Alice, &error);
|
||||||
|
assert(error == TOXAV_ERR_NEW_OK);
|
||||||
while (running) {
|
|
||||||
tox_iterate(bootstrap_node);
|
BobAV = toxav_new(Bob, &error);
|
||||||
tox_iterate(Alice);
|
assert(error == TOXAV_ERR_NEW_OK);
|
||||||
tox_iterate(Bob);
|
|
||||||
|
|
||||||
switch ( step ) {
|
|
||||||
case 0: /* Alice */
|
|
||||||
printf("Alice is calling...\n");
|
|
||||||
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10);
|
|
||||||
step++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: /* Bob */
|
|
||||||
if (status_control.Bob.status == Ringing) {
|
|
||||||
printf("Bob rejects...\n");
|
|
||||||
toxav_reject(status_control.Bob.av, status_control.Bob.call_index, "Who likes D's anyway?");
|
|
||||||
step++;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* Wait for Both to have status ended */
|
|
||||||
if (status_control.Alice.status == Rejected && status_control.Bob.status == Ended) running = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
c_sleep(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toxav_callback_call(AliceAV, t_toxav_call_cb, &AliceCC);
|
||||||
/*
|
toxav_callback_call_state(AliceAV, t_toxav_call_state_cb, &AliceCC);
|
||||||
* Call and cancel
|
toxav_callback_receive_video_frame(AliceAV, t_toxav_receive_video_frame_cb, &AliceCC);
|
||||||
*/
|
toxav_callback_receive_audio_frame(AliceAV, t_toxav_receive_audio_frame_cb, &AliceCC);
|
||||||
{
|
|
||||||
int step = 0;
|
toxav_callback_call(BobAV, t_toxav_call_cb, &BobCC);
|
||||||
int running = 1;
|
toxav_callback_call_state(BobAV, t_toxav_call_state_cb, &BobCC);
|
||||||
|
toxav_callback_receive_video_frame(BobAV, t_toxav_receive_video_frame_cb, &BobCC);
|
||||||
while (running) {
|
toxav_callback_receive_audio_frame(BobAV, t_toxav_receive_audio_frame_cb, &BobCC);
|
||||||
tox_iterate(bootstrap_node);
|
|
||||||
tox_iterate(Alice);
|
printf("Created 2 instances of ToxAV\n");
|
||||||
tox_iterate(Bob);
|
printf("All set after %llu seconds!\n", time(NULL) - cur_time);
|
||||||
|
|
||||||
toxav_do(status_control.Alice.av);
|
|
||||||
toxav_do(status_control.Bob.av);
|
#define REGULAR_CALL_FLOW(A_BR, V_BR) \
|
||||||
|
do { \
|
||||||
|
memset(&AliceCC, 0, sizeof(CallControl)); \
|
||||||
switch ( step ) {
|
memset(&BobCC, 0, sizeof(CallControl)); \
|
||||||
case 0: /* Alice */
|
\
|
||||||
printf("Alice is calling...\n");
|
TOXAV_ERR_CALL rc; \
|
||||||
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10);
|
toxav_call(AliceAV, 0, A_BR, V_BR, &rc); \
|
||||||
step++;
|
\
|
||||||
break;
|
if (rc != TOXAV_ERR_CALL_OK) { \
|
||||||
|
printf("toxav_call failed: %d\n", rc); \
|
||||||
|
exit(1); \
|
||||||
case 1: /* Alice again */
|
} \
|
||||||
if (status_control.Bob.status == Ringing) {
|
\
|
||||||
printf("Alice cancels...\n");
|
\
|
||||||
toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?");
|
long long unsigned int start_time = time(NULL); \
|
||||||
step++;
|
\
|
||||||
}
|
\
|
||||||
|
while (BobCC.state != TOXAV_CALL_STATE_END) { \
|
||||||
break;
|
\
|
||||||
|
if (BobCC.incoming) { \
|
||||||
case 2: /* Wait for Both to have status ended */
|
TOXAV_ERR_ANSWER rc; \
|
||||||
if (status_control.Bob.status == Canceled) running = 0;
|
toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \
|
||||||
|
\
|
||||||
break;
|
if (rc != TOXAV_ERR_ANSWER_OK) { \
|
||||||
}
|
printf("toxav_answer failed: %d\n", rc); \
|
||||||
|
exit(1); \
|
||||||
c_sleep(20);
|
} \
|
||||||
}
|
BobCC.incoming = false; \
|
||||||
|
} else { \
|
||||||
printf("\n");
|
/* TODO rtp */ \
|
||||||
|
\
|
||||||
|
if (time(NULL) - start_time == 5) { \
|
||||||
|
\
|
||||||
|
TOXAV_ERR_CALL_CONTROL rc; \
|
||||||
|
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \
|
||||||
|
\
|
||||||
|
if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \
|
||||||
|
printf("toxav_call_control failed: %d\n", rc); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
iterate_tox(bootstrap, Alice, Bob); \
|
||||||
|
} \
|
||||||
|
printf("Success!\n");\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
if (TEST_REGULAR_AV) {
|
||||||
|
printf("\nTrying regular call (Audio and Video)...\n");
|
||||||
|
REGULAR_CALL_FLOW(48, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (TEST_REGULAR_A) {
|
||||||
* Timeout
|
printf("\nTrying regular call (Audio only)...\n");
|
||||||
*/
|
REGULAR_CALL_FLOW(48, 0);
|
||||||
{
|
|
||||||
int step = 0;
|
|
||||||
int running = 1;
|
|
||||||
|
|
||||||
while (running) {
|
|
||||||
tox_iterate(bootstrap_node);
|
|
||||||
tox_iterate(Alice);
|
|
||||||
tox_iterate(Bob);
|
|
||||||
|
|
||||||
toxav_do(status_control.Alice.av);
|
|
||||||
toxav_do(status_control.Bob.av);
|
|
||||||
|
|
||||||
switch ( step ) {
|
|
||||||
case 0:
|
|
||||||
printf("Alice is calling...\n");
|
|
||||||
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10);
|
|
||||||
step++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
if (status_control.Alice.status == TimedOut) running = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
c_sleep(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vpx_img_free(sample_image);
|
if (TEST_REGULAR_V) {
|
||||||
toxav_kill(status_control.Alice.av);
|
printf("\nTrying regular call (Video only)...\n");
|
||||||
toxav_kill(status_control.Bob.av);
|
REGULAR_CALL_FLOW(0, 4000);
|
||||||
tox_kill(bootstrap_node);
|
}
|
||||||
tox_kill(Alice);
|
|
||||||
|
#undef REGULAR_CALL_FLOW
|
||||||
|
|
||||||
|
if (TEST_REJECT) { /* Alice calls; Bob rejects */
|
||||||
|
printf("\nTrying reject flow...\n");
|
||||||
|
|
||||||
|
memset(&AliceCC, 0, sizeof(CallControl));
|
||||||
|
memset(&BobCC, 0, sizeof(CallControl));
|
||||||
|
|
||||||
|
{
|
||||||
|
TOXAV_ERR_CALL rc;
|
||||||
|
toxav_call(AliceAV, 0, 48, 0, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_CALL_OK) {
|
||||||
|
printf("toxav_call failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!BobCC.incoming)
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
|
||||||
|
/* Reject */
|
||||||
|
{
|
||||||
|
TOXAV_ERR_CALL_CONTROL rc;
|
||||||
|
toxav_call_control(BobAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
||||||
|
printf("toxav_call_control failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (AliceCC.state != TOXAV_CALL_STATE_END)
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
|
||||||
|
printf("Success!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */
|
||||||
|
printf("\nTrying cancel (while ringing) flow...\n");
|
||||||
|
|
||||||
|
memset(&AliceCC, 0, sizeof(CallControl));
|
||||||
|
memset(&BobCC, 0, sizeof(CallControl));
|
||||||
|
|
||||||
|
{
|
||||||
|
TOXAV_ERR_CALL rc;
|
||||||
|
toxav_call(AliceAV, 0, 48, 0, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_CALL_OK) {
|
||||||
|
printf("toxav_call failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!BobCC.incoming)
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
|
||||||
|
/* Cancel */
|
||||||
|
{
|
||||||
|
TOXAV_ERR_CALL_CONTROL rc;
|
||||||
|
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
||||||
|
printf("toxav_call_control failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alice will not receive end state */
|
||||||
|
while (BobCC.state != TOXAV_CALL_STATE_END)
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
|
||||||
|
printf("Success!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */
|
||||||
|
printf("\nTrying mute functionality...\n");
|
||||||
|
|
||||||
|
memset(&AliceCC, 0, sizeof(CallControl));
|
||||||
|
memset(&BobCC, 0, sizeof(CallControl));
|
||||||
|
|
||||||
|
/* Assume sending audio and video */
|
||||||
|
{
|
||||||
|
TOXAV_ERR_CALL rc;
|
||||||
|
toxav_call(AliceAV, 0, 48, 1000, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_CALL_OK) {
|
||||||
|
printf("toxav_call failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!BobCC.incoming)
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
|
||||||
|
/* At first try all stuff while in invalid state */
|
||||||
|
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
|
||||||
|
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
|
||||||
|
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
||||||
|
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
|
||||||
|
|
||||||
|
{
|
||||||
|
TOXAV_ERR_ANSWER rc;
|
||||||
|
toxav_answer(BobAV, 0, 48, 4000, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_ANSWER_OK) {
|
||||||
|
printf("toxav_answer failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
|
||||||
|
/* Pause and Resume */
|
||||||
|
printf("Pause and Resume\n");
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state == TOXAV_CALL_STATE_PAUSED);
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V));
|
||||||
|
|
||||||
|
/* Mute/Unmute single */
|
||||||
|
printf("Mute/Unmute single\n");
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
|
||||||
|
|
||||||
|
/* Mute/Unmute both */
|
||||||
|
printf("Mute/Unmute both\n");
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V);
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
|
||||||
|
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V);
|
||||||
|
|
||||||
|
{
|
||||||
|
TOXAV_ERR_CALL_CONTROL rc;
|
||||||
|
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
||||||
|
printf("toxav_call_control failed: %d\n", rc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_tox(bootstrap, Alice, Bob);
|
||||||
|
assert(BobCC.state == TOXAV_CALL_STATE_END);
|
||||||
|
|
||||||
|
printf("Success!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
toxav_kill(BobAV);
|
||||||
|
toxav_kill(AliceAV);
|
||||||
tox_kill(Bob);
|
tox_kill(Bob);
|
||||||
|
tox_kill(Alice);
|
||||||
printf("Calls ended!\n");
|
tox_kill(bootstrap);
|
||||||
|
|
||||||
|
printf("\nTest successful!\n");
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
Suite *tox_suite(void)
|
Suite *tox_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("ToxAV");
|
Suite *s = suite_create("ToxAV");
|
||||||
|
|
||||||
DEFTESTCASE_SLOW(AV_flows, 200);
|
DEFTESTCASE_SLOW(AV_flows, 200);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -637,6 +444,4 @@ int main(int argc, char *argv[])
|
||||||
srunner_free(test_runner);
|
srunner_free(test_runner);
|
||||||
|
|
||||||
return number_failed;
|
return number_failed;
|
||||||
|
|
||||||
// return test_AV_flows();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <vpx/vpx_image.h>
|
#include <vpx/vpx_image.h>
|
||||||
|
|
||||||
#include "../toxcore/tox.h"
|
#include "../toxcore/tox.h"
|
||||||
|
#include "../toxcore/util.h"
|
||||||
#include "../toxcore/logger.h"
|
#include "../toxcore/logger.h"
|
||||||
#include "../toxcore/crypto_core.h"
|
#include "../toxcore/crypto_core.h"
|
||||||
#include "../toxav/toxav.h"
|
#include "../toxav/toxav.h"
|
||||||
|
@ -26,359 +27,177 @@
|
||||||
#define c_sleep(x) usleep(1000*x)
|
#define c_sleep(x) usleep(1000*x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_t muhmutex;
|
|
||||||
|
|
||||||
typedef enum _CallStatus {
|
typedef struct {
|
||||||
none,
|
bool incoming;
|
||||||
InCall,
|
uint32_t state;
|
||||||
Ringing,
|
|
||||||
Ended,
|
} CallControl;
|
||||||
Rejected,
|
|
||||||
Canceled
|
|
||||||
|
|
||||||
} CallStatus;
|
|
||||||
|
|
||||||
typedef struct _Party {
|
/**
|
||||||
CallStatus status;
|
* Callbacks
|
||||||
ToxAv *av;
|
*/
|
||||||
int id;
|
void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
||||||
} Party;
|
{
|
||||||
|
printf("Handling CALL callback\n");
|
||||||
typedef struct _ACall {
|
((CallControl*)user_data)->incoming = true;
|
||||||
pthread_t tid;
|
}
|
||||||
int idx;
|
void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
|
||||||
|
{
|
||||||
Party Caller;
|
printf("Handling CALL STATE callback: %d\n", state);
|
||||||
Party Callee;
|
((CallControl*)user_data)->state = state;
|
||||||
} ACall;
|
}
|
||||||
|
void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
typedef struct _Status {
|
uint16_t width, uint16_t height,
|
||||||
ACall calls[3]; /* Make 3 calls for this test */
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
} Status;
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
|
void *user_data)
|
||||||
Status status_control;
|
{
|
||||||
|
(void) av;
|
||||||
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
(void) friend_number;
|
||||||
|
(void) width;
|
||||||
|
(void) height;
|
||||||
|
(void) y;
|
||||||
|
(void) u;
|
||||||
|
(void) v;
|
||||||
|
(void) ystride;
|
||||||
|
(void) ustride;
|
||||||
|
(void) vstride;
|
||||||
|
(void) user_data;
|
||||||
|
}
|
||||||
|
void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
|
int16_t const *pcm,
|
||||||
|
size_t sample_count,
|
||||||
|
uint8_t channels,
|
||||||
|
uint32_t sampling_rate,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
(void) av;
|
||||||
|
(void) friend_number;
|
||||||
|
(void) pcm;
|
||||||
|
(void) sample_count;
|
||||||
|
(void) channels;
|
||||||
|
(void) sampling_rate;
|
||||||
|
(void) user_data;
|
||||||
|
}
|
||||||
|
void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
||||||
tox_friend_add_norequest(m, public_key, 0);
|
assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/**
|
||||||
void callback_recv_invite ( void *av, int32_t call_index, void *_arg )
|
* Iterate helper
|
||||||
|
*/
|
||||||
|
ToxAV* setup_av_instance(Tox* tox, CallControl *CC)
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
TOXAV_ERR_NEW error;
|
||||||
cast->calls[call_index].Callee.status = Ringing;
|
|
||||||
|
ToxAV* av = toxav_new(tox, &error);
|
||||||
|
assert(error == TOXAV_ERR_NEW_OK);
|
||||||
|
|
||||||
|
toxav_callback_call(av, t_toxav_call_cb, CC);
|
||||||
|
toxav_callback_call_state(av, t_toxav_call_state_cb, CC);
|
||||||
|
toxav_callback_receive_video_frame(av, t_toxav_receive_video_frame_cb, CC);
|
||||||
|
toxav_callback_receive_audio_frame(av, t_toxav_receive_audio_frame_cb, CC);
|
||||||
|
|
||||||
|
return av;
|
||||||
}
|
}
|
||||||
void callback_recv_ringing ( void *av, int32_t call_index, void *_arg )
|
void* call_thread(ToxAV* Alice, ToxAV* Bob)
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
|
||||||
cast->calls[call_index].Caller.status = Ringing;
|
|
||||||
}
|
|
||||||
void callback_call_ended ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (av == cast->calls[call_index].Caller.av)
|
|
||||||
cast->calls[call_index].Caller.status = Ended;
|
|
||||||
else
|
|
||||||
cast->calls[call_index].Callee.status = Ended;
|
|
||||||
}
|
|
||||||
void callback_call_started ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
|
|
||||||
if (av == cast->calls[call_index].Caller.av)
|
|
||||||
cast->calls[call_index].Caller.status = InCall;
|
|
||||||
else
|
|
||||||
cast->calls[call_index].Callee.status = InCall;
|
|
||||||
}
|
|
||||||
void callback_call_canceled ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void callback_call_rejected ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
Status *cast = _arg;
|
|
||||||
cast->calls[call_index].Caller.status = Rejected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_requ_timeout ( void *av, int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
ck_assert_msg(0, "No answer!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_audio (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void callback_video (void *agent, int32_t call_idx, const vpx_image_t *img, void *data)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void register_callbacks(ToxAv *av, void *data)
|
|
||||||
{
|
|
||||||
toxav_register_callstate_callback(av, callback_call_started, av_OnStart, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_call_canceled, av_OnCancel, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_call_rejected, av_OnReject, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_call_ended, av_OnEnd, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_recv_invite, av_OnInvite, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_recv_ringing, av_OnRinging, data);
|
|
||||||
toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
|
|
||||||
|
|
||||||
|
|
||||||
toxav_register_audio_callback(av, callback_audio, NULL);
|
|
||||||
toxav_register_video_callback(av, callback_video, NULL);
|
|
||||||
}
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
int call_running[3];
|
|
||||||
|
|
||||||
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;
|
|
||||||
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((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);
|
|
||||||
|
|
||||||
uint8_t prepared_payload[RTP_PAYLOAD_SIZE];
|
|
||||||
|
|
||||||
register_callbacks(this_call->Caller.av, &status_control);
|
|
||||||
register_callbacks(this_call->Callee.av, arg);
|
|
||||||
|
|
||||||
/* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
|
|
||||||
while (call_running[this_call->idx]) {
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
|
|
||||||
switch ( step ) {
|
|
||||||
case 0: /* CALLER */
|
|
||||||
toxav_call(this_call->Caller.av, &call_idx, this_call->Callee.id, &av_DefaultSettings, 10);
|
|
||||||
call_print(call_idx, "Calling ...");
|
|
||||||
step++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: /* CALLEE */
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
|
|
||||||
if (this_call->Caller.status == Ringing) {
|
|
||||||
call_print(call_idx, "Callee answers ...");
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
toxav_answer(this_call->Callee.av, 0, &av_DefaultSettings);
|
|
||||||
step++;
|
|
||||||
start = time(NULL);
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* Rtp transmission */
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
|
|
||||||
if (this_call->Caller.status == InCall) { /* I think this is okay */
|
|
||||||
call_print(call_idx, "Sending rtp ...");
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
|
|
||||||
c_sleep(1000); /* We have race condition here */
|
|
||||||
toxav_prepare_transmission(this_call->Callee.av, 0, 1);
|
|
||||||
toxav_prepare_transmission(this_call->Caller.av, call_idx, 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;
|
|
||||||
|
|
||||||
c_sleep(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
step++; /* This terminates the loop */
|
|
||||||
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
toxav_kill_transmission(this_call->Callee.av, 0);
|
|
||||||
toxav_kill_transmission(this_call->Caller.av, call_idx);
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
|
|
||||||
/* Call over CALLER hangs up */
|
|
||||||
toxav_hangup(this_call->Caller.av, call_idx);
|
|
||||||
call_print(call_idx, "Hanging up ...");
|
|
||||||
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: /* Wait for Both to have status ended */
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
|
|
||||||
if (this_call->Caller.status == Ended) {
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
c_sleep(1000); /* race condition */
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
this_call->Callee.status = Ended;
|
|
||||||
call_running[this_call->idx] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
c_sleep(20);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
call_print(call_idx, "Call ended successfully!");
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
START_TEST(test_AV_three_calls)
|
START_TEST(test_AV_three_calls)
|
||||||
// void test_AV_three_calls()
|
|
||||||
{
|
{
|
||||||
long long unsigned int cur_time = time(NULL);
|
Tox* Alice, *bootstrap, *Bobs[3];
|
||||||
Tox *bootstrap_node = tox_new(0, 0, 0, 0);
|
ToxAV* AliceAV, *BobsAV[3];
|
||||||
Tox *caller = tox_new(0, 0, 0, 0);
|
|
||||||
Tox *callees[3] = {
|
CallControl AliceCC[3], BobsCC[3];
|
||||||
tox_new(0, 0, 0, 0),
|
|
||||||
tox_new(0, 0, 0, 0),
|
|
||||||
tox_new(0, 0, 0, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ck_assert_msg(bootstrap_node != NULL, "Failed to create bootstrap node");
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
{
|
||||||
for (; i < 3; i ++) {
|
TOX_ERR_NEW error;
|
||||||
ck_assert_msg(callees[i] != NULL, "Failed to create 3 tox instances");
|
|
||||||
}
|
bootstrap = tox_new(NULL, NULL, 0, &error);
|
||||||
|
assert(error == TOX_ERR_NEW_OK);
|
||||||
for ( i = 0; i < 3; i ++ ) {
|
|
||||||
uint32_t to_compare = 974536;
|
Alice = tox_new(NULL, NULL, 0, &error);
|
||||||
tox_callback_friend_request(callees[i], accept_friend_request, &to_compare);
|
assert(error == TOX_ERR_NEW_OK);
|
||||||
uint8_t address[TOX_ADDRESS_SIZE];
|
|
||||||
tox_self_get_address(callees[i], address);
|
for (; i < 3; i ++) {
|
||||||
|
BobsAV[i] = tox_new(NULL, NULL, 0, &error);
|
||||||
uint32_t test = tox_friend_add(caller, address, (uint8_t *)"gentoo", 7, 0);
|
assert(error == TOX_ERR_NEW_OK);
|
||||||
ck_assert_msg( test == i, "Failed to add friend error code: %i", test);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t off = 1;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
tox_iterate(bootstrap_node);
|
|
||||||
tox_iterate(caller);
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i ++) {
|
|
||||||
tox_iterate(callees[i]);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tox_self_get_connection_status(bootstrap_node) &&
|
printf("Created 5 instances of Tox\n");
|
||||||
tox_self_get_connection_status(caller) &&
|
printf("Preparing network...\n");
|
||||||
tox_self_get_connection_status(callees[0]) &&
|
long long unsigned int cur_time = time(NULL);
|
||||||
tox_self_get_connection_status(callees[1]) &&
|
|
||||||
tox_self_get_connection_status(callees[2]) && off) {
|
uint32_t to_compare = 974536;
|
||||||
|
uint8_t address[TOX_ADDRESS_SIZE];
|
||||||
|
|
||||||
|
tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);
|
||||||
|
tox_self_get_address(Alice, address);
|
||||||
|
|
||||||
|
|
||||||
|
assert(tox_friend_add(Bobs[0], address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
|
||||||
|
assert(tox_friend_add(Bobs[1], address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
|
||||||
|
assert(tox_friend_add(Bobs[2], address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
|
||||||
|
|
||||||
|
uint8_t off = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
tox_iterate(bootstrap);
|
||||||
|
tox_iterate(Alice);
|
||||||
|
tox_iterate(Bobs[0]);
|
||||||
|
tox_iterate(Bobs[1]);
|
||||||
|
tox_iterate(Bobs[2]);
|
||||||
|
|
||||||
|
if (tox_self_get_connection_status(bootstrap) &&
|
||||||
|
tox_self_get_connection_status(Alice) &&
|
||||||
|
tox_self_get_connection_status(Bobs[0]) &&
|
||||||
|
tox_self_get_connection_status(Bobs[1]) &&
|
||||||
|
tox_self_get_connection_status(Bobs[2]) && off) {
|
||||||
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
|
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
|
||||||
off = 0;
|
off = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&
|
||||||
if (tox_friend_get_connection_status(caller, 0, 0) &&
|
tox_friend_get_connection_status(Alice, 1, NULL) == TOX_CONNECTION_UDP &&
|
||||||
tox_friend_get_connection_status(caller, 1, 0) &&
|
tox_friend_get_connection_status(Alice, 2, NULL) == TOX_CONNECTION_UDP &&
|
||||||
tox_friend_get_connection_status(caller, 2, 0) )
|
tox_friend_get_connection_status(Bobs[0], 0, NULL) == TOX_CONNECTION_UDP &&
|
||||||
|
tox_friend_get_connection_status(Bobs[1], 0, NULL) == TOX_CONNECTION_UDP &&
|
||||||
|
tox_friend_get_connection_status(Bobs[2], 0, NULL) == TOX_CONNECTION_UDP)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
c_sleep(20);
|
c_sleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
AliceAV = setup_av_instance(Alice, &AliceCC);
|
||||||
|
BobsAV[0] = setup_av_instance(Bobs[0], &BobsCC[0]);
|
||||||
ToxAv *uniqcallerav = toxav_new(caller, 3);
|
BobsAV[1] = setup_av_instance(Bobs[1], &BobsCC[1]);
|
||||||
|
BobsAV[2] = setup_av_instance(Bobs[2], &BobsCC[2]);
|
||||||
|
|
||||||
|
printf("Created 4 instances of ToxAV\n");
|
||||||
|
printf("All set after %llu seconds!\n", time(NULL) - cur_time);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
tox_kill(bootstrap);
|
||||||
|
tox_kill(Alice);
|
||||||
|
toxav_kill(AliceAV);
|
||||||
|
|
||||||
for (i = 0; i < 3; i ++) {
|
for (i = 0; i < 3; i ++) {
|
||||||
status_control.calls[i].idx = i;
|
tox_kill(Bobs[i]);
|
||||||
|
toxav_kill(BobsAV[i]);
|
||||||
status_control.calls[i].Caller.av = uniqcallerav;
|
|
||||||
status_control.calls[i].Caller.id = 0;
|
|
||||||
status_control.calls[i].Caller.status = none;
|
|
||||||
|
|
||||||
status_control.calls[i].Callee.av = toxav_new(callees[i], 1);
|
|
||||||
status_control.calls[i].Callee.id = i;
|
|
||||||
status_control.calls[i].Callee.status = none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_init(&muhmutex, NULL);
|
printf("\nTest successful!\n");
|
||||||
|
|
||||||
for ( i = 0; i < 3; i++ ) {
|
|
||||||
call_running[i] = 1;
|
|
||||||
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 (call_running[0] || call_running[1] || call_running[2]) {
|
|
||||||
pthread_mutex_lock(&muhmutex);
|
|
||||||
|
|
||||||
tox_iterate(bootstrap_node);
|
|
||||||
tox_iterate(caller);
|
|
||||||
tox_iterate(callees[0]);
|
|
||||||
tox_iterate(callees[1]);
|
|
||||||
tox_iterate(callees[2]);
|
|
||||||
|
|
||||||
for ( i = 0; i < 3; i++ )
|
|
||||||
toxav_do(status_control.calls[0].Caller.av);
|
|
||||||
|
|
||||||
toxav_do(status_control.calls[0].Callee.av);
|
|
||||||
toxav_do(status_control.calls[1].Callee.av);
|
|
||||||
toxav_do(status_control.calls[2].Callee.av);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&muhmutex);
|
|
||||||
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
|
END_TEST
|
||||||
|
|
||||||
|
@ -410,8 +229,4 @@ int main(int argc, char *argv[])
|
||||||
srunner_free(test_runner);
|
srunner_free(test_runner);
|
||||||
|
|
||||||
return number_failed;
|
return number_failed;
|
||||||
|
|
||||||
// test_AV_three_calls();
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,13 +70,6 @@
|
||||||
#define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8)
|
#define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8)
|
||||||
|
|
||||||
|
|
||||||
/* Enable/disable tests */
|
|
||||||
#define TEST_REGULAR_AV 0
|
|
||||||
#define TEST_REGULAR_A 0
|
|
||||||
#define TEST_REGULAR_V 0
|
|
||||||
#define TEST_REJECT 0
|
|
||||||
#define TEST_CANCEL 0
|
|
||||||
#define TEST_MUTE_UNMUTE 0
|
|
||||||
#define TEST_TRANSFER_A 0
|
#define TEST_TRANSFER_A 0
|
||||||
#define TEST_TRANSFER_V 1
|
#define TEST_TRANSFER_V 1
|
||||||
|
|
||||||
|
@ -126,7 +119,7 @@ void* pa_write_thread (void* d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks
|
* Callbacks
|
||||||
*/
|
*/
|
||||||
void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
||||||
|
@ -187,21 +180,21 @@ void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
free(rb_write(cc->arb, f));
|
free(rb_write(cc->arb, f));
|
||||||
pthread_mutex_unlock(cc->arb_mutex);
|
pthread_mutex_unlock(cc->arb_mutex);
|
||||||
}
|
}
|
||||||
void t_toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number,
|
void t_toxav_audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number,
|
||||||
bool good, uint32_t bit_rate, void *user_data)
|
bool stable, uint32_t bit_rate, void *user_data)
|
||||||
{
|
{
|
||||||
if (good)
|
if (stable)
|
||||||
printf ("Set new audio bitrate to: %d\n", bit_rate);
|
printf ("Set new audio bit rate to: %d\n", bit_rate);
|
||||||
else
|
else
|
||||||
printf ("The network is overly saturated with audio bitrate at: %d\n", bit_rate);
|
printf ("The network is overly saturated with audio bit rate at: %d\n", bit_rate);
|
||||||
}
|
}
|
||||||
void t_toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number,
|
void t_toxav_video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number,
|
||||||
bool good, uint32_t bit_rate, void *user_data)
|
bool stable, uint32_t bit_rate, void *user_data)
|
||||||
{
|
{
|
||||||
if (good)
|
if (stable)
|
||||||
printf ("Set new video bitrate to: %d", bit_rate);
|
printf ("Set new video bit rate to: %d", bit_rate);
|
||||||
else
|
else
|
||||||
printf ("The network is overly saturated with video bitrate at: %d", bit_rate);
|
printf ("The network is overly saturated with video bit rate at: %d", bit_rate);
|
||||||
}
|
}
|
||||||
void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
|
@ -287,16 +280,16 @@ void initialize_tox(Tox** bootstrap, ToxAV** AliceAV, CallControl* AliceCC, ToxA
|
||||||
toxav_callback_call_state(*AliceAV, t_toxav_call_state_cb, AliceCC);
|
toxav_callback_call_state(*AliceAV, t_toxav_call_state_cb, AliceCC);
|
||||||
toxav_callback_receive_video_frame(*AliceAV, t_toxav_receive_video_frame_cb, AliceCC);
|
toxav_callback_receive_video_frame(*AliceAV, t_toxav_receive_video_frame_cb, AliceCC);
|
||||||
toxav_callback_receive_audio_frame(*AliceAV, t_toxav_receive_audio_frame_cb, AliceCC);
|
toxav_callback_receive_audio_frame(*AliceAV, t_toxav_receive_audio_frame_cb, AliceCC);
|
||||||
toxav_callback_audio_bitrate_control(*AliceAV, t_toxav_audio_bitrate_control_cb, AliceCC);
|
toxav_callback_audio_bit_rate_status(*AliceAV, t_toxav_audio_bit_rate_status_cb, AliceCC);
|
||||||
toxav_callback_video_bitrate_control(*AliceAV, t_toxav_video_bitrate_control_cb, AliceCC);
|
toxav_callback_video_bit_rate_status(*AliceAV, t_toxav_video_bit_rate_status_cb, AliceCC);
|
||||||
|
|
||||||
/* Bob */
|
/* Bob */
|
||||||
toxav_callback_call(*BobAV, t_toxav_call_cb, BobCC);
|
toxav_callback_call(*BobAV, t_toxav_call_cb, BobCC);
|
||||||
toxav_callback_call_state(*BobAV, t_toxav_call_state_cb, BobCC);
|
toxav_callback_call_state(*BobAV, t_toxav_call_state_cb, BobCC);
|
||||||
toxav_callback_receive_video_frame(*BobAV, t_toxav_receive_video_frame_cb, BobCC);
|
toxav_callback_receive_video_frame(*BobAV, t_toxav_receive_video_frame_cb, BobCC);
|
||||||
toxav_callback_receive_audio_frame(*BobAV, t_toxav_receive_audio_frame_cb, BobCC);
|
toxav_callback_receive_audio_frame(*BobAV, t_toxav_receive_audio_frame_cb, BobCC);
|
||||||
toxav_callback_audio_bitrate_control(*BobAV, t_toxav_audio_bitrate_control_cb, BobCC);
|
toxav_callback_audio_bit_rate_status(*BobAV, t_toxav_audio_bit_rate_status_cb, BobCC);
|
||||||
toxav_callback_video_bitrate_control(*BobAV, t_toxav_video_bitrate_control_cb, BobCC);
|
toxav_callback_video_bit_rate_status(*BobAV, t_toxav_video_bit_rate_status_cb, BobCC);
|
||||||
|
|
||||||
|
|
||||||
printf("Created 2 instances of ToxAV\n");
|
printf("Created 2 instances of ToxAV\n");
|
||||||
|
@ -513,232 +506,7 @@ int main (int argc, char** argv)
|
||||||
|
|
||||||
initialize_tox(&bootstrap, &AliceAV, &AliceCC, &BobAV, &BobCC);
|
initialize_tox(&bootstrap, &AliceAV, &AliceCC, &BobAV, &BobCC);
|
||||||
|
|
||||||
#define REGULAR_CALL_FLOW(A_BR, V_BR) \
|
if (TEST_TRANSFER_A) {
|
||||||
do { \
|
|
||||||
memset(&AliceCC, 0, sizeof(CallControl)); \
|
|
||||||
memset(&BobCC, 0, sizeof(CallControl)); \
|
|
||||||
\
|
|
||||||
TOXAV_ERR_CALL rc; \
|
|
||||||
toxav_call(AliceAV, 0, A_BR, V_BR, &rc); \
|
|
||||||
\
|
|
||||||
if (rc != TOXAV_ERR_CALL_OK) { \
|
|
||||||
printf("toxav_call failed: %d\n", rc); \
|
|
||||||
exit(1); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
\
|
|
||||||
long long unsigned int start_time = time(NULL); \
|
|
||||||
\
|
|
||||||
\
|
|
||||||
while (BobCC.state != TOXAV_CALL_STATE_END) { \
|
|
||||||
\
|
|
||||||
if (BobCC.incoming) { \
|
|
||||||
TOXAV_ERR_ANSWER rc; \
|
|
||||||
toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \
|
|
||||||
\
|
|
||||||
if (rc != TOXAV_ERR_ANSWER_OK) { \
|
|
||||||
printf("toxav_answer failed: %d\n", rc); \
|
|
||||||
exit(1); \
|
|
||||||
} \
|
|
||||||
BobCC.incoming = false; \
|
|
||||||
} else { \
|
|
||||||
/* TODO rtp */ \
|
|
||||||
\
|
|
||||||
if (time(NULL) - start_time == 5) { \
|
|
||||||
\
|
|
||||||
TOXAV_ERR_CALL_CONTROL rc; \
|
|
||||||
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \
|
|
||||||
\
|
|
||||||
if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \
|
|
||||||
printf("toxav_call_control failed: %d\n", rc); \
|
|
||||||
exit(1); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV); \
|
|
||||||
} \
|
|
||||||
printf("Success!\n");\
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
if (TEST_REGULAR_AV) {
|
|
||||||
printf("\nTrying regular call (Audio and Video)...\n");
|
|
||||||
REGULAR_CALL_FLOW(48, 4000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TEST_REGULAR_A) {
|
|
||||||
printf("\nTrying regular call (Audio only)...\n");
|
|
||||||
REGULAR_CALL_FLOW(48, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TEST_REGULAR_V) {
|
|
||||||
printf("\nTrying regular call (Video only)...\n");
|
|
||||||
REGULAR_CALL_FLOW(0, 4000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef REGULAR_CALL_FLOW
|
|
||||||
|
|
||||||
if (TEST_REJECT) { /* Alice calls; Bob rejects */
|
|
||||||
printf("\nTrying reject flow...\n");
|
|
||||||
|
|
||||||
memset(&AliceCC, 0, sizeof(CallControl));
|
|
||||||
memset(&BobCC, 0, sizeof(CallControl));
|
|
||||||
|
|
||||||
{
|
|
||||||
TOXAV_ERR_CALL rc;
|
|
||||||
toxav_call(AliceAV, 0, 48, 0, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_CALL_OK) {
|
|
||||||
printf("toxav_call failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!BobCC.incoming)
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
|
|
||||||
/* Reject */
|
|
||||||
{
|
|
||||||
TOXAV_ERR_CALL_CONTROL rc;
|
|
||||||
toxav_call_control(BobAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
|
||||||
printf("toxav_call_control failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (AliceCC.state != TOXAV_CALL_STATE_END)
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
|
|
||||||
printf("Success!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */
|
|
||||||
printf("\nTrying cancel (while ringing) flow...\n");
|
|
||||||
|
|
||||||
memset(&AliceCC, 0, sizeof(CallControl));
|
|
||||||
memset(&BobCC, 0, sizeof(CallControl));
|
|
||||||
|
|
||||||
{
|
|
||||||
TOXAV_ERR_CALL rc;
|
|
||||||
toxav_call(AliceAV, 0, 48, 0, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_CALL_OK) {
|
|
||||||
printf("toxav_call failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!BobCC.incoming)
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
|
|
||||||
/* Cancel */
|
|
||||||
{
|
|
||||||
TOXAV_ERR_CALL_CONTROL rc;
|
|
||||||
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
|
||||||
printf("toxav_call_control failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Alice will not receive end state */
|
|
||||||
while (BobCC.state != TOXAV_CALL_STATE_END)
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
|
|
||||||
printf("Success!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */
|
|
||||||
printf("\nTrying mute functionality...\n");
|
|
||||||
|
|
||||||
memset(&AliceCC, 0, sizeof(CallControl));
|
|
||||||
memset(&BobCC, 0, sizeof(CallControl));
|
|
||||||
|
|
||||||
/* Assume sending audio and video */
|
|
||||||
{
|
|
||||||
TOXAV_ERR_CALL rc;
|
|
||||||
toxav_call(AliceAV, 0, 48, 1000, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_CALL_OK) {
|
|
||||||
printf("toxav_call failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!BobCC.incoming)
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
|
|
||||||
/* At first try all stuff while in invalid state */
|
|
||||||
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
|
|
||||||
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
|
|
||||||
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
|
||||||
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
|
|
||||||
|
|
||||||
{
|
|
||||||
TOXAV_ERR_ANSWER rc;
|
|
||||||
toxav_answer(BobAV, 0, 48, 4000, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_ANSWER_OK) {
|
|
||||||
printf("toxav_answer failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
|
|
||||||
/* Pause and Resume */
|
|
||||||
printf("Pause and Resume\n");
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state == TOXAV_CALL_STATE_PAUSED);
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V));
|
|
||||||
|
|
||||||
/* Mute/Unmute single */
|
|
||||||
printf("Mute/Unmute single\n");
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
|
|
||||||
|
|
||||||
/* Mute/Unmute both */
|
|
||||||
printf("Mute/Unmute both\n");
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V);
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
|
|
||||||
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V);
|
|
||||||
|
|
||||||
{
|
|
||||||
TOXAV_ERR_CALL_CONTROL rc;
|
|
||||||
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
|
||||||
|
|
||||||
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
|
||||||
printf("toxav_call_control failed: %d\n", rc);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iterate_tox(bootstrap, AliceAV, BobAV);
|
|
||||||
assert(BobCC.state == TOXAV_CALL_STATE_END);
|
|
||||||
|
|
||||||
printf("Success!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TEST_TRANSFER_A) { /* Audio encoding/decoding and transfer */
|
|
||||||
SNDFILE* af_handle;
|
SNDFILE* af_handle;
|
||||||
SF_INFO af_info;
|
SF_INFO af_info;
|
||||||
|
|
|
@ -37,25 +37,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
|
||||||
$(PTHREAD_LIBS) \
|
$(PTHREAD_LIBS) \
|
||||||
$(AV_LIBS)
|
$(AV_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#noinst_PROGRAMS += av_test
|
|
||||||
|
|
||||||
#av_test_SOURCES = ../toxav/av_test.c
|
|
||||||
|
|
||||||
#av_test_CFLAGS = $(LIBSODIUM_CFLAGS) \
|
|
||||||
$(NACL_CFLAGS)
|
|
||||||
|
|
||||||
#av_test_LDADD = $(LIBSODIUM_LDFLAGS) \
|
|
||||||
$(NACL_LDFLAGS) \
|
|
||||||
libtoxav.la \
|
|
||||||
libtoxcore.la \
|
|
||||||
$(LIBSODIUM_LIBS) \
|
|
||||||
$(NACL_OBJECTS) \
|
|
||||||
-lopenal \
|
|
||||||
-lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab \
|
|
||||||
-lsndfile \
|
|
||||||
$(NACL_LIBS)
|
|
||||||
|
|
||||||
|
|
||||||
endif
|
endif
|
|
@ -31,14 +31,14 @@ static void jbuf_clear(struct JitterBuffer *q);
|
||||||
static void jbuf_free(struct JitterBuffer *q);
|
static void jbuf_free(struct JitterBuffer *q);
|
||||||
static int jbuf_write(struct JitterBuffer *q, RTPMessage *m);
|
static int jbuf_write(struct JitterBuffer *q, RTPMessage *m);
|
||||||
static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
|
static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
|
||||||
|
OpusEncoder* create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count);
|
||||||
OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count);
|
|
||||||
bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
|
bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
|
||||||
int32_t *old_br, int32_t *old_sr, int32_t *old_ch);
|
int32_t *old_br, int32_t *old_sr, int32_t *old_ch);
|
||||||
bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels);
|
bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels);
|
||||||
|
|
||||||
|
|
||||||
ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data)
|
|
||||||
|
ACSession* ac_new(ToxAV* av, uint32_t friend_number, toxav_receive_audio_frame_cb *cb, void *cb_data)
|
||||||
{
|
{
|
||||||
ACSession *ac = calloc(sizeof(ACSession), 1);
|
ACSession *ac = calloc(sizeof(ACSession), 1);
|
||||||
|
|
||||||
|
@ -78,11 +78,11 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
|
||||||
goto DECODER_CLEANUP;
|
goto DECODER_CLEANUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
ac->last_encoding_bitrate = 48000;
|
ac->last_encoding_bit_rate = 48000;
|
||||||
ac->last_encoding_sampling_rate = 48000;
|
ac->last_encoding_sampling_rate = 48000;
|
||||||
ac->last_encoding_channel_count = 2;
|
ac->last_encoding_channel_count = 2;
|
||||||
|
|
||||||
ac->last_test_encoding_bitrate = 48000;
|
ac->last_test_encoding_bit_rate = 48000;
|
||||||
ac->last_test_encoding_sampling_rate = 48000;
|
ac->last_test_encoding_sampling_rate = 48000;
|
||||||
ac->last_test_encoding_channel_count = 2;
|
ac->last_test_encoding_channel_count = 2;
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
|
||||||
ac->last_packet_channel_count = 1;
|
ac->last_packet_channel_count = 1;
|
||||||
|
|
||||||
ac->av = av;
|
ac->av = av;
|
||||||
ac->friend_id = friend_id;
|
ac->friend_number = friend_number;
|
||||||
ac->acb.first = cb;
|
ac->acb.first = cb;
|
||||||
ac->acb.second = cb_data;
|
ac->acb.second = cb_data;
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ void ac_do(ACSession* ac)
|
||||||
} else if (ac->acb.first) {
|
} else if (ac->acb.first) {
|
||||||
ac->last_packet_frame_duration = (rc * 1000) / ac->last_packet_sampling_rate;
|
ac->last_packet_frame_duration = (rc * 1000) / ac->last_packet_sampling_rate;
|
||||||
|
|
||||||
ac->acb.first(ac->av, ac->friend_id, tmp, rc * ac->last_packet_channel_count,
|
ac->acb.first(ac->av, ac->friend_number, tmp, rc * ac->last_packet_channel_count,
|
||||||
ac->last_packet_channel_count, ac->last_packet_sampling_rate, ac->acb.second);
|
ac->last_packet_channel_count, ac->last_packet_sampling_rate, ac->acb.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,28 +220,27 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels)
|
int ac_reconfigure_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels)
|
||||||
{
|
{
|
||||||
if (!ac || !reconfigure_audio_encoder(&ac->encoder, bitrate, sampling_rate, channels,
|
if (!ac || !reconfigure_audio_encoder(&ac->encoder, bit_rate, sampling_rate, channels,
|
||||||
&ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
&ac->last_encoding_bit_rate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels);
|
LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bit_rate, sampling_rate, channels);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels)
|
int ac_reconfigure_test_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels)
|
||||||
{
|
{
|
||||||
if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bitrate, sampling_rate, channels,
|
if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bit_rate, sampling_rate, channels,
|
||||||
&ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
&ac->last_encoding_bit_rate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
LOGGER_DEBUG ("Reconfigured test audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels);
|
LOGGER_DEBUG ("Reconfigured test audio encoder br: %d sr: %d cc:%d", bit_rate, sampling_rate, channels);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* JITTER BUFFER WORK */
|
|
||||||
struct JitterBuffer {
|
struct JitterBuffer {
|
||||||
RTPMessage **queue;
|
RTPMessage **queue;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
@ -340,7 +339,7 @@ static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success)
|
||||||
*success = 0;
|
*success = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count)
|
OpusEncoder* create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count)
|
||||||
{
|
{
|
||||||
int status = OPUS_OK;
|
int status = OPUS_OK;
|
||||||
OpusEncoder* rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_AUDIO, &status);
|
OpusEncoder* rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_AUDIO, &status);
|
||||||
|
@ -350,7 +349,7 @@ OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bitrate));
|
status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bit_rate));
|
||||||
|
|
||||||
if ( status != OPUS_OK ) {
|
if ( status != OPUS_OK ) {
|
||||||
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
|
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
|
||||||
|
|
|
@ -31,18 +31,21 @@
|
||||||
|
|
||||||
struct RTPMessage_s;
|
struct RTPMessage_s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base Audio Codec session type.
|
||||||
|
*/
|
||||||
typedef struct ACSession_s {
|
typedef struct ACSession_s {
|
||||||
/* encoding */
|
/* encoding */
|
||||||
OpusEncoder *encoder;
|
OpusEncoder *encoder;
|
||||||
int32_t last_encoding_sampling_rate;
|
int32_t last_encoding_sampling_rate;
|
||||||
int32_t last_encoding_channel_count;
|
int32_t last_encoding_channel_count;
|
||||||
int32_t last_encoding_bitrate;
|
int32_t last_encoding_bit_rate;
|
||||||
|
|
||||||
/* Testing encoder for dynamic bitrate streaming */
|
/* Testing encoder for dynamic bit rate streaming */
|
||||||
OpusEncoder *test_encoder;
|
OpusEncoder *test_encoder;
|
||||||
int32_t last_test_encoding_sampling_rate;
|
int32_t last_test_encoding_sampling_rate;
|
||||||
int32_t last_test_encoding_channel_count;
|
int32_t last_test_encoding_channel_count;
|
||||||
int32_t last_test_encoding_bitrate;
|
int32_t last_test_encoding_bit_rate;
|
||||||
|
|
||||||
/* decoding */
|
/* decoding */
|
||||||
OpusDecoder *decoder;
|
OpusDecoder *decoder;
|
||||||
|
@ -57,14 +60,30 @@ typedef struct ACSession_s {
|
||||||
pthread_mutex_t queue_mutex[1];
|
pthread_mutex_t queue_mutex[1];
|
||||||
|
|
||||||
ToxAV* av;
|
ToxAV* av;
|
||||||
uint32_t friend_id;
|
uint32_t friend_number;
|
||||||
PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
|
PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
|
||||||
} ACSession;
|
} ACSession;
|
||||||
|
|
||||||
ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data);
|
/*
|
||||||
|
* Create new Audio Codec session.
|
||||||
|
*/
|
||||||
|
ACSession* ac_new(ToxAV* av, uint32_t friend_number, toxav_receive_audio_frame_cb *cb, void *cb_data);
|
||||||
|
/*
|
||||||
|
* Kill the Audio Codec session.
|
||||||
|
*/
|
||||||
void ac_kill(ACSession* ac);
|
void ac_kill(ACSession* ac);
|
||||||
|
/*
|
||||||
|
* Do periodic work. Work is consisted out of decoding only.
|
||||||
|
*/
|
||||||
void ac_do(ACSession* ac);
|
void ac_do(ACSession* ac);
|
||||||
|
/*
|
||||||
|
* Queue new rtp message.
|
||||||
|
*/
|
||||||
int ac_queue_message(void *acp, struct RTPMessage_s *msg);
|
int ac_queue_message(void *acp, struct RTPMessage_s *msg);
|
||||||
int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels);
|
/*
|
||||||
int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels);
|
* Set new values to the encoders.
|
||||||
|
*/
|
||||||
|
int ac_reconfigure_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels);
|
||||||
|
int ac_reconfigure_test_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels);
|
||||||
|
|
||||||
#endif /* AUDIO_H */
|
#endif /* AUDIO_H */
|
124
toxav/msi.c
124
toxav/msi.c
|
@ -75,37 +75,37 @@ typedef struct {
|
||||||
MSIHeaderRequest request;
|
MSIHeaderRequest request;
|
||||||
MSIHeaderError error;
|
MSIHeaderError error;
|
||||||
MSIHeaderCapabilities capabilities;
|
MSIHeaderCapabilities capabilities;
|
||||||
MSIHeaderVFPSZ vfpsz; /* Video frame piece size. NOTE: Value must be in network b-order */
|
MSIHeaderVFPSZ vfpsz; /* Video frame piece size. NOTE: Value must be in network b-order TODO: get rid of this eventually */
|
||||||
} MSIMessage;
|
} MSIMessage;
|
||||||
|
|
||||||
|
|
||||||
void msg_init (MSIMessage *dest, MSIRequest request);
|
void msg_init (MSIMessage *dest, MSIRequest request);
|
||||||
int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length );
|
int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length );
|
||||||
uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length );
|
uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length );
|
||||||
int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg );
|
int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg );
|
||||||
int send_error ( Messenger* m, uint32_t friend_id, MSIError error );
|
int send_error ( Messenger* m, uint32_t friend_number, MSIError error );
|
||||||
static int invoke_callback(MSICall* call, MSICallbackID cb);
|
static int invoke_callback(MSICall* call, MSICallbackID cb);
|
||||||
static MSICall *get_call ( MSISession *session, uint32_t friend_id );
|
static MSICall *get_call ( MSISession *session, uint32_t friend_number );
|
||||||
MSICall *new_call ( MSISession *session, uint32_t friend_id );
|
MSICall *new_call ( MSISession *session, uint32_t friend_number );
|
||||||
void kill_call ( MSICall *call );
|
void kill_call ( MSICall *call );
|
||||||
void on_peer_status(Messenger *m, uint32_t friend_id, uint8_t status, void *data);
|
void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data);
|
||||||
void handle_push ( MSICall *call, const MSIMessage *msg );
|
void handle_push ( MSICall *call, const MSIMessage *msg );
|
||||||
void handle_pop ( MSICall *call, const MSIMessage *msg );
|
void handle_pop ( MSICall *call, const MSIMessage *msg );
|
||||||
void handle_msi_packet ( Messenger *m, uint32_t friend_id, const uint8_t *data, uint16_t length, void *object );
|
void handle_msi_packet ( Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public functions
|
* Public functions
|
||||||
*/
|
*/
|
||||||
void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
|
void msi_register_callback ( MSISession* session, msi_action_cb* callback, MSICallbackID id)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
session->callbacks[id] = callback;
|
session->callbacks[id] = callback;
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
}
|
}
|
||||||
MSISession *msi_new ( Messenger *messenger )
|
MSISession *msi_new ( Messenger *m )
|
||||||
{
|
{
|
||||||
if (messenger == NULL) {
|
if (m == NULL) {
|
||||||
LOGGER_ERROR("Could not init session on empty messenger!");
|
LOGGER_ERROR("Could not init session on empty messenger!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -123,12 +123,12 @@ MSISession *msi_new ( Messenger *messenger )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
retu->messenger = messenger;
|
retu->messenger = m;
|
||||||
|
|
||||||
m_callback_msi_packet(messenger, handle_msi_packet, retu );
|
m_callback_msi_packet(m, handle_msi_packet, retu );
|
||||||
|
|
||||||
/* This is called when remote terminates session */
|
/* This is called when remote terminates session */
|
||||||
m_callback_connectionstatus_internal_av(messenger, on_peer_status, retu);
|
m_callback_connectionstatus_internal_av(m, on_peer_status, retu);
|
||||||
|
|
||||||
LOGGER_DEBUG("New msi session: %p ", retu);
|
LOGGER_DEBUG("New msi session: %p ", retu);
|
||||||
return retu;
|
return retu;
|
||||||
|
@ -149,7 +149,7 @@ int msi_kill ( MSISession *session )
|
||||||
|
|
||||||
MSICall* it = get_call(session, session->calls_head);
|
MSICall* it = get_call(session, session->calls_head);
|
||||||
for (; it; it = it->next) {
|
for (; it; it = it->next) {
|
||||||
send_message(session->messenger, it->friend_id, &msg);
|
send_message(session->messenger, it->friend_number, &msg);
|
||||||
kill_call(it); /* This will eventually free session->calls */
|
kill_call(it); /* This will eventually free session->calls */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,18 +161,18 @@ int msi_kill ( MSISession *session )
|
||||||
free ( session );
|
free ( session );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
|
int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities )
|
||||||
{
|
{
|
||||||
LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
|
LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_number);
|
||||||
|
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
if (get_call(session, friend_id) != NULL) {
|
if (get_call(session, friend_number) != NULL) {
|
||||||
LOGGER_ERROR("Already in a call");
|
LOGGER_ERROR("Already in a call");
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*call) = new_call ( session, friend_id );
|
(*call) = new_call ( session, friend_number );
|
||||||
|
|
||||||
if ( *call == NULL ) {
|
if ( *call == NULL ) {
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
|
@ -190,7 +190,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
|
||||||
msg.vfpsz.exists = true;
|
msg.vfpsz.exists = true;
|
||||||
msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
|
msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
|
||||||
|
|
||||||
send_message ( (*call)->session->messenger, (*call)->friend_id, &msg );
|
send_message ( (*call)->session->messenger, (*call)->friend_number, &msg );
|
||||||
|
|
||||||
(*call)->state = msi_CallRequesting;
|
(*call)->state = msi_CallRequesting;
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
|
||||||
}
|
}
|
||||||
int msi_hangup ( MSICall* call )
|
int msi_hangup ( MSICall* call )
|
||||||
{
|
{
|
||||||
LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id);
|
LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_number);
|
||||||
|
|
||||||
MSISession* session = call->session;
|
MSISession* session = call->session;
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
|
@ -208,7 +208,7 @@ int msi_hangup ( MSICall* call )
|
||||||
MSIMessage msg;
|
MSIMessage msg;
|
||||||
msg_init(&msg, requ_pop);
|
msg_init(&msg, requ_pop);
|
||||||
|
|
||||||
send_message ( session->messenger, call->friend_id, &msg );
|
send_message ( session->messenger, call->friend_number, &msg );
|
||||||
|
|
||||||
kill_call(call);
|
kill_call(call);
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
|
@ -216,7 +216,7 @@ int msi_hangup ( MSICall* call )
|
||||||
}
|
}
|
||||||
int msi_answer ( MSICall* call, uint8_t capabilities )
|
int msi_answer ( MSICall* call, uint8_t capabilities )
|
||||||
{
|
{
|
||||||
LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
|
LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_number);
|
||||||
|
|
||||||
MSISession* session = call->session;
|
MSISession* session = call->session;
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
|
@ -240,7 +240,7 @@ int msi_answer ( MSICall* call, uint8_t capabilities )
|
||||||
msg.vfpsz.exists = true;
|
msg.vfpsz.exists = true;
|
||||||
msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
|
msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
|
||||||
|
|
||||||
send_message ( session->messenger, call->friend_id, &msg );
|
send_message ( session->messenger, call->friend_number, &msg );
|
||||||
|
|
||||||
call->state = msi_CallActive;
|
call->state = msi_CallActive;
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
|
@ -249,7 +249,7 @@ int msi_answer ( MSICall* call, uint8_t capabilities )
|
||||||
}
|
}
|
||||||
int msi_change_capabilities( MSICall* call, uint8_t capabilities )
|
int msi_change_capabilities( MSICall* call, uint8_t capabilities )
|
||||||
{
|
{
|
||||||
LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id);
|
LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_number);
|
||||||
|
|
||||||
MSISession* session = call->session;
|
MSISession* session = call->session;
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
|
@ -275,7 +275,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities )
|
||||||
msg.capabilities.exists = true;
|
msg.capabilities.exists = true;
|
||||||
msg.capabilities.value = capabilities;
|
msg.capabilities.value = capabilities;
|
||||||
|
|
||||||
send_message ( call->session->messenger, call->friend_id, &msg );
|
send_message ( call->session->messenger, call->friend_number, &msg );
|
||||||
|
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -394,7 +394,7 @@ uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value
|
||||||
|
|
||||||
return dest + value_len; /* Set to next position ready to be written */
|
return dest + value_len; /* Set to next position ready to be written */
|
||||||
}
|
}
|
||||||
int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg )
|
int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg )
|
||||||
{
|
{
|
||||||
/* Parse and send message */
|
/* Parse and send message */
|
||||||
assert(m);
|
assert(m);
|
||||||
|
@ -438,19 +438,19 @@ int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg )
|
||||||
*it = 0;
|
*it = 0;
|
||||||
size ++;
|
size ++;
|
||||||
|
|
||||||
if ( m_msi_packet(m, friend_id, parsed, size) ) {
|
if ( m_msi_packet(m, friend_number, parsed, size) ) {
|
||||||
LOGGER_DEBUG("Sent message");
|
LOGGER_DEBUG("Sent message");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int send_error ( Messenger* m, uint32_t friend_id, MSIError error )
|
int send_error ( Messenger* m, uint32_t friend_number, MSIError error )
|
||||||
{
|
{
|
||||||
/* Send error message */
|
/* Send error message */
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id);
|
LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_number);
|
||||||
|
|
||||||
MSIMessage msg;
|
MSIMessage msg;
|
||||||
msg_init(&msg, requ_pop);
|
msg_init(&msg, requ_pop);
|
||||||
|
@ -458,7 +458,7 @@ int send_error ( Messenger* m, uint32_t friend_id, MSIError error )
|
||||||
msg.error.exists = true;
|
msg.error.exists = true;
|
||||||
msg.error.value = error;
|
msg.error.value = error;
|
||||||
|
|
||||||
send_message ( m, friend_id, &msg );
|
send_message ( m, friend_number, &msg );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int invoke_callback(MSICall* call, MSICallbackID cb)
|
int invoke_callback(MSICall* call, MSICallbackID cb)
|
||||||
|
@ -484,16 +484,16 @@ FAILURE:
|
||||||
call->error = msi_EHandle;
|
call->error = msi_EHandle;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
static MSICall *get_call ( MSISession *session, uint32_t friend_id )
|
static MSICall *get_call ( MSISession *session, uint32_t friend_number )
|
||||||
{
|
{
|
||||||
assert(session);
|
assert(session);
|
||||||
|
|
||||||
if (session->calls == NULL || session->calls_tail < friend_id)
|
if (session->calls == NULL || session->calls_tail < friend_number)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return session->calls[friend_id];
|
return session->calls[friend_number];
|
||||||
}
|
}
|
||||||
MSICall *new_call ( MSISession *session, uint32_t friend_id )
|
MSICall *new_call ( MSISession *session, uint32_t friend_number )
|
||||||
{
|
{
|
||||||
assert(session);
|
assert(session);
|
||||||
|
|
||||||
|
@ -503,20 +503,20 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
rc->session = session;
|
rc->session = session;
|
||||||
rc->friend_id = friend_id;
|
rc->friend_number = friend_number;
|
||||||
|
|
||||||
if (session->calls == NULL) { /* Creating */
|
if (session->calls == NULL) { /* Creating */
|
||||||
session->calls = calloc (sizeof(MSICall*), friend_id + 1);
|
session->calls = calloc (sizeof(MSICall*), friend_number + 1);
|
||||||
|
|
||||||
if (session->calls == NULL) {
|
if (session->calls == NULL) {
|
||||||
free(rc);
|
free(rc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
session->calls_tail = session->calls_head = friend_id;
|
session->calls_tail = session->calls_head = friend_number;
|
||||||
|
|
||||||
} else if (session->calls_tail < friend_id) { /* Appending */
|
} else if (session->calls_tail < friend_number) { /* Appending */
|
||||||
void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_id + 1);
|
void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_number + 1);
|
||||||
|
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
free(rc);
|
free(rc);
|
||||||
|
@ -526,22 +526,22 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
|
||||||
session->calls = tmp;
|
session->calls = tmp;
|
||||||
|
|
||||||
/* Set fields in between to null */
|
/* Set fields in between to null */
|
||||||
int32_t i = session->calls_tail;
|
int32_t i = session->calls_tail + 1;
|
||||||
for (; i < friend_id; i ++)
|
for (; i < friend_number; i ++)
|
||||||
session->calls[i] = NULL;
|
session->calls[i] = NULL;
|
||||||
|
|
||||||
rc->prev = session->calls[session->calls_tail];
|
rc->prev = session->calls[session->calls_tail];
|
||||||
session->calls[session->calls_tail]->next = rc;
|
session->calls[session->calls_tail]->next = rc;
|
||||||
|
|
||||||
session->calls_tail = friend_id;
|
session->calls_tail = friend_number;
|
||||||
|
|
||||||
} else if (session->calls_head > friend_id) { /* Inserting at front */
|
} else if (session->calls_head > friend_number) { /* Inserting at front */
|
||||||
rc->next = session->calls[session->calls_head];
|
rc->next = session->calls[session->calls_head];
|
||||||
session->calls[session->calls_head]->prev = rc;
|
session->calls[session->calls_head]->prev = rc;
|
||||||
session->calls_head = friend_id;
|
session->calls_head = friend_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
session->calls[friend_id] = rc;
|
session->calls[friend_number] = rc;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
void kill_call ( MSICall *call )
|
void kill_call ( MSICall *call )
|
||||||
|
@ -560,16 +560,16 @@ void kill_call ( MSICall *call )
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
else if (next)
|
else if (next)
|
||||||
session->calls_head = next->friend_id;
|
session->calls_head = next->friend_number;
|
||||||
else goto CLEAR_CONTAINER;
|
else goto CLEAR_CONTAINER;
|
||||||
|
|
||||||
if (next)
|
if (next)
|
||||||
next->prev = prev;
|
next->prev = prev;
|
||||||
else if (prev)
|
else if (prev)
|
||||||
session->calls_tail = prev->friend_id;
|
session->calls_tail = prev->friend_number;
|
||||||
else goto CLEAR_CONTAINER;
|
else goto CLEAR_CONTAINER;
|
||||||
|
|
||||||
session->calls[call->friend_id] = NULL;
|
session->calls[call->friend_number] = NULL;
|
||||||
free(call);
|
free(call);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -579,17 +579,17 @@ CLEAR_CONTAINER:
|
||||||
free(call);
|
free(call);
|
||||||
session->calls = NULL;
|
session->calls = NULL;
|
||||||
}
|
}
|
||||||
void on_peer_status(Messenger* m, uint32_t friend_id, uint8_t status, void* data)
|
void on_peer_status(Messenger* m, uint32_t friend_number, uint8_t status, void* data)
|
||||||
{
|
{
|
||||||
(void)m;
|
(void)m;
|
||||||
MSISession *session = data;
|
MSISession *session = data;
|
||||||
|
|
||||||
switch ( status ) {
|
switch ( status ) {
|
||||||
case 0: { /* Friend is now offline */
|
case 0: { /* Friend is now offline */
|
||||||
LOGGER_DEBUG("Friend %d is now offline", friend_id);
|
LOGGER_DEBUG("Friend %d is now offline", friend_number);
|
||||||
|
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
MSICall* call = get_call(session, friend_id);
|
MSICall* call = get_call(session, friend_number);
|
||||||
|
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
|
@ -610,9 +610,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
|
||||||
{
|
{
|
||||||
assert(call);
|
assert(call);
|
||||||
|
|
||||||
MSISession* session = call->session;
|
LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_number);
|
||||||
|
|
||||||
LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_id);
|
|
||||||
|
|
||||||
if (!msg->capabilities.exists) {
|
if (!msg->capabilities.exists) {
|
||||||
LOGGER_WARNING("Session: %p Invalid capabilities on 'push'");
|
LOGGER_WARNING("Session: %p Invalid capabilities on 'push'");
|
||||||
|
@ -670,7 +668,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
|
||||||
msg.vfpsz.exists = true;
|
msg.vfpsz.exists = true;
|
||||||
msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
|
msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
|
||||||
|
|
||||||
send_message ( call->session->messenger, call->friend_id, &msg );
|
send_message ( call->session->messenger, call->friend_number, &msg );
|
||||||
|
|
||||||
/* If peer changed capabilities during re-call they will
|
/* If peer changed capabilities during re-call they will
|
||||||
* be handled accordingly during the next step
|
* be handled accordingly during the next step
|
||||||
|
@ -708,14 +706,14 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FAILURE:
|
FAILURE:
|
||||||
send_error(call->session->messenger, call->friend_id, call->error);
|
send_error(call->session->messenger, call->friend_number, call->error);
|
||||||
kill_call(call);
|
kill_call(call);
|
||||||
}
|
}
|
||||||
void handle_pop ( MSICall *call, const MSIMessage *msg )
|
void handle_pop ( MSICall *call, const MSIMessage *msg )
|
||||||
{
|
{
|
||||||
assert(call);
|
assert(call);
|
||||||
|
|
||||||
LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id);
|
LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_number);
|
||||||
|
|
||||||
/* callback errors are ignored */
|
/* callback errors are ignored */
|
||||||
|
|
||||||
|
@ -751,7 +749,7 @@ void handle_pop ( MSICall *call, const MSIMessage *msg )
|
||||||
|
|
||||||
kill_call ( call );
|
kill_call ( call );
|
||||||
}
|
}
|
||||||
void handle_msi_packet ( Messenger* m, uint32_t friend_id, const uint8_t* data, uint16_t length, void* object )
|
void handle_msi_packet ( Messenger* m, uint32_t friend_number, const uint8_t* data, uint16_t length, void* object )
|
||||||
{
|
{
|
||||||
LOGGER_DEBUG("Got msi message");
|
LOGGER_DEBUG("Got msi message");
|
||||||
|
|
||||||
|
@ -760,25 +758,25 @@ void handle_msi_packet ( Messenger* m, uint32_t friend_id, const uint8_t* data,
|
||||||
|
|
||||||
if ( msg_parse_in ( &msg, data, length ) == -1 ) {
|
if ( msg_parse_in ( &msg, data, length ) == -1 ) {
|
||||||
LOGGER_WARNING("Error parsing message");
|
LOGGER_WARNING("Error parsing message");
|
||||||
send_error(m, friend_id, msi_EInvalidMessage);
|
send_error(m, friend_number, msi_EInvalidMessage);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
LOGGER_DEBUG("Successfully parsed message");
|
LOGGER_DEBUG("Successfully parsed message");
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(session->mutex);
|
pthread_mutex_lock(session->mutex);
|
||||||
MSICall *call = get_call(session, friend_id);
|
MSICall *call = get_call(session, friend_number);
|
||||||
|
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
if (msg.request.value != requ_push) {
|
if (msg.request.value != requ_push) {
|
||||||
send_error(m, friend_id, msi_EStrayMessage);
|
send_error(m, friend_number, msi_EStrayMessage);
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
call = new_call(session, friend_id);
|
call = new_call(session, friend_number);
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
send_error(m, friend_id, msi_ESystem);
|
send_error(m, friend_number, msi_ESystem);
|
||||||
pthread_mutex_unlock(session->mutex);
|
pthread_mutex_unlock(session->mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
24
toxav/msi.h
24
toxav/msi.h
|
@ -89,7 +89,7 @@ typedef struct MSICall_s {
|
||||||
uint8_t peer_capabilities; /* Peer capabilities */
|
uint8_t peer_capabilities; /* Peer capabilities */
|
||||||
uint8_t self_capabilities; /* Self capabilities */
|
uint8_t self_capabilities; /* Self capabilities */
|
||||||
uint16_t peer_vfpsz; /* Video frame piece size */
|
uint16_t peer_vfpsz; /* Video frame piece size */
|
||||||
uint32_t friend_id; /* Index of this call in MSISession */
|
uint32_t friend_number; /* Index of this call in MSISession */
|
||||||
MSIError error; /* Last error */
|
MSIError error; /* Last error */
|
||||||
|
|
||||||
void* av_call; /* Pointer to av call handler */
|
void* av_call; /* Pointer to av call handler */
|
||||||
|
@ -100,12 +100,11 @@ typedef struct MSICall_s {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Msi callback type. 'agent' is a pointer to ToxAv.
|
|
||||||
* Expected return on success is 0, if any other number is
|
* Expected return on success is 0, if any other number is
|
||||||
* returned the call is considered errored and will be handled
|
* returned the call is considered errored and will be handled
|
||||||
* as such which means it will be terminated without any notice.
|
* as such which means it will be terminated without any notice.
|
||||||
*/
|
*/
|
||||||
typedef int ( *MSICallbackType ) ( void *agent, MSICall* call);
|
typedef int msi_action_cb ( void *av, MSICall* call);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Control session struct. Please do not modify outside msi.c
|
* Control session struct. Please do not modify outside msi.c
|
||||||
|
@ -119,43 +118,34 @@ typedef struct MSISession_s {
|
||||||
void *av;
|
void *av;
|
||||||
Messenger *messenger;
|
Messenger *messenger;
|
||||||
|
|
||||||
/* The mutex controls async access from control
|
|
||||||
* thread(s) and core thread.
|
|
||||||
*/
|
|
||||||
pthread_mutex_t mutex[1];
|
pthread_mutex_t mutex[1];
|
||||||
MSICallbackType callbacks[7];
|
msi_action_cb* callbacks[7];
|
||||||
} MSISession;
|
} MSISession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the control session.
|
* Start the control session.
|
||||||
*/
|
*/
|
||||||
MSISession *msi_new ( Messenger *messenger );
|
MSISession *msi_new ( Messenger *m );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate control session. NOTE: all calls will be freed
|
* Terminate control session. NOTE: all calls will be freed
|
||||||
*/
|
*/
|
||||||
int msi_kill ( MSISession *session );
|
int msi_kill ( MSISession *session );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback setter.
|
* Callback setter.
|
||||||
*/
|
*/
|
||||||
void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id);
|
void msi_register_callback(MSISession *session, msi_action_cb* callback, MSICallbackID id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send invite request to friend_id.
|
* Send invite request to friend_number.
|
||||||
*/
|
*/
|
||||||
int msi_invite ( MSISession* session, MSICall** call, uint32_t friend_id, uint8_t capabilities );
|
int msi_invite ( MSISession* session, MSICall** call, uint32_t friend_number, uint8_t capabilities );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hangup call. NOTE: 'call' will be freed
|
* Hangup call. NOTE: 'call' will be freed
|
||||||
*/
|
*/
|
||||||
int msi_hangup ( MSICall* call );
|
int msi_hangup ( MSICall* call );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Answer call request.
|
* Answer call request.
|
||||||
*/
|
*/
|
||||||
int msi_answer ( MSICall* call, uint8_t capabilities );
|
int msi_answer ( MSICall* call, uint8_t capabilities );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change capabilities of the call.
|
* Change capabilities of the call.
|
||||||
*/
|
*/
|
||||||
|
|
67
toxav/rtp.c
67
toxav/rtp.c
|
@ -78,11 +78,11 @@ int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *dat
|
||||||
void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
|
void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
|
||||||
|
|
||||||
|
|
||||||
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) )
|
RTPSession *rtp_new ( int payload_type, Messenger *m, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) )
|
||||||
{
|
{
|
||||||
assert(mcb);
|
assert(mcb);
|
||||||
assert(cs);
|
assert(cs);
|
||||||
assert(messenger);
|
assert(m);
|
||||||
|
|
||||||
RTPSession *retu = calloc(1, sizeof(RTPSession));
|
RTPSession *retu = calloc(1, sizeof(RTPSession));
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, vo
|
||||||
retu->ssrc = random_int();
|
retu->ssrc = random_int();
|
||||||
retu->payload_type = payload_type % 128;
|
retu->payload_type = payload_type % 128;
|
||||||
|
|
||||||
retu->m = messenger;
|
retu->m = m;
|
||||||
retu->friend_id = friend_num;
|
retu->friend_number = friend_num;
|
||||||
|
|
||||||
if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) {
|
if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) {
|
||||||
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
||||||
|
@ -161,7 +161,7 @@ int rtp_do(RTPSession *session)
|
||||||
return rtp_StateNormal;
|
return rtp_StateNormal;
|
||||||
|
|
||||||
if (current_time_monotonic() - session->rtcp_session->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) {
|
if (current_time_monotonic() - session->rtcp_session->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) {
|
||||||
send_rtcp_report(session->rtcp_session, session->m, session->friend_id);
|
send_rtcp_report(session->rtcp_session, session->m, session->friend_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rb_full(session->rtcp_session->pl_stats)) {
|
if (rb_full(session->rtcp_session->pl_stats)) {
|
||||||
|
@ -209,15 +209,15 @@ int rtp_start_receiving(RTPSession* session)
|
||||||
if (session == NULL)
|
if (session == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (m_callback_rtp_packet(session->m, session->friend_id, session->prefix,
|
if (m_callback_rtp_packet(session->m, session->friend_number, session->prefix,
|
||||||
handle_rtp_packet, session) == -1) {
|
handle_rtp_packet, session) == -1) {
|
||||||
LOGGER_WARNING("Failed to register rtp receive handler");
|
LOGGER_WARNING("Failed to register rtp receive handler");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (m_callback_rtp_packet(session->m, session->friend_id, session->rtcp_session->prefix,
|
if (m_callback_rtp_packet(session->m, session->friend_number, session->rtcp_session->prefix,
|
||||||
handle_rtcp_packet, session->rtcp_session) == -1) {
|
handle_rtcp_packet, session->rtcp_session) == -1) {
|
||||||
LOGGER_WARNING("Failed to register rtcp receive handler");
|
LOGGER_WARNING("Failed to register rtcp receive handler");
|
||||||
m_callback_rtp_packet(session->m, session->friend_id, session->prefix, NULL, NULL);
|
m_callback_rtp_packet(session->m, session->friend_number, session->prefix, NULL, NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,8 +228,8 @@ int rtp_stop_receiving(RTPSession* session)
|
||||||
if (session == NULL)
|
if (session == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
m_callback_rtp_packet(session->m, session->friend_id, session->prefix, NULL, NULL);
|
m_callback_rtp_packet(session->m, session->friend_number, session->prefix, NULL, NULL);
|
||||||
m_callback_rtp_packet(session->m, session->friend_id, session->rtcp_session->prefix, NULL, NULL); /* RTCP */
|
m_callback_rtp_packet(session->m, session->friend_number, session->rtcp_session->prefix, NULL, NULL); /* RTCP */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,8 @@ int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, b
|
||||||
uint8_t parsed[MAX_RTP_SIZE];
|
uint8_t parsed[MAX_RTP_SIZE];
|
||||||
uint8_t *it;
|
uint8_t *it;
|
||||||
|
|
||||||
RTPHeader header[1];
|
RTPHeader header[1] = {0};
|
||||||
|
|
||||||
ADD_FLAG_VERSION ( header, session->version );
|
ADD_FLAG_VERSION ( header, session->version );
|
||||||
ADD_FLAG_PADDING ( header, session->padding );
|
ADD_FLAG_PADDING ( header, session->padding );
|
||||||
ADD_FLAG_EXTENSION ( header, session->extension );
|
ADD_FLAG_EXTENSION ( header, session->extension );
|
||||||
|
@ -278,12 +279,11 @@ int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, b
|
||||||
|
|
||||||
memcpy(it, data, length);
|
memcpy(it, data, length);
|
||||||
|
|
||||||
if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) {
|
if ( -1 == send_custom_lossy_packet(session->m, session->friend_number, parsed, parsed_len) ) {
|
||||||
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
|
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set sequ number */
|
|
||||||
session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
|
session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,6 @@ void rtp_free_msg ( RTPMessage *msg )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
||||||
{
|
{
|
||||||
if ( !payload || !length ) {
|
if ( !payload || !length ) {
|
||||||
|
@ -322,12 +321,7 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
||||||
|
|
||||||
retu->flags = *it;
|
retu->flags = *it;
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
/* This indicates if the first 2 bits are valid.
|
|
||||||
* Now it may happen that this is out of order but
|
|
||||||
* it cuts down chances of parsing some invalid value
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) {
|
if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) {
|
||||||
/* Deallocate */
|
/* Deallocate */
|
||||||
LOGGER_WARNING("Invalid version!");
|
LOGGER_WARNING("Invalid version!");
|
||||||
|
@ -335,15 +329,10 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Added a check for the size of the header little sooner so
|
|
||||||
* I don't need to parse the other stuff if it's bad
|
|
||||||
*/
|
|
||||||
uint8_t cc = GET_FLAG_CSRCC ( retu );
|
uint8_t cc = GET_FLAG_CSRCC ( retu );
|
||||||
int total = 12 /* Minimum header len */ + ( cc * 4 );
|
int total = 12 /* Minimum header len */ + ( cc * 4 );
|
||||||
|
|
||||||
if ( length < total ) {
|
if ( length < total ) {
|
||||||
/* Deallocate */
|
|
||||||
LOGGER_WARNING("Length invalid!");
|
LOGGER_WARNING("Length invalid!");
|
||||||
free(retu);
|
free(retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -355,9 +344,10 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
||||||
|
|
||||||
|
|
||||||
memcpy(&retu->timestamp, it, sizeof(retu->timestamp));
|
memcpy(&retu->timestamp, it, sizeof(retu->timestamp));
|
||||||
retu->timestamp = ntohl(retu->timestamp);
|
|
||||||
it += 4;
|
it += 4;
|
||||||
memcpy(&retu->ssrc, it, sizeof(retu->ssrc));
|
memcpy(&retu->ssrc, it, sizeof(retu->ssrc));
|
||||||
|
|
||||||
|
retu->timestamp = ntohl(retu->timestamp);
|
||||||
retu->ssrc = ntohl(retu->ssrc);
|
retu->ssrc = ntohl(retu->ssrc);
|
||||||
|
|
||||||
uint8_t x;
|
uint8_t x;
|
||||||
|
@ -380,34 +370,31 @@ RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ext_length;
|
memcpy(&retu->length, it, sizeof(retu->length));
|
||||||
memcpy(&ext_length, it, sizeof(ext_length));
|
retu->length = ntohs(retu->length);
|
||||||
ext_length = ntohs(ext_length);
|
|
||||||
it += 2;
|
it += 2;
|
||||||
|
|
||||||
|
if ( length < ( retu->length * sizeof(uint32_t) ) ) {
|
||||||
if ( length < ( ext_length * sizeof(uint32_t) ) ) {
|
|
||||||
LOGGER_WARNING("Length invalid!");
|
LOGGER_WARNING("Length invalid!");
|
||||||
free(retu);
|
free(retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
retu->length = ext_length;
|
|
||||||
memcpy(&retu->type, it, sizeof(retu->type));
|
memcpy(&retu->type, it, sizeof(retu->type));
|
||||||
retu->type = ntohs(retu->type);
|
retu->type = ntohs(retu->type);
|
||||||
|
|
||||||
it += 2;
|
it += 2;
|
||||||
|
|
||||||
if ( !(retu->table = calloc(ext_length, sizeof (uint32_t))) ) {
|
if ( !(retu->table = calloc(retu->length, sizeof (uint32_t))) ) {
|
||||||
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
||||||
free(retu);
|
free(retu);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
|
for ( x = 0; x < retu->length; x++ ) {
|
||||||
for ( x = 0; x < ext_length; x++ ) {
|
|
||||||
it += 4;
|
it += 4;
|
||||||
memcpy(&(retu->table[x]), it, sizeof(retu->table[x]));
|
memcpy(retu->table + x, it, sizeof(*retu->table));
|
||||||
retu->table[x] = ntohl(retu->table[x]);
|
retu->table[x] = ntohl(retu->table[x]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +420,6 @@ uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload )
|
||||||
*it = header->marker_payloadt;
|
*it = header->marker_payloadt;
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
|
|
||||||
timestamp = htonl(header->timestamp);
|
timestamp = htonl(header->timestamp);
|
||||||
memcpy(it, ×tamp, sizeof(timestamp));
|
memcpy(it, ×tamp, sizeof(timestamp));
|
||||||
it += 4;
|
it += 4;
|
||||||
|
@ -579,7 +565,6 @@ int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* dat
|
||||||
report->received_packets = ntohl(report->received_packets);
|
report->received_packets = ntohl(report->received_packets);
|
||||||
report->expected_packets = ntohl(report->expected_packets);
|
report->expected_packets = ntohl(report->expected_packets);
|
||||||
|
|
||||||
/* Invalid values */
|
|
||||||
if (report->expected_packets == 0 || report->received_packets > report->expected_packets) {
|
if (report->expected_packets == 0 || report->received_packets > report->expected_packets) {
|
||||||
LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets);
|
LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets);
|
||||||
free(report);
|
free(report);
|
||||||
|
|
11
toxav/rtp.h
11
toxav/rtp.h
|
@ -113,10 +113,9 @@ typedef struct {
|
||||||
uint8_t prefix;
|
uint8_t prefix;
|
||||||
|
|
||||||
Messenger *m;
|
Messenger *m;
|
||||||
int friend_id;
|
int friend_number;
|
||||||
struct RTCPSession_s *rtcp_session;
|
struct RTCPSession_s *rtcp_session;
|
||||||
|
|
||||||
|
|
||||||
void *cs;
|
void *cs;
|
||||||
int (*mcb) (void*, RTPMessage* msg);
|
int (*mcb) (void*, RTPMessage* msg);
|
||||||
|
|
||||||
|
@ -125,33 +124,27 @@ typedef struct {
|
||||||
/**
|
/**
|
||||||
* Must be called before calling any other rtp function.
|
* Must be called before calling any other rtp function.
|
||||||
*/
|
*/
|
||||||
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) );
|
RTPSession *rtp_new ( int payload_type, Messenger *m, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate the session.
|
* Terminate the session.
|
||||||
*/
|
*/
|
||||||
void rtp_kill ( RTPSession* session );
|
void rtp_kill ( RTPSession* session );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do periodical rtp work.
|
* Do periodical rtp work.
|
||||||
*/
|
*/
|
||||||
int rtp_do(RTPSession *session);
|
int rtp_do(RTPSession *session);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default rtp is in receiving state
|
* By default rtp is in receiving state
|
||||||
*/
|
*/
|
||||||
int rtp_start_receiving (RTPSession *session);
|
int rtp_start_receiving (RTPSession *session);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause rtp receiving mode.
|
* Pause rtp receiving mode.
|
||||||
*/
|
*/
|
||||||
int rtp_stop_receiving (RTPSession *session);
|
int rtp_stop_receiving (RTPSession *session);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends msg to RTPSession::dest
|
* Sends msg to RTPSession::dest
|
||||||
*/
|
*/
|
||||||
int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy );
|
int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dealloc msg.
|
* Dealloc msg.
|
||||||
*/
|
*/
|
||||||
|
|
132
toxav/toxav.c
132
toxav/toxav.c
|
@ -58,10 +58,10 @@ typedef struct ToxAVCall_s {
|
||||||
|
|
||||||
bool active;
|
bool active;
|
||||||
MSICall* msi_call;
|
MSICall* msi_call;
|
||||||
uint32_t friend_id;
|
uint32_t friend_number;
|
||||||
|
|
||||||
uint32_t audio_bit_rate; /* Sending audio bitrate */
|
uint32_t audio_bit_rate; /* Sending audio bit rate */
|
||||||
uint32_t video_bit_rate; /* Sending video bitrate */
|
uint32_t video_bit_rate; /* Sending video bit rate */
|
||||||
|
|
||||||
ToxAvBitrateAdapter aba;
|
ToxAvBitrateAdapter aba;
|
||||||
ToxAvBitrateAdapter vba;
|
ToxAvBitrateAdapter vba;
|
||||||
|
@ -93,8 +93,8 @@ struct toxAV {
|
||||||
PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */
|
PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */
|
||||||
PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
|
PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
|
||||||
PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
|
PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
|
||||||
PAIR(toxav_audio_bitrate_control_cb *, void *) abcb; /* Audio bitrate control callback */
|
PAIR(toxav_audio_bit_rate_status_cb *, void *) abcb; /* Audio bit rate control callback */
|
||||||
PAIR(toxav_video_bitrate_control_cb *, void *) vbcb; /* Video bitrate control callback */
|
PAIR(toxav_video_bit_rate_status_cb *, void *) vbcb; /* Video bit rate control callback */
|
||||||
|
|
||||||
/** Decode time measures */
|
/** Decode time measures */
|
||||||
int32_t dmssc; /** Measure count */
|
int32_t dmssc; /** Measure count */
|
||||||
|
@ -111,8 +111,8 @@ int callback_end(void* toxav_inst, MSICall* call);
|
||||||
int callback_error(void* toxav_inst, MSICall* call);
|
int callback_error(void* toxav_inst, MSICall* call);
|
||||||
int callback_capabilites(void* toxav_inst, MSICall* call);
|
int callback_capabilites(void* toxav_inst, MSICall* call);
|
||||||
|
|
||||||
bool audio_bitrate_invalid(uint32_t bitrate);
|
bool audio_bit_rate_invalid(uint32_t bit_rate);
|
||||||
bool video_bitrate_invalid(uint32_t bitrate);
|
bool video_bit_rate_invalid(uint32_t bit_rate);
|
||||||
void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
|
void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
|
||||||
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
|
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
|
||||||
ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
|
ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
|
||||||
|
@ -129,12 +129,12 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
||||||
|
|
||||||
if (tox == NULL) {
|
if (tox == NULL) {
|
||||||
rc = TOXAV_ERR_NEW_NULL;
|
rc = TOXAV_ERR_NEW_NULL;
|
||||||
goto FAILURE;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((Messenger*)tox)->msi_packet) {
|
if (((Messenger*)tox)->msi_packet) {
|
||||||
rc = TOXAV_ERR_NEW_MULTIPLE;
|
rc = TOXAV_ERR_NEW_MULTIPLE;
|
||||||
goto FAILURE;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
av = calloc (sizeof(ToxAV), 1);
|
av = calloc (sizeof(ToxAV), 1);
|
||||||
|
@ -142,13 +142,13 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
||||||
if (av == NULL) {
|
if (av == NULL) {
|
||||||
LOGGER_WARNING("Allocation failed!");
|
LOGGER_WARNING("Allocation failed!");
|
||||||
rc = TOXAV_ERR_NEW_MALLOC;
|
rc = TOXAV_ERR_NEW_MALLOC;
|
||||||
goto FAILURE;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_recursive_mutex(av->mutex) != 0) {
|
if (create_recursive_mutex(av->mutex) != 0) {
|
||||||
LOGGER_WARNING("Mutex creation failed!");
|
LOGGER_WARNING("Mutex creation failed!");
|
||||||
rc = TOXAV_ERR_NEW_MALLOC;
|
rc = TOXAV_ERR_NEW_MALLOC;
|
||||||
goto FAILURE;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
av->m = (Messenger *)tox;
|
av->m = (Messenger *)tox;
|
||||||
|
@ -157,7 +157,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
||||||
if (av->msi == NULL) {
|
if (av->msi == NULL) {
|
||||||
pthread_mutex_destroy(av->mutex);
|
pthread_mutex_destroy(av->mutex);
|
||||||
rc = TOXAV_ERR_NEW_MALLOC;
|
rc = TOXAV_ERR_NEW_MALLOC;
|
||||||
goto FAILURE;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
av->interval = 200;
|
av->interval = 200;
|
||||||
|
@ -170,19 +170,16 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
||||||
msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout);
|
msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout);
|
||||||
msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities);
|
msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities);
|
||||||
|
|
||||||
|
END:
|
||||||
if (error)
|
if (error)
|
||||||
*error = rc;
|
*error = rc;
|
||||||
|
|
||||||
|
if (rc != TOXAV_ERR_NEW_OK) {
|
||||||
|
free(av);
|
||||||
|
av = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return av;
|
return av;
|
||||||
|
|
||||||
FAILURE:
|
|
||||||
if (error)
|
|
||||||
*error = rc;
|
|
||||||
|
|
||||||
free(av);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void toxav_kill(ToxAV* av)
|
void toxav_kill(ToxAV* av)
|
||||||
|
@ -249,14 +246,14 @@ void toxav_iterate(ToxAV* av)
|
||||||
|
|
||||||
/* Notify app */
|
/* Notify app */
|
||||||
if (av->abcb.first)
|
if (av->abcb.first)
|
||||||
av->abcb.first (av, i->friend_id, false, bb, av->abcb.second);
|
av->abcb.first (av, i->friend_number, false, bb, av->abcb.second);
|
||||||
} else if (i->aba.active && i->aba.end_time < current_time_monotonic()) {
|
} else if (i->aba.active && i->aba.end_time < current_time_monotonic()) {
|
||||||
|
|
||||||
i->audio_bit_rate = i->aba.bit_rate;
|
i->audio_bit_rate = i->aba.bit_rate;
|
||||||
|
|
||||||
/* Notify user about the new bitrate */
|
/* Notify user about the new bit rate */
|
||||||
if (av->abcb.first)
|
if (av->abcb.first)
|
||||||
av->abcb.first (av, i->friend_id, true, i->aba.bit_rate, av->abcb.second);
|
av->abcb.first (av, i->friend_number, true, i->aba.bit_rate, av->abcb.second);
|
||||||
|
|
||||||
/* Stop sending dummy packets */
|
/* Stop sending dummy packets */
|
||||||
memset(&i->aba, 0, sizeof(i->aba));
|
memset(&i->aba, 0, sizeof(i->aba));
|
||||||
|
@ -275,15 +272,15 @@ void toxav_iterate(ToxAV* av)
|
||||||
|
|
||||||
/* Notify app */
|
/* Notify app */
|
||||||
if (av->vbcb.first)
|
if (av->vbcb.first)
|
||||||
av->vbcb.first (av, i->friend_id, false, bb, av->vbcb.second);
|
av->vbcb.first (av, i->friend_number, false, bb, av->vbcb.second);
|
||||||
|
|
||||||
} else if (i->vba.active && i->vba.end_time < current_time_monotonic()) {
|
} else if (i->vba.active && i->vba.end_time < current_time_monotonic()) {
|
||||||
|
|
||||||
i->video_bit_rate = i->vba.bit_rate;
|
i->video_bit_rate = i->vba.bit_rate;
|
||||||
|
|
||||||
/* Notify user about the new bitrate */
|
/* Notify user about the new bit rate */
|
||||||
if (av->vbcb.first)
|
if (av->vbcb.first)
|
||||||
av->vbcb.first (av, i->friend_id, true, i->vba.bit_rate, av->vbcb.second);
|
av->vbcb.first (av, i->friend_number, true, i->vba.bit_rate, av->vbcb.second);
|
||||||
|
|
||||||
/* Stop sending dummy packets */
|
/* Stop sending dummy packets */
|
||||||
memset(&i->vba, 0, sizeof(i->vba));
|
memset(&i->vba, 0, sizeof(i->vba));
|
||||||
|
@ -297,7 +294,7 @@ void toxav_iterate(ToxAV* av)
|
||||||
i->msi_call->peer_capabilities & msi_CapSVideo)
|
i->msi_call->peer_capabilities & msi_CapSVideo)
|
||||||
rc = MIN(i->video.second->lcfd, rc);
|
rc = MIN(i->video.second->lcfd, rc);
|
||||||
|
|
||||||
uint32_t fid = i->friend_id;
|
uint32_t fid = i->friend_number;
|
||||||
|
|
||||||
pthread_mutex_unlock(i->mutex);
|
pthread_mutex_unlock(i->mutex);
|
||||||
pthread_mutex_lock(av->mutex);
|
pthread_mutex_lock(av->mutex);
|
||||||
|
@ -356,7 +353,7 @@ void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data)
|
||||||
av->ccb.first = function;
|
av->ccb.first = function;
|
||||||
av->ccb.second = user_data;
|
av->ccb.second = user_data;
|
||||||
pthread_mutex_unlock(av->mutex);
|
pthread_mutex_unlock(av->mutex);
|
||||||
}/** Required for monitoring */
|
}
|
||||||
|
|
||||||
bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error)
|
bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error)
|
||||||
{
|
{
|
||||||
|
@ -368,8 +365,8 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((audio_bit_rate && audio_bitrate_invalid(audio_bit_rate))
|
if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))
|
||||||
||(video_bit_rate && video_bitrate_invalid(video_bit_rate))
|
||(video_bit_rate && video_bit_rate_invalid(video_bit_rate))
|
||||||
) {
|
) {
|
||||||
rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
|
rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
|
||||||
goto END;
|
goto END;
|
||||||
|
@ -561,7 +558,7 @@ END:
|
||||||
return rc == TOXAV_ERR_CALL_CONTROL_OK;
|
return rc == TOXAV_ERR_CALL_CONTROL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toxav_callback_video_bitrate_control(ToxAV* av, toxav_video_bitrate_control_cb* function, void* user_data)
|
void toxav_callback_video_bit_rate_status(ToxAV* av, toxav_video_bit_rate_status_cb* function, void* user_data)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(av->mutex);
|
pthread_mutex_lock(av->mutex);
|
||||||
av->vbcb.first = function;
|
av->vbcb.first = function;
|
||||||
|
@ -579,7 +576,7 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video_bitrate_invalid(video_bit_rate)) {
|
if (video_bit_rate_invalid(video_bit_rate)) {
|
||||||
rc = TOXAV_ERR_BIT_RATE_INVALID;
|
rc = TOXAV_ERR_BIT_RATE_INVALID;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
@ -605,7 +602,7 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
|
||||||
call->video_bit_rate = video_bit_rate;
|
call->video_bit_rate = video_bit_rate;
|
||||||
|
|
||||||
if (!force && av->vbcb.first)
|
if (!force && av->vbcb.first)
|
||||||
av->vbcb.first (av, call->friend_id, true, video_bit_rate, av->vbcb.second);
|
av->vbcb.first (av, call->friend_number, true, video_bit_rate, av->vbcb.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(call->mutex);
|
pthread_mutex_unlock(call->mutex);
|
||||||
|
@ -618,7 +615,7 @@ END:
|
||||||
return rc == TOXAV_ERR_BIT_RATE_OK;
|
return rc == TOXAV_ERR_BIT_RATE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toxav_callback_audio_bitrate_control(ToxAV* av, toxav_audio_bitrate_control_cb* function, void* user_data)
|
void toxav_callback_audio_bit_rate_status(ToxAV* av, toxav_audio_bit_rate_status_cb* function, void* user_data)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(av->mutex);
|
pthread_mutex_lock(av->mutex);
|
||||||
av->abcb.first = function;
|
av->abcb.first = function;
|
||||||
|
@ -636,7 +633,7 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bitrate_invalid(audio_bit_rate)) {
|
if (audio_bit_rate_invalid(audio_bit_rate)) {
|
||||||
rc = TOXAV_ERR_BIT_RATE_INVALID;
|
rc = TOXAV_ERR_BIT_RATE_INVALID;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
@ -662,7 +659,7 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
|
||||||
call->audio_bit_rate = audio_bit_rate;
|
call->audio_bit_rate = audio_bit_rate;
|
||||||
|
|
||||||
if (!force && av->abcb.first)
|
if (!force && av->abcb.first)
|
||||||
av->abcb.first (av, call->friend_id, true, audio_bit_rate, av->abcb.second);
|
av->abcb.first (av, call->friend_number, true, audio_bit_rate, av->abcb.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(call->mutex);
|
pthread_mutex_unlock(call->mutex);
|
||||||
|
@ -897,11 +894,11 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* For bitrate measurement; send dummy packet */
|
/* For bit rate measurement; send dummy packet */
|
||||||
if (ba_shoud_send_dummy(&call->aba)) {
|
if (ba_shoud_send_dummy(&call->aba)) {
|
||||||
sampling_rate = ntohl(sampling_rate);
|
sampling_rate = ntohl(sampling_rate);
|
||||||
if (ac_reconfigure_test_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {
|
if (ac_reconfigure_test_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {
|
||||||
/* FIXME should the bitrate changing fail here? */
|
/* FIXME should the bit rate changing fail here? */
|
||||||
pthread_mutex_unlock(call->mutex_audio);
|
pthread_mutex_unlock(call->mutex_audio);
|
||||||
rc = TOXAV_ERR_SEND_FRAME_INVALID;
|
rc = TOXAV_ERR_SEND_FRAME_INVALID;
|
||||||
goto END;
|
goto END;
|
||||||
|
@ -966,7 +963,7 @@ int callback_invite(void* toxav_inst, MSICall* call)
|
||||||
ToxAV* toxav = toxav_inst;
|
ToxAV* toxav = toxav_inst;
|
||||||
pthread_mutex_lock(toxav->mutex);
|
pthread_mutex_lock(toxav->mutex);
|
||||||
|
|
||||||
ToxAVCall* av_call = call_new(toxav, call->friend_id, NULL);
|
ToxAVCall* av_call = call_new(toxav, call->friend_number, NULL);
|
||||||
if (av_call == NULL) {
|
if (av_call == NULL) {
|
||||||
LOGGER_WARNING("Failed to initialize call...");
|
LOGGER_WARNING("Failed to initialize call...");
|
||||||
pthread_mutex_unlock(toxav->mutex);
|
pthread_mutex_unlock(toxav->mutex);
|
||||||
|
@ -977,7 +974,7 @@ int callback_invite(void* toxav_inst, MSICall* call)
|
||||||
av_call->msi_call = call;
|
av_call->msi_call = call;
|
||||||
|
|
||||||
if (toxav->ccb.first)
|
if (toxav->ccb.first)
|
||||||
toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio,
|
toxav->ccb.first(toxav, call->friend_number, call->peer_capabilities & msi_CapSAudio,
|
||||||
call->peer_capabilities & msi_CapSVideo, toxav->ccb.second);
|
call->peer_capabilities & msi_CapSVideo, toxav->ccb.second);
|
||||||
|
|
||||||
pthread_mutex_unlock(toxav->mutex);
|
pthread_mutex_unlock(toxav->mutex);
|
||||||
|
@ -989,7 +986,7 @@ int callback_start(void* toxav_inst, MSICall* call)
|
||||||
ToxAV* toxav = toxav_inst;
|
ToxAV* toxav = toxav_inst;
|
||||||
pthread_mutex_lock(toxav->mutex);
|
pthread_mutex_lock(toxav->mutex);
|
||||||
|
|
||||||
ToxAVCall* av_call = call_get(toxav, call->friend_id);
|
ToxAVCall* av_call = call_get(toxav, call->friend_number);
|
||||||
|
|
||||||
if (av_call == NULL) {
|
if (av_call == NULL) {
|
||||||
/* Should this ever happen? */
|
/* Should this ever happen? */
|
||||||
|
@ -1004,7 +1001,7 @@ int callback_start(void* toxav_inst, MSICall* call)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
invoke_call_state(toxav, call->friend_id, call->peer_capabilities);
|
invoke_call_state(toxav, call->friend_number, call->peer_capabilities);
|
||||||
|
|
||||||
pthread_mutex_unlock(toxav->mutex);
|
pthread_mutex_unlock(toxav->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1015,7 +1012,7 @@ int callback_end(void* toxav_inst, MSICall* call)
|
||||||
ToxAV* toxav = toxav_inst;
|
ToxAV* toxav = toxav_inst;
|
||||||
pthread_mutex_lock(toxav->mutex);
|
pthread_mutex_lock(toxav->mutex);
|
||||||
|
|
||||||
invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_END);
|
invoke_call_state(toxav, call->friend_number, TOXAV_CALL_STATE_END);
|
||||||
|
|
||||||
call_kill_transmission(call->av_call);
|
call_kill_transmission(call->av_call);
|
||||||
call_remove(call->av_call);
|
call_remove(call->av_call);
|
||||||
|
@ -1029,7 +1026,7 @@ int callback_error(void* toxav_inst, MSICall* call)
|
||||||
ToxAV* toxav = toxav_inst;
|
ToxAV* toxav = toxav_inst;
|
||||||
pthread_mutex_lock(toxav->mutex);
|
pthread_mutex_lock(toxav->mutex);
|
||||||
|
|
||||||
invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR);
|
invoke_call_state(toxav, call->friend_number, TOXAV_CALL_STATE_ERROR);
|
||||||
|
|
||||||
call_kill_transmission(call->av_call);
|
call_kill_transmission(call->av_call);
|
||||||
call_remove(call->av_call);
|
call_remove(call->av_call);
|
||||||
|
@ -1043,21 +1040,21 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
|
||||||
ToxAV* toxav = toxav_inst;
|
ToxAV* toxav = toxav_inst;
|
||||||
pthread_mutex_lock(toxav->mutex);
|
pthread_mutex_lock(toxav->mutex);
|
||||||
|
|
||||||
invoke_call_state(toxav, call->friend_id, call->peer_capabilities);
|
invoke_call_state(toxav, call->friend_number, call->peer_capabilities);
|
||||||
|
|
||||||
pthread_mutex_unlock(toxav->mutex);
|
pthread_mutex_unlock(toxav->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio_bitrate_invalid(uint32_t bitrate)
|
bool audio_bit_rate_invalid(uint32_t bit_rate)
|
||||||
{
|
{
|
||||||
/* Opus RFC 6716 section-2.1.1 dictates the following:
|
/* Opus RFC 6716 section-2.1.1 dictates the following:
|
||||||
* Opus supports all bitrates from 6 kbit/s to 510 kbit/s.
|
* Opus supports all bit rates from 6 kbit/s to 510 kbit/s.
|
||||||
*/
|
*/
|
||||||
return bitrate < 6 || bitrate > 510;
|
return bit_rate < 6 || bit_rate > 510;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool video_bitrate_invalid(uint32_t bitrate)
|
bool video_bit_rate_invalid(uint32_t bit_rate)
|
||||||
{
|
{
|
||||||
/* TODO: If anyone knows the answer to this one please fill it up */
|
/* TODO: If anyone knows the answer to this one please fill it up */
|
||||||
return false;
|
return false;
|
||||||
|
@ -1099,7 +1096,7 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
|
||||||
}
|
}
|
||||||
|
|
||||||
call->av = av;
|
call->av = av;
|
||||||
call->friend_id = friend_number;
|
call->friend_number = friend_number;
|
||||||
|
|
||||||
if (av->calls == NULL) { /* Creating */
|
if (av->calls == NULL) { /* Creating */
|
||||||
av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1);
|
av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1);
|
||||||
|
@ -1126,7 +1123,7 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
|
||||||
av->calls = tmp;
|
av->calls = tmp;
|
||||||
|
|
||||||
/* Set fields in between to null */
|
/* Set fields in between to null */
|
||||||
int32_t i = av->calls_tail;
|
int32_t i = av->calls_tail + 1;
|
||||||
for (; i < friend_number; i ++)
|
for (; i < friend_number; i ++)
|
||||||
av->calls[i] = NULL;
|
av->calls[i] = NULL;
|
||||||
|
|
||||||
|
@ -1164,7 +1161,7 @@ void call_remove(ToxAVCall* call)
|
||||||
if (call == NULL)
|
if (call == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t friend_id = call->friend_id;
|
uint32_t friend_number = call->friend_number;
|
||||||
ToxAV* av = call->av;
|
ToxAV* av = call->av;
|
||||||
|
|
||||||
ToxAVCall* prev = call->prev;
|
ToxAVCall* prev = call->prev;
|
||||||
|
@ -1175,16 +1172,16 @@ void call_remove(ToxAVCall* call)
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
else if (next)
|
else if (next)
|
||||||
av->calls_head = next->friend_id;
|
av->calls_head = next->friend_number;
|
||||||
else goto CLEAR;
|
else goto CLEAR;
|
||||||
|
|
||||||
if (next)
|
if (next)
|
||||||
next->prev = prev;
|
next->prev = prev;
|
||||||
else if (prev)
|
else if (prev)
|
||||||
av->calls_tail = prev->friend_id;
|
av->calls_tail = prev->friend_number;
|
||||||
else goto CLEAR;
|
else goto CLEAR;
|
||||||
|
|
||||||
av->calls[friend_id] = NULL;
|
av->calls[friend_number] = NULL;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CLEAR:
|
CLEAR:
|
||||||
|
@ -1214,17 +1211,16 @@ bool call_prepare_transmission(ToxAVCall* call)
|
||||||
if (create_recursive_mutex(call->mutex_audio) != 0)
|
if (create_recursive_mutex(call->mutex_audio) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (create_recursive_mutex(call->mutex_video) != 0) {
|
if (create_recursive_mutex(call->mutex_video) != 0)
|
||||||
goto AUDIO_SENDING_MUTEX_CLEANUP;
|
goto FAILURE_3;
|
||||||
}
|
|
||||||
|
if (create_recursive_mutex(call->mutex) != 0)
|
||||||
|
goto FAILURE_2;
|
||||||
|
|
||||||
if (create_recursive_mutex(call->mutex) != 0) {
|
|
||||||
goto VIDEO_SENDING_MUTEX_CLEANUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ /* Prepare audio */
|
{ /* Prepare audio */
|
||||||
call->audio.second = ac_new(av, call->friend_id, av->acb.first, av->acb.second);
|
call->audio.second = ac_new(av, call->friend_number, av->acb.first, av->acb.second);
|
||||||
call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_id, call->audio.second, ac_queue_message);
|
call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_number, call->audio.second, ac_queue_message);
|
||||||
|
|
||||||
if ( !call->audio.first || !call->audio.second ) {
|
if ( !call->audio.first || !call->audio.second ) {
|
||||||
LOGGER_ERROR("Error while starting audio!\n");
|
LOGGER_ERROR("Error while starting audio!\n");
|
||||||
|
@ -1233,8 +1229,8 @@ bool call_prepare_transmission(ToxAVCall* call)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ /* Prepare video */
|
{ /* Prepare video */
|
||||||
call->video.second = vc_new(av, call->friend_id, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz);
|
call->video.second = vc_new(av, call->friend_number, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz);
|
||||||
call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_id, call->video.second, vc_queue_message);
|
call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_number, call->video.second, vc_queue_message);
|
||||||
|
|
||||||
if ( !call->video.first || !call->video.second ) {
|
if ( !call->video.first || !call->video.second ) {
|
||||||
LOGGER_ERROR("Error while starting video!\n");
|
LOGGER_ERROR("Error while starting video!\n");
|
||||||
|
@ -1255,9 +1251,9 @@ FAILURE:
|
||||||
call->video.first = NULL;
|
call->video.first = NULL;
|
||||||
call->video.second = NULL;
|
call->video.second = NULL;
|
||||||
pthread_mutex_destroy(call->mutex);
|
pthread_mutex_destroy(call->mutex);
|
||||||
VIDEO_SENDING_MUTEX_CLEANUP:
|
FAILURE_2:
|
||||||
pthread_mutex_destroy(call->mutex_video);
|
pthread_mutex_destroy(call->mutex_video);
|
||||||
AUDIO_SENDING_MUTEX_CLEANUP:
|
FAILURE_3:
|
||||||
pthread_mutex_destroy(call->mutex_audio);
|
pthread_mutex_destroy(call->mutex_audio);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,23 +333,23 @@ typedef enum TOXAV_ERR_BIT_RATE {
|
||||||
TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL
|
TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL
|
||||||
} TOXAV_ERR_BIT_RATE;
|
} TOXAV_ERR_BIT_RATE;
|
||||||
/**
|
/**
|
||||||
* The function type for the `audio_bitrate_control` callback.
|
* The function type for the `audio_bit_rate_status` callback.
|
||||||
*
|
*
|
||||||
* @param friend_number The friend number of the friend for which to set the
|
* @param friend_number The friend number of the friend for which to set the
|
||||||
* audio bit rate.
|
* audio bit rate.
|
||||||
* @param good Is the stream good enough to keep the said bitrate. Upon failed
|
* @param stable Is the stream stable enough to keep the bit rate.
|
||||||
* non forceful bit rate setup this will be set to false and 'bit_rate'
|
* Upon successful, non forceful, bit rate change, this is set to
|
||||||
* will be set to the bit rate that failed, otherwise 'good' will be set to
|
* true and 'bit_rate' is set to new bit rate.
|
||||||
* true with 'bit_rate' set to new bit rate. If the stream becomes bad,
|
* The stable is set to false with bit_rate set to the unstable
|
||||||
* the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
|
* bit rate when either current stream is unstable with said bit rate
|
||||||
* This callback will never be called when the stream is good.
|
* or the non forceful change failed.
|
||||||
* @param bit_rate The bit rate in Kb/sec.
|
* @param bit_rate The bit rate in Kb/sec.
|
||||||
*/
|
*/
|
||||||
typedef void toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data);
|
typedef void toxav_audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data);
|
||||||
/**
|
/**
|
||||||
* Set the callback for the `audio_bitrate_control` event. Pass NULL to unset.
|
* Set the callback for the `audio_bit_rate_status` event. Pass NULL to unset.
|
||||||
*/
|
*/
|
||||||
void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control_cb *function, void *user_data);
|
void toxav_callback_audio_bit_rate_status(ToxAV *av, toxav_audio_bit_rate_status_cb *function, void *user_data);
|
||||||
/**
|
/**
|
||||||
* Set the audio bit rate to be used in subsequent audio frames.
|
* Set the audio bit rate to be used in subsequent audio frames.
|
||||||
*
|
*
|
||||||
|
@ -362,23 +362,23 @@ void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control
|
||||||
*/
|
*/
|
||||||
bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
|
bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
|
||||||
/**
|
/**
|
||||||
* The function type for the `video_bitrate_control` callback.
|
* The function type for the `video_bit_rate_status` callback.
|
||||||
*
|
*
|
||||||
* @param friend_number The friend number of the friend for which to set the
|
* @param friend_number The friend number of the friend for which to set the
|
||||||
* video bit rate.
|
* video bit rate.
|
||||||
* @param good Is the stream good enough to keep the said bitrate. Upon failed
|
* @param stable Is the stream stable enough to keep the bit rate.
|
||||||
* non forceful bit rate setup this will be set to false and 'bit_rate'
|
* Upon successful, non forceful, bit rate change, this is set to
|
||||||
* will be set to the bit rate that failed, otherwise 'good' will be set to
|
* true and 'bit_rate' is set to new bit rate.
|
||||||
* true with 'bit_rate' set to new bit rate. If the stream becomes bad,
|
* The stable is set to false with bit_rate set to the unstable
|
||||||
* the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
|
* bit rate when either current stream is unstable with said bit rate
|
||||||
* This callback will never be called when the stream is good.
|
* or the non forceful change failed.
|
||||||
* @param bit_rate The bit rate in Kb/sec.
|
* @param bit_rate The bit rate in Kb/sec.
|
||||||
*/
|
*/
|
||||||
typedef void toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data);
|
typedef void toxav_video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data);
|
||||||
/**
|
/**
|
||||||
* Set the callback for the `video_bitrate_control` event. Pass NULL to unset.
|
* Set the callback for the `video_bit_rate_status` event. Pass NULL to unset.
|
||||||
*/
|
*/
|
||||||
void toxav_callback_video_bitrate_control(ToxAV *av, toxav_video_bitrate_control_cb *function, void *user_data);
|
void toxav_callback_video_bit_rate_status(ToxAV *av, toxav_video_bit_rate_status_cb *function, void *user_data);
|
||||||
/**
|
/**
|
||||||
* Set the video bit rate to be used in subsequent video frames.
|
* Set the video bit rate to be used in subsequent video frames.
|
||||||
*
|
*
|
||||||
|
|
|
@ -35,15 +35,14 @@
|
||||||
#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
|
#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
|
||||||
#define VIDEOFRAME_HEADER_SIZE 0x2
|
#define VIDEOFRAME_HEADER_SIZE 0x2
|
||||||
|
|
||||||
/* FIXME: Might not be enough? NOTE: I think it is enough */
|
|
||||||
#define VIDEO_DECODE_BUFFER_SIZE 20
|
#define VIDEO_DECODE_BUFFER_SIZE 20
|
||||||
|
|
||||||
typedef struct { uint16_t size; uint8_t data[]; } Payload;
|
typedef struct { uint16_t size; uint8_t data[]; } Payload;
|
||||||
|
|
||||||
bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate);
|
bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bit_rate);
|
||||||
|
|
||||||
|
|
||||||
VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* cb, void* cb_data, uint32_t mvfpsz)
|
VCSession* vc_new(ToxAV* av, uint32_t friend_number, toxav_receive_video_frame_cb* cb, void* cb_data, uint32_t mvfpsz)
|
||||||
{
|
{
|
||||||
VCSession *vc = calloc(sizeof(VCSession), 1);
|
VCSession *vc = calloc(sizeof(VCSession), 1);
|
||||||
|
|
||||||
|
@ -86,7 +85,7 @@ VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* c
|
||||||
vc->lcfd = 60;
|
vc->lcfd = 60;
|
||||||
vc->vcb.first = cb;
|
vc->vcb.first = cb;
|
||||||
vc->vcb.second = cb_data;
|
vc->vcb.second = cb_data;
|
||||||
vc->friend_id = friend_id;
|
vc->friend_number = friend_number;
|
||||||
vc->peer_video_frame_piece_size = mvfpsz;
|
vc->peer_video_frame_piece_size = mvfpsz;
|
||||||
|
|
||||||
return vc;
|
return vc;
|
||||||
|
@ -140,7 +139,7 @@ void vc_do(VCSession* vc)
|
||||||
/* Play decoded images */
|
/* Play decoded images */
|
||||||
for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {
|
for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {
|
||||||
if (vc->vcb.first)
|
if (vc->vcb.first)
|
||||||
vc->vcb.first(vc->av, vc->friend_id, dest->d_w, dest->d_h,
|
vc->vcb.first(vc->av, vc->friend_number, dest->d_w, dest->d_h,
|
||||||
(const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2],
|
(const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2],
|
||||||
dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second);
|
dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second);
|
||||||
|
|
||||||
|
@ -289,16 +288,16 @@ end:
|
||||||
rtp_free_msg(msg);
|
rtp_free_msg(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height)
|
int vc_reconfigure_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height)
|
||||||
{
|
{
|
||||||
if (!vc)
|
if (!vc)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
vpx_codec_enc_cfg_t cfg = *vc->encoder->config.enc;
|
vpx_codec_enc_cfg_t cfg = *vc->encoder->config.enc;
|
||||||
if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height)
|
if (cfg.rc_target_bitrate == bit_rate && cfg.g_w == width && cfg.g_h == height)
|
||||||
return 0; /* Nothing changed */
|
return 0; /* Nothing changed */
|
||||||
|
|
||||||
cfg.rc_target_bitrate = bitrate;
|
cfg.rc_target_bitrate = bit_rate;
|
||||||
cfg.g_w = width;
|
cfg.g_w = width;
|
||||||
cfg.g_h = height;
|
cfg.g_h = height;
|
||||||
|
|
||||||
|
@ -310,16 +309,16 @@ int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint1
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height)
|
int vc_reconfigure_test_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height)
|
||||||
{
|
{
|
||||||
if (!vc)
|
if (!vc)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
vpx_codec_enc_cfg_t cfg = *vc->test_encoder->config.enc;
|
vpx_codec_enc_cfg_t cfg = *vc->test_encoder->config.enc;
|
||||||
if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height)
|
if (cfg.rc_target_bitrate == bit_rate && cfg.g_w == width && cfg.g_h == height)
|
||||||
return 0; /* Nothing changed */
|
return 0; /* Nothing changed */
|
||||||
|
|
||||||
cfg.rc_target_bitrate = bitrate;
|
cfg.rc_target_bitrate = bit_rate;
|
||||||
cfg.g_w = width;
|
cfg.g_w = width;
|
||||||
cfg.g_h = height;
|
cfg.g_h = height;
|
||||||
|
|
||||||
|
@ -334,7 +333,7 @@ int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate)
|
bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bit_rate)
|
||||||
{
|
{
|
||||||
assert(dest);
|
assert(dest);
|
||||||
|
|
||||||
|
@ -354,7 +353,7 @@ bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.rc_target_bitrate = bitrate;
|
cfg.rc_target_bitrate = bit_rate;
|
||||||
cfg.g_w = 800;
|
cfg.g_w = 800;
|
||||||
cfg.g_h = 600;
|
cfg.g_h = 600;
|
||||||
cfg.g_pass = VPX_RC_ONE_PASS;
|
cfg.g_pass = VPX_RC_ONE_PASS;
|
||||||
|
|
|
@ -38,6 +38,9 @@
|
||||||
|
|
||||||
struct RTPMessage_s;
|
struct RTPMessage_s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base Video Codec session type.
|
||||||
|
*/
|
||||||
typedef struct VCSession_s {
|
typedef struct VCSession_s {
|
||||||
|
|
||||||
/* encoding */
|
/* encoding */
|
||||||
|
@ -65,23 +68,46 @@ typedef struct VCSession_s {
|
||||||
const uint8_t *processing_video_frame;
|
const uint8_t *processing_video_frame;
|
||||||
uint16_t processing_video_frame_size;
|
uint16_t processing_video_frame_size;
|
||||||
|
|
||||||
|
|
||||||
ToxAV *av;
|
ToxAV *av;
|
||||||
int32_t friend_id;
|
uint32_t friend_number;
|
||||||
|
|
||||||
PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
|
PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
|
||||||
|
|
||||||
pthread_mutex_t queue_mutex[1];
|
pthread_mutex_t queue_mutex[1];
|
||||||
} VCSession;
|
} VCSession;
|
||||||
|
|
||||||
VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb *cb, void *cb_data, uint32_t mvfpsz);
|
/*
|
||||||
|
* Create new Video Codec session.
|
||||||
|
*/
|
||||||
|
VCSession* vc_new(ToxAV* av, uint32_t friend_number, toxav_receive_video_frame_cb *cb, void *cb_data, uint32_t mvfpsz);
|
||||||
|
/*
|
||||||
|
* Kill the Video Codec session.
|
||||||
|
*/
|
||||||
void vc_kill(VCSession* vc);
|
void vc_kill(VCSession* vc);
|
||||||
|
/*
|
||||||
|
* Do periodic work. Work is consisted out of decoding only.
|
||||||
|
*/
|
||||||
void vc_do(VCSession* vc);
|
void vc_do(VCSession* vc);
|
||||||
|
/*
|
||||||
|
* Set new video splitting cycle. This is requirement in order to send video packets.
|
||||||
|
*/
|
||||||
void vc_init_video_splitter_cycle(VCSession* vc);
|
void vc_init_video_splitter_cycle(VCSession* vc);
|
||||||
|
/*
|
||||||
|
* Update the video splitter cycle with new data.
|
||||||
|
*/
|
||||||
int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length);
|
int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length);
|
||||||
|
/*
|
||||||
|
* Iterate over splitted cycle.
|
||||||
|
*/
|
||||||
const uint8_t *vc_iterate_split_video_frame(VCSession* vc, uint16_t *size);
|
const uint8_t *vc_iterate_split_video_frame(VCSession* vc, uint16_t *size);
|
||||||
|
/*
|
||||||
|
* Queue new rtp message.
|
||||||
|
*/
|
||||||
int vc_queue_message(void *vcp, struct RTPMessage_s *msg);
|
int vc_queue_message(void *vcp, struct RTPMessage_s *msg);
|
||||||
int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height);
|
/*
|
||||||
int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height);
|
* Set new values to the encoders.
|
||||||
|
*/
|
||||||
|
int vc_reconfigure_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height);
|
||||||
|
int vc_reconfigure_test_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height);
|
||||||
|
|
||||||
#endif /* VIDEO_H */
|
#endif /* VIDEO_H */
|
Loading…
Reference in New Issue
Block a user