mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Done
This commit is contained in:
parent
e4a020333d
commit
9bba7a0434
|
@ -21,8 +21,8 @@ AUTOTEST_LDADD = \
|
|||
|
||||
|
||||
if BUILD_AV
|
||||
TESTS += toxav_basic_test toxav_many_test
|
||||
check_PROGRAMS += toxav_basic_test toxav_many_test
|
||||
TESTS += toxav_basic_test #toxav_many_test
|
||||
check_PROGRAMS += toxav_basic_test #toxav_many_test
|
||||
AUTOTEST_LDADD += libtoxav.la
|
||||
endif
|
||||
|
||||
|
@ -90,11 +90,11 @@ toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)
|
|||
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
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <vpx/vpx_image.h>
|
||||
|
||||
#include "../toxcore/tox.h"
|
||||
#include "../toxcore/util.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/crypto_core.h"
|
||||
#include "../toxav/toxav.h"
|
||||
|
@ -28,600 +29,406 @@
|
|||
#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;
|
||||
|
||||
typedef struct _Party {
|
||||
CallStatus status;
|
||||
ToxAv *av;
|
||||
time_t *CallStarted;
|
||||
int call_index;
|
||||
} Party;
|
||||
} CallControl;
|
||||
|
||||
typedef struct _Status {
|
||||
Party Alice;
|
||||
Party Bob;
|
||||
} Status;
|
||||
|
||||
/* My default settings */
|
||||
static ToxAvCSettings muhcaps;
|
||||
|
||||
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||
/**
|
||||
* Callbacks
|
||||
*/
|
||||
void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
||||
{
|
||||
printf("Handling CALL callback\n");
|
||||
((CallControl*)user_data)->incoming = true;
|
||||
}
|
||||
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) {
|
||||
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 )
|
||||
{
|
||||
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++;
|
||||
/**
|
||||
* Iterate helper
|
||||
*/
|
||||
#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \
|
||||
{ int step = 0, running = 1; while (running) {\
|
||||
tox_iterate(bootstrap_node); tox_iterate(Alice); tox_iterate(Bob); \
|
||||
toxav_do(status_control.Bob.av); toxav_do(status_control.Alice.av); \
|
||||
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 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)
|
||||
int iterate_tox(Tox* bootstrap, Tox* Alice, Tox* Bob)
|
||||
{
|
||||
tox_iterate(bootstrap);
|
||||
tox_iterate(Alice);
|
||||
tox_iterate(Bob);
|
||||
|
||||
return MIN(tox_iteration_interval(Alice), tox_iteration_interval(Bob));
|
||||
}
|
||||
|
||||
|
||||
#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)
|
||||
{
|
||||
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);
|
||||
Tox* Alice, *Bob, *bootstrap;
|
||||
ToxAV* AliceAV, *BobAV;
|
||||
|
||||
ck_assert_msg(bootstrap_node || Alice || Bob, "Failed to create 3 tox instances");
|
||||
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);
|
||||
|
||||
uint32_t to_compare = 974536;
|
||||
tox_callback_friend_request(Alice, accept_friend_request, &to_compare);
|
||||
uint8_t address[TOX_ADDRESS_SIZE];
|
||||
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);
|
||||
tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);
|
||||
tox_self_get_address(Alice, address);
|
||||
|
||||
|
||||
assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
|
||||
|
||||
uint8_t off = 1;
|
||||
|
||||
while (1) {
|
||||
tox_iterate(bootstrap_node);
|
||||
tox_iterate(Alice);
|
||||
tox_iterate(Bob);
|
||||
iterate_tox(bootstrap, Alice, Bob);
|
||||
|
||||
if (tox_self_get_connection_status(bootstrap_node) && tox_self_get_connection_status(Alice)
|
||||
&& tox_self_get_connection_status(Bob)
|
||||
&& off) {
|
||||
if (tox_self_get_connection_status(bootstrap) &&
|
||||
tox_self_get_connection_status(Alice) &&
|
||||
tox_self_get_connection_status(Bob) && off) {
|
||||
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
|
||||
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;
|
||||
|
||||
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;
|
||||
int running = 1;
|
||||
TOXAV_ERR_NEW error;
|
||||
AliceAV = toxav_new(Alice, &error);
|
||||
assert(error == TOXAV_ERR_NEW_OK);
|
||||
|
||||
while (running) {
|
||||
tox_iterate(bootstrap_node);
|
||||
tox_iterate(Alice);
|
||||
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++;
|
||||
BobAV = toxav_new(Bob, &error);
|
||||
assert(error == TOXAV_ERR_NEW_OK);
|
||||
}
|
||||
|
||||
break;
|
||||
toxav_callback_call(AliceAV, t_toxav_call_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_audio_frame(AliceAV, t_toxav_receive_audio_frame_cb, &AliceCC);
|
||||
|
||||
case 2: /* Wait for Both to have status ended */
|
||||
if (status_control.Alice.status == Rejected && status_control.Bob.status == Ended) running = 0;
|
||||
toxav_callback_call(BobAV, t_toxav_call_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_audio_frame(BobAV, t_toxav_receive_audio_frame_cb, &BobCC);
|
||||
|
||||
break;
|
||||
printf("Created 2 instances of ToxAV\n");
|
||||
printf("All set after %llu seconds!\n", time(NULL) - cur_time);
|
||||
|
||||
|
||||
#define REGULAR_CALL_FLOW(A_BR, V_BR) \
|
||||
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, Alice, Bob); \
|
||||
} \
|
||||
printf("Success!\n");\
|
||||
} while(0)
|
||||
|
||||
if (TEST_REGULAR_AV) {
|
||||
printf("\nTrying regular call (Audio and Video)...\n");
|
||||
REGULAR_CALL_FLOW(48, 4000);
|
||||
}
|
||||
|
||||
c_sleep(20);
|
||||
if (TEST_REGULAR_A) {
|
||||
printf("\nTrying regular call (Audio only)...\n");
|
||||
REGULAR_CALL_FLOW(48, 0);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
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));
|
||||
|
||||
/*
|
||||
* Call and cancel
|
||||
*/
|
||||
{
|
||||
int step = 0;
|
||||
int running = 1;
|
||||
TOXAV_ERR_CALL rc;
|
||||
toxav_call(AliceAV, 0, 48, 0, &rc);
|
||||
|
||||
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: /* Alice */
|
||||
printf("Alice is calling...\n");
|
||||
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, &muhcaps, 10);
|
||||
step++;
|
||||
break;
|
||||
|
||||
|
||||
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?");
|
||||
step++;
|
||||
if (rc != TOXAV_ERR_CALL_OK) {
|
||||
printf("toxav_call failed: %d\n", rc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
while (!BobCC.incoming)
|
||||
iterate_tox(bootstrap, Alice, Bob);
|
||||
|
||||
case 2: /* Wait for Both to have status ended */
|
||||
if (status_control.Bob.status == Canceled) running = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
c_sleep(20);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Timeout
|
||||
*/
|
||||
/* Reject */
|
||||
{
|
||||
int step = 0;
|
||||
int running = 1;
|
||||
TOXAV_ERR_CALL_CONTROL rc;
|
||||
toxav_call_control(BobAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
|
||||
|
||||
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;
|
||||
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
|
||||
printf("toxav_call_control failed: %d\n", rc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
c_sleep(20);
|
||||
while (AliceCC.state != TOXAV_CALL_STATE_END)
|
||||
iterate_tox(bootstrap, Alice, Bob);
|
||||
|
||||
printf("Success!\n");
|
||||
}
|
||||
|
||||
printf("\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);
|
||||
}
|
||||
}
|
||||
|
||||
vpx_img_free(sample_image);
|
||||
toxav_kill(status_control.Alice.av);
|
||||
toxav_kill(status_control.Bob.av);
|
||||
tox_kill(bootstrap_node);
|
||||
tox_kill(Alice);
|
||||
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(Alice);
|
||||
tox_kill(bootstrap);
|
||||
|
||||
printf("Calls ended!\n");
|
||||
printf("\nTest successful!\n");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
||||
Suite *tox_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("ToxAV");
|
||||
|
||||
DEFTESTCASE_SLOW(AV_flows, 200);
|
||||
|
||||
return s;
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -637,6 +444,4 @@ int main(int argc, char *argv[])
|
|||
srunner_free(test_runner);
|
||||
|
||||
return number_failed;
|
||||
|
||||
// return test_AV_flows();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <vpx/vpx_image.h>
|
||||
|
||||
#include "../toxcore/tox.h"
|
||||
#include "../toxcore/util.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/crypto_core.h"
|
||||
#include "../toxav/toxav.h"
|
||||
|
@ -26,359 +27,177 @@
|
|||
#define c_sleep(x) usleep(1000*x)
|
||||
#endif
|
||||
|
||||
pthread_mutex_t muhmutex;
|
||||
|
||||
typedef enum _CallStatus {
|
||||
none,
|
||||
InCall,
|
||||
Ringing,
|
||||
Ended,
|
||||
Rejected,
|
||||
Canceled
|
||||
typedef struct {
|
||||
bool incoming;
|
||||
uint32_t state;
|
||||
|
||||
} CallStatus;
|
||||
} CallControl;
|
||||
|
||||
typedef struct _Party {
|
||||
CallStatus status;
|
||||
ToxAv *av;
|
||||
int id;
|
||||
} Party;
|
||||
|
||||
typedef struct _ACall {
|
||||
pthread_t tid;
|
||||
int idx;
|
||||
|
||||
Party Caller;
|
||||
Party Callee;
|
||||
} ACall;
|
||||
|
||||
typedef struct _Status {
|
||||
ACall calls[3]; /* Make 3 calls for this test */
|
||||
} Status;
|
||||
|
||||
Status status_control;
|
||||
|
||||
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||
/**
|
||||
* Callbacks
|
||||
*/
|
||||
void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
||||
{
|
||||
printf("Handling CALL callback\n");
|
||||
((CallControl*)user_data)->incoming = true;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
cast->calls[call_index].Callee.status = Ringing;
|
||||
TOXAV_ERR_NEW error;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
START_TEST(test_AV_three_calls)
|
||||
// void test_AV_three_calls()
|
||||
{
|
||||
long long unsigned int cur_time = time(NULL);
|
||||
Tox *bootstrap_node = tox_new(0, 0, 0, 0);
|
||||
Tox *caller = tox_new(0, 0, 0, 0);
|
||||
Tox *callees[3] = {
|
||||
tox_new(0, 0, 0, 0),
|
||||
tox_new(0, 0, 0, 0),
|
||||
tox_new(0, 0, 0, 0),
|
||||
};
|
||||
Tox* Alice, *bootstrap, *Bobs[3];
|
||||
ToxAV* AliceAV, *BobsAV[3];
|
||||
|
||||
|
||||
ck_assert_msg(bootstrap_node != NULL, "Failed to create bootstrap node");
|
||||
CallControl AliceCC[3], BobsCC[3];
|
||||
|
||||
int i = 0;
|
||||
{
|
||||
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);
|
||||
|
||||
for (; i < 3; i ++) {
|
||||
ck_assert_msg(callees[i] != NULL, "Failed to create 3 tox instances");
|
||||
BobsAV[i] = tox_new(NULL, NULL, 0, &error);
|
||||
assert(error == TOX_ERR_NEW_OK);
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < 3; i ++ ) {
|
||||
printf("Created 5 instances of Tox\n");
|
||||
printf("Preparing network...\n");
|
||||
long long unsigned int cur_time = time(NULL);
|
||||
|
||||
uint32_t to_compare = 974536;
|
||||
tox_callback_friend_request(callees[i], accept_friend_request, &to_compare);
|
||||
uint8_t address[TOX_ADDRESS_SIZE];
|
||||
tox_self_get_address(callees[i], address);
|
||||
|
||||
uint32_t test = tox_friend_add(caller, address, (uint8_t *)"gentoo", 7, 0);
|
||||
ck_assert_msg( test == i, "Failed to add friend error code: %i", test);
|
||||
}
|
||||
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_node);
|
||||
tox_iterate(caller);
|
||||
tox_iterate(bootstrap);
|
||||
tox_iterate(Alice);
|
||||
tox_iterate(Bobs[0]);
|
||||
tox_iterate(Bobs[1]);
|
||||
tox_iterate(Bobs[2]);
|
||||
|
||||
for (i = 0; i < 3; i ++) {
|
||||
tox_iterate(callees[i]);
|
||||
}
|
||||
|
||||
|
||||
if (tox_self_get_connection_status(bootstrap_node) &&
|
||||
tox_self_get_connection_status(caller) &&
|
||||
tox_self_get_connection_status(callees[0]) &&
|
||||
tox_self_get_connection_status(callees[1]) &&
|
||||
tox_self_get_connection_status(callees[2]) && off) {
|
||||
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);
|
||||
off = 0;
|
||||
}
|
||||
|
||||
|
||||
if (tox_friend_get_connection_status(caller, 0, 0) &&
|
||||
tox_friend_get_connection_status(caller, 1, 0) &&
|
||||
tox_friend_get_connection_status(caller, 2, 0) )
|
||||
if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&
|
||||
tox_friend_get_connection_status(Alice, 1, NULL) == TOX_CONNECTION_UDP &&
|
||||
tox_friend_get_connection_status(Alice, 2, NULL) == TOX_CONNECTION_UDP &&
|
||||
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;
|
||||
|
||||
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]);
|
||||
BobsAV[1] = setup_av_instance(Bobs[1], &BobsCC[1]);
|
||||
BobsAV[2] = setup_av_instance(Bobs[2], &BobsCC[2]);
|
||||
|
||||
ToxAv *uniqcallerav = toxav_new(caller, 3);
|
||||
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 ++) {
|
||||
status_control.calls[i].idx = 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;
|
||||
tox_kill(Bobs[i]);
|
||||
toxav_kill(BobsAV[i]);
|
||||
}
|
||||
|
||||
pthread_mutex_init(&muhmutex, NULL);
|
||||
|
||||
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]);
|
||||
|
||||
printf("\nTest successful!\n");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
@ -410,8 +229,4 @@ int main(int argc, char *argv[])
|
|||
srunner_free(test_runner);
|
||||
|
||||
return number_failed;
|
||||
|
||||
// test_AV_three_calls();
|
||||
|
||||
// return 0;
|
||||
}
|
||||
|
|
|
@ -70,13 +70,6 @@
|
|||
#define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8)
|
||||
|
||||
|
||||
/* 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_V 1
|
||||
|
||||
|
@ -187,21 +180,21 @@ void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
|||
free(rb_write(cc->arb, f));
|
||||
pthread_mutex_unlock(cc->arb_mutex);
|
||||
}
|
||||
void t_toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number,
|
||||
bool good, uint32_t bit_rate, void *user_data)
|
||||
void t_toxav_audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number,
|
||||
bool stable, uint32_t bit_rate, void *user_data)
|
||||
{
|
||||
if (good)
|
||||
printf ("Set new audio bitrate to: %d\n", bit_rate);
|
||||
if (stable)
|
||||
printf ("Set new audio bit rate to: %d\n", bit_rate);
|
||||
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,
|
||||
bool good, uint32_t bit_rate, void *user_data)
|
||||
void t_toxav_video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number,
|
||||
bool stable, uint32_t bit_rate, void *user_data)
|
||||
{
|
||||
if (good)
|
||||
printf ("Set new video bitrate to: %d", bit_rate);
|
||||
if (stable)
|
||||
printf ("Set new video bit rate to: %d", bit_rate);
|
||||
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)
|
||||
{
|
||||
|
@ -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_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_audio_bitrate_control(*AliceAV, t_toxav_audio_bitrate_control_cb, AliceCC);
|
||||
toxav_callback_video_bitrate_control(*AliceAV, t_toxav_video_bitrate_control_cb, AliceCC);
|
||||
toxav_callback_audio_bit_rate_status(*AliceAV, t_toxav_audio_bit_rate_status_cb, AliceCC);
|
||||
toxav_callback_video_bit_rate_status(*AliceAV, t_toxav_video_bit_rate_status_cb, AliceCC);
|
||||
|
||||
/* Bob */
|
||||
toxav_callback_call(*BobAV, t_toxav_call_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_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_video_bitrate_control(*BobAV, t_toxav_video_bitrate_control_cb, BobCC);
|
||||
toxav_callback_audio_bit_rate_status(*BobAV, t_toxav_audio_bit_rate_status_cb, BobCC);
|
||||
toxav_callback_video_bit_rate_status(*BobAV, t_toxav_video_bit_rate_status_cb, BobCC);
|
||||
|
||||
|
||||
printf("Created 2 instances of ToxAV\n");
|
||||
|
@ -513,232 +506,7 @@ int main (int argc, char** argv)
|
|||
|
||||
initialize_tox(&bootstrap, &AliceAV, &AliceCC, &BobAV, &BobCC);
|
||||
|
||||
#define REGULAR_CALL_FLOW(A_BR, V_BR) \
|
||||
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 */
|
||||
if (TEST_TRANSFER_A) {
|
||||
SNDFILE* af_handle;
|
||||
SF_INFO af_info;
|
||||
|
|
@ -37,25 +37,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
|
|||
$(PTHREAD_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
|
|
@ -31,14 +31,14 @@ static void jbuf_clear(struct JitterBuffer *q);
|
|||
static void jbuf_free(struct JitterBuffer *q);
|
||||
static int jbuf_write(struct JitterBuffer *q, RTPMessage *m);
|
||||
static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
@ -78,11 +78,11 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
|
|||
goto DECODER_CLEANUP;
|
||||
}
|
||||
|
||||
ac->last_encoding_bitrate = 48000;
|
||||
ac->last_encoding_bit_rate = 48000;
|
||||
ac->last_encoding_sampling_rate = 48000;
|
||||
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_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->av = av;
|
||||
ac->friend_id = friend_id;
|
||||
ac->friend_number = friend_number;
|
||||
ac->acb.first = cb;
|
||||
ac->acb.second = cb_data;
|
||||
|
||||
|
@ -181,7 +181,7 @@ void ac_do(ACSession* ac)
|
|||
} else if (ac->acb.first) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -220,28 +220,27 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
|
|||
|
||||
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,
|
||||
&ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
||||
if (!ac || !reconfigure_audio_encoder(&ac->encoder, bit_rate, sampling_rate, channels,
|
||||
&ac->last_encoding_bit_rate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
||||
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;
|
||||
}
|
||||
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,
|
||||
&ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
||||
if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bit_rate, sampling_rate, channels,
|
||||
&ac->last_encoding_bit_rate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* JITTER BUFFER WORK */
|
||||
struct JitterBuffer {
|
||||
RTPMessage **queue;
|
||||
uint32_t size;
|
||||
|
@ -340,7 +339,7 @@ static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success)
|
|||
*success = 0;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bitrate));
|
||||
status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bit_rate));
|
||||
|
||||
if ( status != OPUS_OK ) {
|
||||
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
|
||||
|
|
|
@ -31,18 +31,21 @@
|
|||
|
||||
struct RTPMessage_s;
|
||||
|
||||
/*
|
||||
* Base Audio Codec session type.
|
||||
*/
|
||||
typedef struct ACSession_s {
|
||||
/* encoding */
|
||||
OpusEncoder *encoder;
|
||||
int32_t last_encoding_sampling_rate;
|
||||
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;
|
||||
int32_t last_test_encoding_sampling_rate;
|
||||
int32_t last_test_encoding_channel_count;
|
||||
int32_t last_test_encoding_bitrate;
|
||||
int32_t last_test_encoding_bit_rate;
|
||||
|
||||
/* decoding */
|
||||
OpusDecoder *decoder;
|
||||
|
@ -57,14 +60,30 @@ typedef struct ACSession_s {
|
|||
pthread_mutex_t queue_mutex[1];
|
||||
|
||||
ToxAV* av;
|
||||
uint32_t friend_id;
|
||||
uint32_t friend_number;
|
||||
PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
|
||||
} 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);
|
||||
/*
|
||||
* Do periodic work. Work is consisted out of decoding only.
|
||||
*/
|
||||
void ac_do(ACSession* ac);
|
||||
/*
|
||||
* Queue new rtp message.
|
||||
*/
|
||||
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 */
|
124
toxav/msi.c
124
toxav/msi.c
|
@ -75,37 +75,37 @@ typedef struct {
|
|||
MSIHeaderRequest request;
|
||||
MSIHeaderError error;
|
||||
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;
|
||||
|
||||
|
||||
void msg_init (MSIMessage *dest, MSIRequest request);
|
||||
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 );
|
||||
int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg );
|
||||
int send_error ( Messenger* m, uint32_t friend_id, MSIError error );
|
||||
int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg );
|
||||
int send_error ( Messenger* m, uint32_t friend_number, MSIError error );
|
||||
static int invoke_callback(MSICall* call, MSICallbackID cb);
|
||||
static MSICall *get_call ( MSISession *session, uint32_t friend_id );
|
||||
MSICall *new_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_number );
|
||||
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_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
|
||||
*/
|
||||
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);
|
||||
session->callbacks[id] = callback;
|
||||
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!");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -123,12 +123,12 @@ MSISession *msi_new ( Messenger *messenger )
|
|||
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 */
|
||||
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);
|
||||
return retu;
|
||||
|
@ -149,7 +149,7 @@ int msi_kill ( MSISession *session )
|
|||
|
||||
MSICall* it = get_call(session, session->calls_head);
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
@ -161,18 +161,18 @@ int msi_kill ( MSISession *session )
|
|||
free ( session );
|
||||
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);
|
||||
if (get_call(session, friend_id) != NULL) {
|
||||
if (get_call(session, friend_number) != NULL) {
|
||||
LOGGER_ERROR("Already in a call");
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*call) = new_call ( session, friend_id );
|
||||
(*call) = new_call ( session, friend_number );
|
||||
|
||||
if ( *call == NULL ) {
|
||||
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.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;
|
||||
|
||||
|
@ -200,7 +200,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
|
|||
}
|
||||
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;
|
||||
pthread_mutex_lock(session->mutex);
|
||||
|
@ -208,7 +208,7 @@ int msi_hangup ( MSICall* call )
|
|||
MSIMessage msg;
|
||||
msg_init(&msg, requ_pop);
|
||||
|
||||
send_message ( session->messenger, call->friend_id, &msg );
|
||||
send_message ( session->messenger, call->friend_number, &msg );
|
||||
|
||||
kill_call(call);
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
|
@ -216,7 +216,7 @@ int msi_hangup ( MSICall* call )
|
|||
}
|
||||
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;
|
||||
pthread_mutex_lock(session->mutex);
|
||||
|
@ -240,7 +240,7 @@ int msi_answer ( MSICall* call, uint8_t capabilities )
|
|||
msg.vfpsz.exists = true;
|
||||
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;
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
pthread_mutex_lock(session->mutex);
|
||||
|
@ -275,7 +275,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities )
|
|||
msg.capabilities.exists = true;
|
||||
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);
|
||||
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 */
|
||||
}
|
||||
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 */
|
||||
assert(m);
|
||||
|
@ -438,19 +438,19 @@ int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg )
|
|||
*it = 0;
|
||||
size ++;
|
||||
|
||||
if ( m_msi_packet(m, friend_id, parsed, size) ) {
|
||||
if ( m_msi_packet(m, friend_number, parsed, size) ) {
|
||||
LOGGER_DEBUG("Sent message");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
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;
|
||||
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.value = error;
|
||||
|
||||
send_message ( m, friend_id, &msg );
|
||||
send_message ( m, friend_number, &msg );
|
||||
return 0;
|
||||
}
|
||||
int invoke_callback(MSICall* call, MSICallbackID cb)
|
||||
|
@ -484,16 +484,16 @@ FAILURE:
|
|||
call->error = msi_EHandle;
|
||||
return -1;
|
||||
}
|
||||
static MSICall *get_call ( MSISession *session, uint32_t friend_id )
|
||||
static MSICall *get_call ( MSISession *session, uint32_t friend_number )
|
||||
{
|
||||
assert(session);
|
||||
|
||||
if (session->calls == NULL || session->calls_tail < friend_id)
|
||||
if (session->calls == NULL || session->calls_tail < friend_number)
|
||||
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);
|
||||
|
||||
|
@ -503,20 +503,20 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
|
|||
return NULL;
|
||||
|
||||
rc->session = session;
|
||||
rc->friend_id = friend_id;
|
||||
rc->friend_number = friend_number;
|
||||
|
||||
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) {
|
||||
free(rc);
|
||||
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 */
|
||||
void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_id + 1);
|
||||
} else if (session->calls_tail < friend_number) { /* Appending */
|
||||
void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_number + 1);
|
||||
|
||||
if (tmp == NULL) {
|
||||
free(rc);
|
||||
|
@ -526,22 +526,22 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
|
|||
session->calls = tmp;
|
||||
|
||||
/* Set fields in between to null */
|
||||
int32_t i = session->calls_tail;
|
||||
for (; i < friend_id; i ++)
|
||||
int32_t i = session->calls_tail + 1;
|
||||
for (; i < friend_number; i ++)
|
||||
session->calls[i] = NULL;
|
||||
|
||||
rc->prev = session->calls[session->calls_tail];
|
||||
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];
|
||||
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;
|
||||
}
|
||||
void kill_call ( MSICall *call )
|
||||
|
@ -560,16 +560,16 @@ void kill_call ( MSICall *call )
|
|||
if (prev)
|
||||
prev->next = next;
|
||||
else if (next)
|
||||
session->calls_head = next->friend_id;
|
||||
session->calls_head = next->friend_number;
|
||||
else goto CLEAR_CONTAINER;
|
||||
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
else if (prev)
|
||||
session->calls_tail = prev->friend_id;
|
||||
session->calls_tail = prev->friend_number;
|
||||
else goto CLEAR_CONTAINER;
|
||||
|
||||
session->calls[call->friend_id] = NULL;
|
||||
session->calls[call->friend_number] = NULL;
|
||||
free(call);
|
||||
return;
|
||||
|
||||
|
@ -579,17 +579,17 @@ CLEAR_CONTAINER:
|
|||
free(call);
|
||||
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;
|
||||
MSISession *session = data;
|
||||
|
||||
switch ( status ) {
|
||||
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);
|
||||
MSICall* call = get_call(session, friend_id);
|
||||
MSICall* call = get_call(session, friend_number);
|
||||
|
||||
if (call == NULL) {
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
|
@ -610,9 +610,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
|
|||
{
|
||||
assert(call);
|
||||
|
||||
MSISession* session = call->session;
|
||||
|
||||
LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_id);
|
||||
LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_number);
|
||||
|
||||
if (!msg->capabilities.exists) {
|
||||
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.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
|
||||
* be handled accordingly during the next step
|
||||
|
@ -708,14 +706,14 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
|
|||
return;
|
||||
|
||||
FAILURE:
|
||||
send_error(call->session->messenger, call->friend_id, call->error);
|
||||
send_error(call->session->messenger, call->friend_number, call->error);
|
||||
kill_call(call);
|
||||
}
|
||||
void handle_pop ( MSICall *call, const MSIMessage *msg )
|
||||
{
|
||||
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 */
|
||||
|
||||
|
@ -751,7 +749,7 @@ void handle_pop ( MSICall *call, const MSIMessage *msg )
|
|||
|
||||
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");
|
||||
|
||||
|
@ -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 ) {
|
||||
LOGGER_WARNING("Error parsing message");
|
||||
send_error(m, friend_id, msi_EInvalidMessage);
|
||||
send_error(m, friend_number, msi_EInvalidMessage);
|
||||
return;
|
||||
} else {
|
||||
LOGGER_DEBUG("Successfully parsed message");
|
||||
}
|
||||
|
||||
pthread_mutex_lock(session->mutex);
|
||||
MSICall *call = get_call(session, friend_id);
|
||||
MSICall *call = get_call(session, friend_number);
|
||||
|
||||
if (call == NULL) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
call = new_call(session, friend_id);
|
||||
call = new_call(session, friend_number);
|
||||
if (call == NULL) {
|
||||
send_error(m, friend_id, msi_ESystem);
|
||||
send_error(m, friend_number, msi_ESystem);
|
||||
pthread_mutex_unlock(session->mutex);
|
||||
return;
|
||||
}
|
||||
|
|
24
toxav/msi.h
24
toxav/msi.h
|
@ -89,7 +89,7 @@ typedef struct MSICall_s {
|
|||
uint8_t peer_capabilities; /* Peer capabilities */
|
||||
uint8_t self_capabilities; /* Self capabilities */
|
||||
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 */
|
||||
|
||||
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
|
||||
* returned the call is considered errored and will be handled
|
||||
* 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
|
||||
|
@ -119,43 +118,34 @@ typedef struct MSISession_s {
|
|||
void *av;
|
||||
Messenger *messenger;
|
||||
|
||||
/* The mutex controls async access from control
|
||||
* thread(s) and core thread.
|
||||
*/
|
||||
pthread_mutex_t mutex[1];
|
||||
MSICallbackType callbacks[7];
|
||||
msi_action_cb* callbacks[7];
|
||||
} MSISession;
|
||||
|
||||
/**
|
||||
* Start the control session.
|
||||
*/
|
||||
MSISession *msi_new ( Messenger *messenger );
|
||||
|
||||
MSISession *msi_new ( Messenger *m );
|
||||
/**
|
||||
* Terminate control session. NOTE: all calls will be freed
|
||||
*/
|
||||
int msi_kill ( MSISession *session );
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
int msi_hangup ( MSICall* call );
|
||||
|
||||
/**
|
||||
* Answer call request.
|
||||
*/
|
||||
int msi_answer ( MSICall* call, uint8_t capabilities );
|
||||
|
||||
/**
|
||||
* Change capabilities of the call.
|
||||
*/
|
||||
|
|
59
toxav/rtp.c
59
toxav/rtp.c
|
@ -78,11 +78,11 @@ int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *dat
|
|||
void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
|
||||
|
||||
|
||||
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(cs);
|
||||
assert(messenger);
|
||||
assert(m);
|
||||
|
||||
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->payload_type = payload_type % 128;
|
||||
|
||||
retu->m = messenger;
|
||||
retu->friend_id = friend_num;
|
||||
retu->m = m;
|
||||
retu->friend_number = friend_num;
|
||||
|
||||
if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) {
|
||||
LOGGER_WARNING("Alloc failed! Program might misbehave!");
|
||||
|
@ -161,7 +161,7 @@ int rtp_do(RTPSession *session)
|
|||
return rtp_StateNormal;
|
||||
|
||||
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)) {
|
||||
|
@ -209,15 +209,15 @@ int rtp_start_receiving(RTPSession* session)
|
|||
if (session == NULL)
|
||||
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) {
|
||||
LOGGER_WARNING("Failed to register rtp receive handler");
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -228,8 +228,8 @@ int rtp_stop_receiving(RTPSession* session)
|
|||
if (session == NULL)
|
||||
return -1;
|
||||
|
||||
m_callback_rtp_packet(session->m, session->friend_id, 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->prefix, NULL, NULL);
|
||||
m_callback_rtp_packet(session->m, session->friend_number, session->rtcp_session->prefix, NULL, NULL); /* RTCP */
|
||||
|
||||
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 *it;
|
||||
|
||||
RTPHeader header[1];
|
||||
RTPHeader header[1] = {0};
|
||||
|
||||
ADD_FLAG_VERSION ( header, session->version );
|
||||
ADD_FLAG_PADDING ( header, session->padding );
|
||||
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);
|
||||
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set sequ number */
|
||||
session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -300,7 +300,6 @@ void rtp_free_msg ( RTPMessage *msg )
|
|||
|
||||
|
||||
|
||||
|
||||
RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
||||
{
|
||||
if ( !payload || !length ) {
|
||||
|
@ -323,11 +322,6 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
|||
retu->flags = *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 ) {
|
||||
/* Deallocate */
|
||||
LOGGER_WARNING("Invalid version!");
|
||||
|
@ -335,15 +329,10 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
|||
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 );
|
||||
int total = 12 /* Minimum header len */ + ( cc * 4 );
|
||||
|
||||
if ( length < total ) {
|
||||
/* Deallocate */
|
||||
LOGGER_WARNING("Length invalid!");
|
||||
free(retu);
|
||||
return NULL;
|
||||
|
@ -355,9 +344,10 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
|
|||
|
||||
|
||||
memcpy(&retu->timestamp, it, sizeof(retu->timestamp));
|
||||
retu->timestamp = ntohl(retu->timestamp);
|
||||
it += 4;
|
||||
memcpy(&retu->ssrc, it, sizeof(retu->ssrc));
|
||||
|
||||
retu->timestamp = ntohl(retu->timestamp);
|
||||
retu->ssrc = ntohl(retu->ssrc);
|
||||
|
||||
uint8_t x;
|
||||
|
@ -380,34 +370,31 @@ RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
uint16_t ext_length;
|
||||
memcpy(&ext_length, it, sizeof(ext_length));
|
||||
ext_length = ntohs(ext_length);
|
||||
memcpy(&retu->length, it, sizeof(retu->length));
|
||||
retu->length = ntohs(retu->length);
|
||||
it += 2;
|
||||
|
||||
|
||||
if ( length < ( ext_length * sizeof(uint32_t) ) ) {
|
||||
if ( length < ( retu->length * sizeof(uint32_t) ) ) {
|
||||
LOGGER_WARNING("Length invalid!");
|
||||
free(retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retu->length = ext_length;
|
||||
memcpy(&retu->type, it, sizeof(retu->type));
|
||||
retu->type = ntohs(retu->type);
|
||||
|
||||
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!");
|
||||
free(retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint16_t x;
|
||||
|
||||
for ( x = 0; x < ext_length; x++ ) {
|
||||
for ( x = 0; x < retu->length; x++ ) {
|
||||
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]);
|
||||
}
|
||||
|
||||
|
@ -433,7 +420,6 @@ uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload )
|
|||
*it = header->marker_payloadt;
|
||||
++it;
|
||||
|
||||
|
||||
timestamp = htonl(header->timestamp);
|
||||
memcpy(it, ×tamp, sizeof(timestamp));
|
||||
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->expected_packets = ntohl(report->expected_packets);
|
||||
|
||||
/* Invalid values */
|
||||
if (report->expected_packets == 0 || report->received_packets > report->expected_packets) {
|
||||
LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets);
|
||||
free(report);
|
||||
|
|
11
toxav/rtp.h
11
toxav/rtp.h
|
@ -113,10 +113,9 @@ typedef struct {
|
|||
uint8_t prefix;
|
||||
|
||||
Messenger *m;
|
||||
int friend_id;
|
||||
int friend_number;
|
||||
struct RTCPSession_s *rtcp_session;
|
||||
|
||||
|
||||
void *cs;
|
||||
int (*mcb) (void*, RTPMessage* msg);
|
||||
|
||||
|
@ -125,33 +124,27 @@ typedef struct {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
void rtp_kill ( RTPSession* session );
|
||||
|
||||
/**
|
||||
* Do periodical rtp work.
|
||||
*/
|
||||
int rtp_do(RTPSession *session);
|
||||
|
||||
/**
|
||||
* By default rtp is in receiving state
|
||||
*/
|
||||
int rtp_start_receiving (RTPSession *session);
|
||||
|
||||
/**
|
||||
* Pause rtp receiving mode.
|
||||
*/
|
||||
int rtp_stop_receiving (RTPSession *session);
|
||||
|
||||
/**
|
||||
* Sends msg to RTPSession::dest
|
||||
*/
|
||||
int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy );
|
||||
|
||||
/**
|
||||
* Dealloc msg.
|
||||
*/
|
||||
|
|
132
toxav/toxav.c
132
toxav/toxav.c
|
@ -58,10 +58,10 @@ typedef struct ToxAVCall_s {
|
|||
|
||||
bool active;
|
||||
MSICall* msi_call;
|
||||
uint32_t friend_id;
|
||||
uint32_t friend_number;
|
||||
|
||||
uint32_t audio_bit_rate; /* Sending audio bitrate */
|
||||
uint32_t video_bit_rate; /* Sending video bitrate */
|
||||
uint32_t audio_bit_rate; /* Sending audio bit rate */
|
||||
uint32_t video_bit_rate; /* Sending video bit rate */
|
||||
|
||||
ToxAvBitrateAdapter aba;
|
||||
ToxAvBitrateAdapter vba;
|
||||
|
@ -93,8 +93,8 @@ struct toxAV {
|
|||
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_video_frame_cb *, void *) vcb; /* Video frame receive callback */
|
||||
PAIR(toxav_audio_bitrate_control_cb *, void *) abcb; /* Audio bitrate control callback */
|
||||
PAIR(toxav_video_bitrate_control_cb *, void *) vbcb; /* Video bitrate control callback */
|
||||
PAIR(toxav_audio_bit_rate_status_cb *, void *) abcb; /* Audio bit rate control callback */
|
||||
PAIR(toxav_video_bit_rate_status_cb *, void *) vbcb; /* Video bit rate control callback */
|
||||
|
||||
/** Decode time measures */
|
||||
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_capabilites(void* toxav_inst, MSICall* call);
|
||||
|
||||
bool audio_bitrate_invalid(uint32_t bitrate);
|
||||
bool video_bitrate_invalid(uint32_t bitrate);
|
||||
bool audio_bit_rate_invalid(uint32_t bit_rate);
|
||||
bool video_bit_rate_invalid(uint32_t bit_rate);
|
||||
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_get(ToxAV* av, uint32_t friend_number);
|
||||
|
@ -129,12 +129,12 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
|||
|
||||
if (tox == NULL) {
|
||||
rc = TOXAV_ERR_NEW_NULL;
|
||||
goto FAILURE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
if (((Messenger*)tox)->msi_packet) {
|
||||
rc = TOXAV_ERR_NEW_MULTIPLE;
|
||||
goto FAILURE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
av = calloc (sizeof(ToxAV), 1);
|
||||
|
@ -142,13 +142,13 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
|||
if (av == NULL) {
|
||||
LOGGER_WARNING("Allocation failed!");
|
||||
rc = TOXAV_ERR_NEW_MALLOC;
|
||||
goto FAILURE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
if (create_recursive_mutex(av->mutex) != 0) {
|
||||
LOGGER_WARNING("Mutex creation failed!");
|
||||
rc = TOXAV_ERR_NEW_MALLOC;
|
||||
goto FAILURE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
av->m = (Messenger *)tox;
|
||||
|
@ -157,7 +157,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
|
|||
if (av->msi == NULL) {
|
||||
pthread_mutex_destroy(av->mutex);
|
||||
rc = TOXAV_ERR_NEW_MALLOC;
|
||||
goto FAILURE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
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_capabilites, msi_OnCapabilities);
|
||||
|
||||
|
||||
END:
|
||||
if (error)
|
||||
*error = rc;
|
||||
|
||||
if (rc != TOXAV_ERR_NEW_OK) {
|
||||
free(av);
|
||||
av = NULL;
|
||||
}
|
||||
|
||||
return av;
|
||||
|
||||
FAILURE:
|
||||
if (error)
|
||||
*error = rc;
|
||||
|
||||
free(av);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void toxav_kill(ToxAV* av)
|
||||
|
@ -249,14 +246,14 @@ void toxav_iterate(ToxAV* av)
|
|||
|
||||
/* Notify app */
|
||||
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()) {
|
||||
|
||||
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)
|
||||
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 */
|
||||
memset(&i->aba, 0, sizeof(i->aba));
|
||||
|
@ -275,15 +272,15 @@ void toxav_iterate(ToxAV* av)
|
|||
|
||||
/* Notify app */
|
||||
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()) {
|
||||
|
||||
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)
|
||||
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 */
|
||||
memset(&i->vba, 0, sizeof(i->vba));
|
||||
|
@ -297,7 +294,7 @@ void toxav_iterate(ToxAV* av)
|
|||
i->msi_call->peer_capabilities & msi_CapSVideo)
|
||||
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_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.second = user_data;
|
||||
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)
|
||||
{
|
||||
|
@ -368,8 +365,8 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui
|
|||
goto END;
|
||||
}
|
||||
|
||||
if ((audio_bit_rate && audio_bitrate_invalid(audio_bit_rate))
|
||||
||(video_bit_rate && video_bitrate_invalid(video_bit_rate))
|
||||
if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))
|
||||
||(video_bit_rate && video_bit_rate_invalid(video_bit_rate))
|
||||
) {
|
||||
rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
|
||||
goto END;
|
||||
|
@ -561,7 +558,7 @@ END:
|
|||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
if (video_bitrate_invalid(video_bit_rate)) {
|
||||
if (video_bit_rate_invalid(video_bit_rate)) {
|
||||
rc = TOXAV_ERR_BIT_RATE_INVALID;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
@ -618,7 +615,7 @@ END:
|
|||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
if (audio_bitrate_invalid(audio_bit_rate)) {
|
||||
if (audio_bit_rate_invalid(audio_bit_rate)) {
|
||||
rc = TOXAV_ERR_BIT_RATE_INVALID;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
@ -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)) {
|
||||
sampling_rate = ntohl(sampling_rate);
|
||||
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);
|
||||
rc = TOXAV_ERR_SEND_FRAME_INVALID;
|
||||
goto END;
|
||||
|
@ -966,7 +963,7 @@ int callback_invite(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
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) {
|
||||
LOGGER_WARNING("Failed to initialize call...");
|
||||
pthread_mutex_unlock(toxav->mutex);
|
||||
|
@ -977,7 +974,7 @@ int callback_invite(void* toxav_inst, MSICall* call)
|
|||
av_call->msi_call = call;
|
||||
|
||||
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);
|
||||
|
||||
pthread_mutex_unlock(toxav->mutex);
|
||||
|
@ -989,7 +986,7 @@ int callback_start(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
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) {
|
||||
/* Should this ever happen? */
|
||||
|
@ -1004,7 +1001,7 @@ int callback_start(void* toxav_inst, MSICall* call)
|
|||
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);
|
||||
return 0;
|
||||
|
@ -1015,7 +1012,7 @@ int callback_end(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
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_remove(call->av_call);
|
||||
|
@ -1029,7 +1026,7 @@ int callback_error(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
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_remove(call->av_call);
|
||||
|
@ -1043,21 +1040,21 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
|
|||
ToxAV* toxav = toxav_inst;
|
||||
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);
|
||||
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 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 */
|
||||
return false;
|
||||
|
@ -1099,7 +1096,7 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
|
|||
}
|
||||
|
||||
call->av = av;
|
||||
call->friend_id = friend_number;
|
||||
call->friend_number = friend_number;
|
||||
|
||||
if (av->calls == NULL) { /* Creating */
|
||||
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;
|
||||
|
||||
/* Set fields in between to null */
|
||||
int32_t i = av->calls_tail;
|
||||
int32_t i = av->calls_tail + 1;
|
||||
for (; i < friend_number; i ++)
|
||||
av->calls[i] = NULL;
|
||||
|
||||
|
@ -1164,7 +1161,7 @@ void call_remove(ToxAVCall* call)
|
|||
if (call == NULL)
|
||||
return;
|
||||
|
||||
uint32_t friend_id = call->friend_id;
|
||||
uint32_t friend_number = call->friend_number;
|
||||
ToxAV* av = call->av;
|
||||
|
||||
ToxAVCall* prev = call->prev;
|
||||
|
@ -1175,16 +1172,16 @@ void call_remove(ToxAVCall* call)
|
|||
if (prev)
|
||||
prev->next = next;
|
||||
else if (next)
|
||||
av->calls_head = next->friend_id;
|
||||
av->calls_head = next->friend_number;
|
||||
else goto CLEAR;
|
||||
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
else if (prev)
|
||||
av->calls_tail = prev->friend_id;
|
||||
av->calls_tail = prev->friend_number;
|
||||
else goto CLEAR;
|
||||
|
||||
av->calls[friend_id] = NULL;
|
||||
av->calls[friend_number] = NULL;
|
||||
return;
|
||||
|
||||
CLEAR:
|
||||
|
@ -1214,17 +1211,16 @@ bool call_prepare_transmission(ToxAVCall* call)
|
|||
if (create_recursive_mutex(call->mutex_audio) != 0)
|
||||
return false;
|
||||
|
||||
if (create_recursive_mutex(call->mutex_video) != 0) {
|
||||
goto AUDIO_SENDING_MUTEX_CLEANUP;
|
||||
}
|
||||
if (create_recursive_mutex(call->mutex_video) != 0)
|
||||
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 */
|
||||
call->audio.second = ac_new(av, call->friend_id, 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.second = ac_new(av, call->friend_number, av->acb.first, av->acb.second);
|
||||
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 ) {
|
||||
LOGGER_ERROR("Error while starting audio!\n");
|
||||
|
@ -1233,8 +1229,8 @@ bool call_prepare_transmission(ToxAVCall* call)
|
|||
}
|
||||
|
||||
{ /* Prepare video */
|
||||
call->video.second = vc_new(av, call->friend_id, 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.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_number, call->video.second, vc_queue_message);
|
||||
|
||||
if ( !call->video.first || !call->video.second ) {
|
||||
LOGGER_ERROR("Error while starting video!\n");
|
||||
|
@ -1255,9 +1251,9 @@ FAILURE:
|
|||
call->video.first = NULL;
|
||||
call->video.second = NULL;
|
||||
pthread_mutex_destroy(call->mutex);
|
||||
VIDEO_SENDING_MUTEX_CLEANUP:
|
||||
FAILURE_2:
|
||||
pthread_mutex_destroy(call->mutex_video);
|
||||
AUDIO_SENDING_MUTEX_CLEANUP:
|
||||
FAILURE_3:
|
||||
pthread_mutex_destroy(call->mutex_audio);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -333,23 +333,23 @@ typedef enum TOXAV_ERR_BIT_RATE {
|
|||
TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL
|
||||
} 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
|
||||
* audio bit rate.
|
||||
* @param good Is the stream good enough to keep the said bitrate. Upon failed
|
||||
* non forceful bit rate setup this will be set to false and 'bit_rate'
|
||||
* will be set to the bit rate that failed, otherwise 'good' will be set to
|
||||
* true with 'bit_rate' set to new bit rate. If the stream becomes bad,
|
||||
* the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
|
||||
* This callback will never be called when the stream is good.
|
||||
* @param stable Is the stream stable enough to keep the bit rate.
|
||||
* Upon successful, non forceful, bit rate change, this is set to
|
||||
* true and 'bit_rate' is set to new bit rate.
|
||||
* The stable is set to false with bit_rate set to the unstable
|
||||
* bit rate when either current stream is unstable with said bit rate
|
||||
* or the non forceful change failed.
|
||||
* @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.
|
||||
*
|
||||
|
@ -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);
|
||||
/**
|
||||
* 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
|
||||
* video bit rate.
|
||||
* @param good Is the stream good enough to keep the said bitrate. Upon failed
|
||||
* non forceful bit rate setup this will be set to false and 'bit_rate'
|
||||
* will be set to the bit rate that failed, otherwise 'good' will be set to
|
||||
* true with 'bit_rate' set to new bit rate. If the stream becomes bad,
|
||||
* the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
|
||||
* This callback will never be called when the stream is good.
|
||||
* @param stable Is the stream stable enough to keep the bit rate.
|
||||
* Upon successful, non forceful, bit rate change, this is set to
|
||||
* true and 'bit_rate' is set to new bit rate.
|
||||
* The stable is set to false with bit_rate set to the unstable
|
||||
* bit rate when either current stream is unstable with said bit rate
|
||||
* or the non forceful change failed.
|
||||
* @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.
|
||||
*
|
||||
|
|
|
@ -35,15 +35,14 @@
|
|||
#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
|
||||
#define VIDEOFRAME_HEADER_SIZE 0x2
|
||||
|
||||
/* FIXME: Might not be enough? NOTE: I think it is enough */
|
||||
#define VIDEO_DECODE_BUFFER_SIZE 20
|
||||
|
||||
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);
|
||||
|
||||
|
@ -86,7 +85,7 @@ VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* c
|
|||
vc->lcfd = 60;
|
||||
vc->vcb.first = cb;
|
||||
vc->vcb.second = cb_data;
|
||||
vc->friend_id = friend_id;
|
||||
vc->friend_number = friend_number;
|
||||
vc->peer_video_frame_piece_size = mvfpsz;
|
||||
|
||||
return vc;
|
||||
|
@ -140,7 +139,7 @@ void vc_do(VCSession* vc)
|
|||
/* Play decoded images */
|
||||
for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {
|
||||
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],
|
||||
dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second);
|
||||
|
||||
|
@ -289,16 +288,16 @@ end:
|
|||
rtp_free_msg(msg);
|
||||
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)
|
||||
return -1;
|
||||
|
||||
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 */
|
||||
|
||||
cfg.rc_target_bitrate = bitrate;
|
||||
cfg.rc_target_bitrate = bit_rate;
|
||||
cfg.g_w = width;
|
||||
cfg.g_h = height;
|
||||
|
||||
|
@ -310,16 +309,16 @@ int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint1
|
|||
|
||||
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)
|
||||
return -1;
|
||||
|
||||
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 */
|
||||
|
||||
cfg.rc_target_bitrate = bitrate;
|
||||
cfg.rc_target_bitrate = bit_rate;
|
||||
cfg.g_w = width;
|
||||
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);
|
||||
|
||||
|
@ -354,7 +353,7 @@ bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate)
|
|||
return false;
|
||||
}
|
||||
|
||||
cfg.rc_target_bitrate = bitrate;
|
||||
cfg.rc_target_bitrate = bit_rate;
|
||||
cfg.g_w = 800;
|
||||
cfg.g_h = 600;
|
||||
cfg.g_pass = VPX_RC_ONE_PASS;
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
|
||||
struct RTPMessage_s;
|
||||
|
||||
/*
|
||||
* Base Video Codec session type.
|
||||
*/
|
||||
typedef struct VCSession_s {
|
||||
|
||||
/* encoding */
|
||||
|
@ -65,23 +68,46 @@ typedef struct VCSession_s {
|
|||
const uint8_t *processing_video_frame;
|
||||
uint16_t processing_video_frame_size;
|
||||
|
||||
|
||||
ToxAV *av;
|
||||
int32_t friend_id;
|
||||
uint32_t friend_number;
|
||||
|
||||
PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
|
||||
|
||||
pthread_mutex_t queue_mutex[1];
|
||||
} 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);
|
||||
/*
|
||||
* Do periodic work. Work is consisted out of decoding only.
|
||||
*/
|
||||
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);
|
||||
/*
|
||||
* Update the video splitter cycle with new data.
|
||||
*/
|
||||
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);
|
||||
/*
|
||||
* Queue new rtp message.
|
||||
*/
|
||||
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 */
|
Loading…
Reference in New Issue
Block a user