This commit is contained in:
mannol 2015-04-29 01:01:25 +02:00
parent e4a020333d
commit 9bba7a0434
15 changed files with 791 additions and 1419 deletions

View File

@ -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

View File

@ -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();
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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

View File

@ -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));

View File

@ -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 */

View File

@ -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;
} }

View File

@ -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.
*/ */

View File

@ -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, &timestamp, sizeof(timestamp)); memcpy(it, &timestamp, 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);

View File

@ -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.
*/ */

View File

@ -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;
} }

View File

@ -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.
* *

View File

@ -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;

View File

@ -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 */