mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Improved protocol and cleaned code a bit
This commit is contained in:
parent
77c7a3e103
commit
1aeeef58b2
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -53,6 +53,10 @@ libtool
|
||||||
.deps
|
.deps
|
||||||
.libs
|
.libs
|
||||||
.dirstamp
|
.dirstamp
|
||||||
|
build/
|
||||||
|
|
||||||
|
#kdevelop
|
||||||
|
*.kdev*
|
||||||
|
|
||||||
# Netbeans
|
# Netbeans
|
||||||
nbproject
|
nbproject
|
||||||
|
|
|
@ -31,7 +31,8 @@ typedef enum _CallStatus {
|
||||||
Ringing,
|
Ringing,
|
||||||
Ended,
|
Ended,
|
||||||
Rejected,
|
Rejected,
|
||||||
Cancel
|
Cancel,
|
||||||
|
TimedOut
|
||||||
|
|
||||||
} CallStatus;
|
} CallStatus;
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *dat
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void callback_recv_invite ( int32_t call_index, void *_arg )
|
void callback_recv_invite ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
@ -67,23 +68,23 @@ void callback_recv_invite ( int32_t call_index, void *_arg )
|
||||||
cast->Bob.status = Ringing;
|
cast->Bob.status = Ringing;
|
||||||
cast->Bob.call_index = call_index;
|
cast->Bob.call_index = call_index;
|
||||||
}
|
}
|
||||||
void callback_recv_ringing ( int32_t call_index, void *_arg )
|
void callback_recv_ringing ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Alice always sends invite */
|
/* Alice always sends invite */
|
||||||
cast->Alice.status = Ringing;
|
cast->Alice.status = Ringing;
|
||||||
}
|
}
|
||||||
void callback_recv_starting ( int32_t call_index, void *_arg )
|
void callback_recv_starting ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Alice always sends invite */
|
/* Alice always sends invite */
|
||||||
printf("Call started on Alice side...\n");
|
printf("Call started on Alice side...\n");
|
||||||
cast->Alice.status = InCall;
|
cast->Alice.status = InCall;
|
||||||
toxav_prepare_transmission(cast->Alice.av, call_index, &muhcaps, 1);
|
toxav_prepare_transmission(av, call_index, &muhcaps, 1);
|
||||||
}
|
}
|
||||||
void callback_recv_ending ( int32_t call_index, void *_arg )
|
void callback_recv_ending ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
@ -96,28 +97,24 @@ void callback_recv_ending ( int32_t call_index, void *_arg )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_recv_error ( int32_t call_index, void *_arg )
|
|
||||||
{
|
|
||||||
ck_assert_msg(0, "AV internal error");
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_call_started ( int32_t call_index, void *_arg )
|
void callback_call_started ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
/* Alice always sends invite */
|
/* Alice always sends invite */
|
||||||
printf("Call started on Bob side...\n");
|
printf("Call started on Bob side...\n");
|
||||||
cast->Bob.status = InCall;
|
cast->Bob.status = InCall;
|
||||||
toxav_prepare_transmission(cast->Bob.av, call_index, &muhcaps, 1);
|
toxav_prepare_transmission(av, call_index, &muhcaps, 1);
|
||||||
}
|
}
|
||||||
void callback_call_canceled ( int32_t call_index, void *_arg )
|
void callback_call_canceled ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
printf ( "Call Canceled for Bob!\n" );
|
printf ( "Call Canceled for Bob!\n" );
|
||||||
cast->Bob.status = Cancel;
|
cast->Bob.status = Cancel;
|
||||||
}
|
}
|
||||||
void callback_call_rejected ( int32_t call_index, void *_arg )
|
void callback_call_rejected ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
@ -126,7 +123,7 @@ void callback_call_rejected ( int32_t call_index, void *_arg )
|
||||||
/* If Bob rejects, call is ended for alice and she sends ending */
|
/* If Bob rejects, call is ended for alice and she sends ending */
|
||||||
cast->Alice.status = Rejected;
|
cast->Alice.status = Rejected;
|
||||||
}
|
}
|
||||||
void callback_call_ended ( int32_t call_index, void *_arg )
|
void callback_call_ended ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
|
@ -134,14 +131,50 @@ void callback_call_ended ( int32_t call_index, void *_arg )
|
||||||
cast->Bob.status = Ended;
|
cast->Bob.status = Ended;
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_requ_timeout ( int32_t call_index, void *_arg )
|
void callback_call_type_change ( void *av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
ck_assert_msg(0, "No answer!");
|
printf("Call type changed; new type: %s!\n", toxav_get_peer_transmission_type
|
||||||
|
(av, call_index, 0) == TypeAudio ? "audio" : "video");
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback_requ_timeout ( void *av, int32_t call_index, void *_arg )
|
||||||
|
{
|
||||||
|
Status *cast = _arg;
|
||||||
|
printf("Call timed-out!");
|
||||||
|
cast->Alice.status = TimedOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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_recv_starting, av_OnStarting, data);
|
||||||
|
toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data);
|
||||||
|
|
||||||
|
toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
|
||||||
|
toxav_register_callstate_callback(av, callback_call_type_change, av_OnMediaChange, data);
|
||||||
|
|
||||||
|
|
||||||
|
toxav_register_audio_recv_callback(av, callback_audio);
|
||||||
|
toxav_register_video_recv_callback(av, callback_video);
|
||||||
}
|
}
|
||||||
/*************************************************************************************************/
|
/*************************************************************************************************/
|
||||||
|
|
||||||
/* Alice calls bob and the call starts.
|
/* Alice calls bob and the call starts.
|
||||||
* What happens in the call is defined after. To quit the loop use: step++;
|
* What happens during the call is defined after. To quit the loop use: step++;
|
||||||
*/
|
*/
|
||||||
#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \
|
#define CALL_AND_START_LOOP(AliceCallType, BobCallType) \
|
||||||
{ int step = 0, running = 1; while (running) {\
|
{ int step = 0, running = 1; while (running) {\
|
||||||
|
@ -199,7 +232,7 @@ START_TEST(test_AV_flows)
|
||||||
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
printf("All set after %llu seconds! Starting call...\n", time(NULL) - cur_time);
|
||||||
|
|
||||||
muhcaps = av_DefaultSettings;
|
muhcaps = av_DefaultSettings;
|
||||||
muhcaps.video_height = muhcaps.video_width = 128;
|
muhcaps.max_video_height = muhcaps.max_video_width = 128;
|
||||||
|
|
||||||
Status status_control = {
|
Status status_control = {
|
||||||
{none, toxav_new(Alice, 1), NULL, -1},
|
{none, toxav_new(Alice, 1), NULL, -1},
|
||||||
|
@ -209,19 +242,8 @@ START_TEST(test_AV_flows)
|
||||||
ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
|
ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances");
|
||||||
|
|
||||||
|
|
||||||
toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control);
|
register_callbacks(status_control.Alice.av, &status_control);
|
||||||
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control);
|
register_callbacks(status_control.Bob.av, &status_control);
|
||||||
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
|
|
||||||
|
|
||||||
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
|
|
||||||
|
|
||||||
toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
|
|
||||||
|
|
||||||
|
|
||||||
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
||||||
int16_t sample_payload[frame_size];
|
int16_t sample_payload[frame_size];
|
||||||
|
@ -266,23 +288,6 @@ START_TEST(test_AV_flows)
|
||||||
|
|
||||||
toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
|
toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size);
|
||||||
|
|
||||||
/* Both receive */
|
|
||||||
int16_t storage[frame_size];
|
|
||||||
int recved;
|
|
||||||
|
|
||||||
/* Payload from Bob */
|
|
||||||
recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
|
@ -320,38 +325,6 @@ START_TEST(test_AV_flows)
|
||||||
|
|
||||||
// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
|
// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
|
||||||
|
|
||||||
/* Both receive */
|
|
||||||
int16_t storage[frame_size];
|
|
||||||
vpx_image_t *video_storage;
|
|
||||||
int recved;
|
|
||||||
|
|
||||||
/* Payload from Bob */
|
|
||||||
recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Video payload */
|
|
||||||
// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
|
|
||||||
//
|
|
||||||
// if ( video_storage ) {
|
|
||||||
// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
|
||||||
// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
|
||||||
// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
|
|
||||||
// vpx_img_free(video_storage);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Payload from Alice */
|
|
||||||
recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
|
||||||
|
@ -391,48 +364,6 @@ START_TEST(test_AV_flows)
|
||||||
// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image);
|
// 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);
|
// toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
|
||||||
|
|
||||||
/* Both receive */
|
|
||||||
int16_t storage[frame_size];
|
|
||||||
vpx_image_t *video_storage;
|
|
||||||
int recved;
|
|
||||||
|
|
||||||
/* Payload from Bob */
|
|
||||||
recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Video payload */
|
|
||||||
// toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
|
|
||||||
//
|
|
||||||
// if ( video_storage ) {
|
|
||||||
// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
|
||||||
// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
|
||||||
// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Bob is invalid");*/
|
|
||||||
// vpx_img_free(video_storage);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Payload from Alice */
|
|
||||||
recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Video payload */
|
|
||||||
// toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage);
|
|
||||||
//
|
|
||||||
// if ( video_storage ) {
|
|
||||||
// /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
|
|
||||||
// memcmp(video_storage->planes[VPX_PLANE_U], sample_payload, 10) == 0 ||
|
|
||||||
// memcmp(video_storage->planes[VPX_PLANE_V], sample_payload, 10) == 0 , "Payload from Alice is invalid");*/
|
|
||||||
// vpx_img_free(video_storage);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
|
@ -446,6 +377,47 @@ START_TEST(test_AV_flows)
|
||||||
TERMINATE_SCOPE()
|
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);
|
||||||
|
toxav_change_type(status_control.Alice.av, status_control.Alice.call_index,
|
||||||
|
toxav_get_peer_transmission_type(status_control.Bob.av, status_control.Bob.call_index, 0)
|
||||||
|
== TypeAudio ? TypeVideo : TypeAudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* Other flows
|
||||||
|
@ -510,7 +482,7 @@ START_TEST(test_AV_flows)
|
||||||
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
|
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
|
||||||
step++;
|
step++;
|
||||||
break;
|
break;
|
||||||
\
|
|
||||||
|
|
||||||
case 1: /* Alice again */
|
case 1: /* Alice again */
|
||||||
if (status_control.Bob.status == Ringing) {
|
if (status_control.Bob.status == Ringing) {
|
||||||
|
@ -533,6 +505,37 @@ START_TEST(test_AV_flows)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timeout
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int step = 0;
|
||||||
|
int running = 1;
|
||||||
|
while (running) {
|
||||||
|
tox_do(bootstrap_node);
|
||||||
|
tox_do(Alice);
|
||||||
|
tox_do(Bob);
|
||||||
|
|
||||||
|
switch ( step ) {
|
||||||
|
case 0:
|
||||||
|
printf("Alice is calling...\n");
|
||||||
|
toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
|
||||||
|
step++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if (status_control.Alice.status == TimedOut) running = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_sleep(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
printf("Calls ended!\n");
|
printf("Calls ended!\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define c_sleep(x) usleep(1000*x)
|
#define c_sleep(x) usleep(1000*x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
pthread_mutex_t muhmutex;
|
||||||
|
|
||||||
typedef enum _CallStatus {
|
typedef enum _CallStatus {
|
||||||
none,
|
none,
|
||||||
|
@ -43,6 +44,7 @@ typedef struct _Party {
|
||||||
|
|
||||||
typedef struct _ACall {
|
typedef struct _ACall {
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
|
int idx;
|
||||||
|
|
||||||
Party Caller;
|
Party Caller;
|
||||||
Party Callee;
|
Party Callee;
|
||||||
|
@ -52,6 +54,8 @@ typedef struct _Status {
|
||||||
ACall calls[3]; /* Make 3 calls for this test */
|
ACall calls[3]; /* Make 3 calls for this test */
|
||||||
} Status;
|
} Status;
|
||||||
|
|
||||||
|
Status status_control;
|
||||||
|
|
||||||
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
|
void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
|
||||||
{
|
{
|
||||||
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
|
||||||
|
@ -61,58 +65,49 @@ void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *dat
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
void callback_recv_invite ( int32_t call_index, void *_arg )
|
void callback_recv_invite ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Callee.status = Ringing;*/
|
cast->calls[call_index].Callee.status = Ringing;*/
|
||||||
}
|
}
|
||||||
void callback_recv_ringing ( int32_t call_index, void *_arg )
|
void callback_recv_ringing ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Caller.status = Ringing;
|
cast->calls[call_index].Caller.status = Ringing;
|
||||||
}
|
}
|
||||||
void callback_recv_starting ( int32_t call_index, void *_arg )
|
void callback_recv_starting ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Caller.status = InCall;
|
cast->calls[call_index].Caller.status = InCall;
|
||||||
}
|
}
|
||||||
void callback_recv_ending ( int32_t call_index, void *_arg )
|
void callback_recv_ending ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Caller.status = Ended;
|
cast->calls[call_index].Caller.status = Ended;
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_recv_error ( int32_t call_index, void *_arg )
|
void callback_call_started ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
|
||||||
ck_assert_msg(0, "AV internal error");
|
|
||||||
}
|
|
||||||
|
|
||||||
void callback_call_started ( int32_t call_index, void *_arg )
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Callee.status = InCall;*/
|
cast->calls[call_index].Callee.status = InCall;*/
|
||||||
}
|
}
|
||||||
void callback_call_canceled ( int32_t call_index, void *_arg )
|
void callback_call_canceled ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Callee.status = Cancel;*/
|
cast->calls[call_index].Callee.status = Cancel;*/
|
||||||
}
|
}
|
||||||
void callback_call_rejected ( int32_t call_index, void *_arg )
|
void callback_call_rejected ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
|
||||||
cast->calls[call_index].Caller.status = Rejected;
|
cast->calls[call_index].Caller.status = Rejected;
|
||||||
}
|
}
|
||||||
void callback_call_ended ( int32_t call_index, void *_arg )
|
void callback_call_ended ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Status *cast = _arg;
|
Status *cast = _arg;
|
||||||
|
@ -120,12 +115,40 @@ void callback_call_ended ( int32_t call_index, void *_arg )
|
||||||
cast->calls[call_index].Callee.status = Ended;*/
|
cast->calls[call_index].Callee.status = Ended;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_requ_timeout ( int32_t call_index, void *_arg )
|
void callback_requ_timeout ( void* av, int32_t call_index, void *_arg )
|
||||||
{
|
{
|
||||||
ck_assert_msg(0, "No answer!");
|
ck_assert_msg(0, "No answer!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void callback_audio(ToxAv *av, int32_t call_index, int16_t *data, int length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback_video(ToxAv *av, int32_t call_index, vpx_image_t *img)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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_recv_starting, av_OnStarting, data);
|
||||||
|
toxav_register_callstate_callback(av, callback_recv_ending, av_OnEnding, data);
|
||||||
|
|
||||||
|
toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
|
||||||
|
|
||||||
|
|
||||||
|
toxav_register_audio_recv_callback(av, callback_audio);
|
||||||
|
toxav_register_video_recv_callback(av, callback_video);
|
||||||
|
}
|
||||||
/*************************************************************************************************/
|
/*************************************************************************************************/
|
||||||
|
|
||||||
|
int call_running[3];
|
||||||
|
|
||||||
void *in_thread_call (void *arg)
|
void *in_thread_call (void *arg)
|
||||||
{
|
{
|
||||||
|
@ -133,18 +156,22 @@ void *in_thread_call (void *arg)
|
||||||
|
|
||||||
ACall *this_call = arg;
|
ACall *this_call = arg;
|
||||||
uint64_t start = 0;
|
uint64_t start = 0;
|
||||||
int step = 0, running = 1;
|
int step = 0;
|
||||||
int call_idx;
|
int call_idx;
|
||||||
|
|
||||||
|
call_running[this_call->idx] = 1;
|
||||||
|
|
||||||
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000);
|
||||||
int16_t sample_payload[frame_size];
|
int16_t sample_payload[frame_size];
|
||||||
randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);
|
randombytes((uint8_t *)sample_payload, sizeof(int16_t) * frame_size);
|
||||||
|
|
||||||
uint8_t prepared_payload[RTP_PAYLOAD_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 */
|
/* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */
|
||||||
while (running) {
|
while (call_running[this_call->idx]) {
|
||||||
|
|
||||||
switch ( step ) {
|
switch ( step ) {
|
||||||
case 0: /* CALLER */
|
case 0: /* CALLER */
|
||||||
|
@ -191,27 +218,15 @@ void *in_thread_call (void *arg)
|
||||||
int16_t storage[RTP_PAYLOAD_SIZE];
|
int16_t storage[RTP_PAYLOAD_SIZE];
|
||||||
int recved;
|
int recved;
|
||||||
|
|
||||||
/* Payload from CALLER */
|
|
||||||
recved = toxav_recv_audio(this_call->Callee.av, 0, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLER is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Payload from CALLEE */
|
|
||||||
recved = toxav_recv_audio(this_call->Caller.av, call_idx, frame_size, storage);
|
|
||||||
|
|
||||||
if ( recved ) {
|
|
||||||
/*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLEE is invalid");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
c_sleep(20);
|
c_sleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
step++; /* This terminates the loop */
|
step++; /* This terminates the loop */
|
||||||
|
|
||||||
|
pthread_mutex_lock(&muhmutex);
|
||||||
toxav_kill_transmission(this_call->Callee.av, 0);
|
toxav_kill_transmission(this_call->Callee.av, 0);
|
||||||
toxav_kill_transmission(this_call->Caller.av, call_idx);
|
toxav_kill_transmission(this_call->Caller.av, call_idx);
|
||||||
|
pthread_mutex_unlock(&muhmutex);
|
||||||
|
|
||||||
/* Call over CALLER hangs up */
|
/* Call over CALLER hangs up */
|
||||||
toxav_hangup(this_call->Caller.av, call_idx);
|
toxav_hangup(this_call->Caller.av, call_idx);
|
||||||
|
@ -224,7 +239,7 @@ void *in_thread_call (void *arg)
|
||||||
if (this_call->Caller.status == Ended) {
|
if (this_call->Caller.status == Ended) {
|
||||||
c_sleep(1000); /* race condition */
|
c_sleep(1000); /* race condition */
|
||||||
this_call->Callee.status = Ended;
|
this_call->Callee.status = Ended;
|
||||||
running = 0;
|
call_running[this_call->idx] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -306,55 +321,38 @@ START_TEST(test_AV_three_calls)
|
||||||
|
|
||||||
ToxAv *uniqcallerav = toxav_new(caller, 3);
|
ToxAv *uniqcallerav = toxav_new(caller, 3);
|
||||||
|
|
||||||
Status status_control = {
|
for (i = 0; i < 3; i ++) {
|
||||||
0,
|
status_control.calls[i].idx = i;
|
||||||
{none, uniqcallerav, 0},
|
|
||||||
{none, toxav_new(callees[0], 1), 0},
|
|
||||||
|
|
||||||
0,
|
status_control.calls[i].Caller.av = uniqcallerav;
|
||||||
{none, uniqcallerav},
|
status_control.calls[i].Caller.id = 0;
|
||||||
{none, toxav_new(callees[1], 1), 1},
|
status_control.calls[i].Caller.status= none;
|
||||||
|
|
||||||
0,
|
|
||||||
{none, uniqcallerav},
|
|
||||||
{none, toxav_new(callees[2], 1), 2}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
toxav_register_callstate_callback(callback_call_started, av_OnStart, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, &status_control);
|
|
||||||
|
|
||||||
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, &status_control);
|
|
||||||
|
|
||||||
toxav_register_callstate_callback(callback_recv_error, av_OnError, &status_control);
|
|
||||||
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control);
|
|
||||||
|
|
||||||
|
status_control.calls[i].Callee.av = toxav_new(callees[i], 1);
|
||||||
|
status_control.calls[i].Callee.id = i;
|
||||||
|
status_control.calls[i].Callee.status= none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_init(&muhmutex, NULL);
|
||||||
|
|
||||||
for ( i = 0; i < 3; i++ )
|
for ( i = 0; i < 3; i++ )
|
||||||
pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]);
|
pthread_create(&status_control.calls[i].tid, NULL, in_thread_call, &status_control.calls[i]);
|
||||||
|
|
||||||
|
|
||||||
/* Now start 3 calls and they'll run for 10 s */
|
/* Now start 3 calls and they'll run for 10 s */
|
||||||
|
|
||||||
for ( i = 0; i < 3; i++ )
|
for ( i = 0; i < 3; i++ )
|
||||||
pthread_detach(status_control.calls[i].tid);
|
pthread_detach(status_control.calls[i].tid);
|
||||||
|
|
||||||
while (
|
while (call_running[0] || call_running[1] || call_running[2]) {
|
||||||
status_control.calls[0].Callee.status != Ended && status_control.calls[0].Caller.status != Ended &&
|
pthread_mutex_lock(&muhmutex);
|
||||||
status_control.calls[1].Callee.status != Ended && status_control.calls[1].Caller.status != Ended &&
|
|
||||||
status_control.calls[2].Callee.status != Ended && status_control.calls[2].Caller.status != Ended
|
|
||||||
) {
|
|
||||||
tox_do(bootstrap_node);
|
tox_do(bootstrap_node);
|
||||||
tox_do(caller);
|
tox_do(caller);
|
||||||
tox_do(callees[0]);
|
tox_do(callees[0]);
|
||||||
tox_do(callees[1]);
|
tox_do(callees[1]);
|
||||||
tox_do(callees[2]);
|
tox_do(callees[2]);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&muhmutex);
|
||||||
c_sleep(20);
|
c_sleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,9 @@ int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_
|
||||||
if (cfg.g_w == width && cfg.g_h == height)
|
if (cfg.g_w == width && cfg.g_h == height)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (width * height > cs->max_width * cs->max_height)
|
||||||
|
return -1;
|
||||||
|
|
||||||
LOGGER_DEBUG("New video resolution: %u %u", width, height);
|
LOGGER_DEBUG("New video resolution: %u %u", width, height);
|
||||||
cfg.g_w = width;
|
cfg.g_w = width;
|
||||||
cfg.g_h = height;
|
cfg.g_h = height;
|
||||||
|
@ -249,7 +252,7 @@ int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate)
|
int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate)
|
||||||
{
|
{
|
||||||
vpx_codec_enc_cfg_t cfg;
|
vpx_codec_enc_cfg_t cfg;
|
||||||
int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
|
int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
|
||||||
|
@ -260,13 +263,18 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.rc_target_bitrate = video_bitrate;
|
cfg.rc_target_bitrate = video_bitrate;
|
||||||
cfg.g_w = 8192;
|
cfg.g_w = max_width;
|
||||||
cfg.g_h = 8192;
|
cfg.g_h = max_height;
|
||||||
cfg.g_pass = VPX_RC_ONE_PASS;
|
cfg.g_pass = VPX_RC_ONE_PASS;
|
||||||
cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
|
cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
|
||||||
cfg.g_lag_in_frames = 0;
|
cfg.g_lag_in_frames = 0;
|
||||||
cfg.kf_min_dist = 0;
|
cfg.kf_min_dist = 0;
|
||||||
cfg.kf_max_dist = 300;
|
cfg.kf_max_dist = 300;
|
||||||
|
cfg.kf_mode = VPX_KF_AUTO;
|
||||||
|
|
||||||
|
cs->max_width = max_width;
|
||||||
|
cs->max_height = max_height;
|
||||||
|
cs->bitrate = video_bitrate;
|
||||||
|
|
||||||
rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
|
rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
|
||||||
|
|
||||||
|
@ -282,9 +290,6 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reconfigure_video_encoder_resolution(cs, width, height) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,8 +327,8 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
|
||||||
uint32_t audio_sample_rate,
|
uint32_t audio_sample_rate,
|
||||||
uint32_t audio_channels,
|
uint32_t audio_channels,
|
||||||
uint32_t audio_VAD_tolerance_ms,
|
uint32_t audio_VAD_tolerance_ms,
|
||||||
uint16_t video_width,
|
uint16_t max_video_width,
|
||||||
uint16_t video_height,
|
uint16_t max_video_height,
|
||||||
uint32_t video_bitrate )
|
uint32_t video_bitrate )
|
||||||
{
|
{
|
||||||
CodecState *retu = calloc(sizeof(CodecState), 1);
|
CodecState *retu = calloc(sizeof(CodecState), 1);
|
||||||
|
@ -334,11 +339,12 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
|
||||||
retu->audio_sample_rate = audio_sample_rate;
|
retu->audio_sample_rate = audio_sample_rate;
|
||||||
|
|
||||||
/* Encoders */
|
/* Encoders */
|
||||||
if (!video_width || !video_height) { /* Disable video */
|
if (!max_video_width || !max_video_height) { /* Disable video */
|
||||||
/*video_width = 320;
|
/*video_width = 320;
|
||||||
video_height = 240; */
|
video_height = 240; */
|
||||||
} else {
|
} else {
|
||||||
retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0;
|
retu->capabilities |= ( 0 == init_video_encoder(retu, max_video_width, max_video_height,
|
||||||
|
video_bitrate) ) ? v_encoding : 0;
|
||||||
retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
|
retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ typedef struct _CodecState {
|
||||||
|
|
||||||
/* video decoding */
|
/* video decoding */
|
||||||
vpx_codec_ctx_t v_decoder;
|
vpx_codec_ctx_t v_decoder;
|
||||||
|
int bitrate;
|
||||||
|
int max_width;
|
||||||
|
int max_height;
|
||||||
|
|
||||||
/* audio encoding */
|
/* audio encoding */
|
||||||
OpusEncoder *audio_encoder;
|
OpusEncoder *audio_encoder;
|
||||||
|
|
1099
toxav/msi.c
1099
toxav/msi.c
File diff suppressed because it is too large
Load Diff
103
toxav/msi.h
103
toxav/msi.h
|
@ -1,4 +1,4 @@
|
||||||
/** toxmsi.h
|
/** msi.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||||
*
|
*
|
||||||
|
@ -27,11 +27,9 @@
|
||||||
|
|
||||||
#include "../toxcore/Messenger.h"
|
#include "../toxcore/Messenger.h"
|
||||||
|
|
||||||
/* define size for call_id */
|
typedef uint8_t MSICallIDType[12];
|
||||||
#define CALL_ID_LEN 12
|
typedef uint8_t MSIReasonStrType[255];
|
||||||
|
typedef void ( *MSICallbackType ) ( void* agent, int32_t call_idx, void *arg );
|
||||||
|
|
||||||
typedef void ( *MSICallback ) ( int32_t, void *arg );
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +55,36 @@ typedef enum {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callbacks ids that handle the states
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/* Requests */
|
||||||
|
MSI_OnInvite,
|
||||||
|
MSI_OnStart,
|
||||||
|
MSI_OnCancel,
|
||||||
|
MSI_OnReject,
|
||||||
|
MSI_OnEnd,
|
||||||
|
|
||||||
|
/* Responses */
|
||||||
|
MSI_OnRinging,
|
||||||
|
MSI_OnStarting,
|
||||||
|
MSI_OnEnding,
|
||||||
|
|
||||||
|
/* Protocol */
|
||||||
|
MSI_OnRequestTimeout,
|
||||||
|
MSI_OnPeerTimeout,
|
||||||
|
MSI_OnMediaChange
|
||||||
|
} MSICallbackID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callbacks container
|
||||||
|
*/
|
||||||
|
typedef struct _MSICallbackCont {
|
||||||
|
MSICallbackType function;
|
||||||
|
void *data;
|
||||||
|
} MSICallbackCont;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The call struct.
|
* @brief The call struct.
|
||||||
*
|
*
|
||||||
|
@ -69,7 +97,7 @@ typedef struct _MSICall { /* Call info structure */
|
||||||
MSICallType type_local; /* Type of payload user is ending */
|
MSICallType type_local; /* Type of payload user is ending */
|
||||||
MSICallType *type_peer; /* Type of payload others are sending */
|
MSICallType *type_peer; /* Type of payload others are sending */
|
||||||
|
|
||||||
uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
|
MSICallIDType id; /* Random value identifying the call */
|
||||||
|
|
||||||
int ringing_tout_ms; /* Ringing timeout in ms */
|
int ringing_tout_ms; /* Ringing timeout in ms */
|
||||||
|
|
||||||
|
@ -92,56 +120,30 @@ typedef struct _MSICall { /* Call info structure */
|
||||||
typedef struct _MSISession {
|
typedef struct _MSISession {
|
||||||
|
|
||||||
/* Call handlers */
|
/* Call handlers */
|
||||||
struct _MSICall **calls;
|
MSICall **calls;
|
||||||
int32_t max_calls;
|
int32_t max_calls;
|
||||||
|
|
||||||
int last_error_id; /* Determine the last error */
|
void *agent_handler;
|
||||||
const uint8_t *last_error_str;
|
Messenger *messenger_handle;
|
||||||
|
|
||||||
void *agent_handler; /* Pointer to an object that is handling msi */
|
uint32_t frequ;
|
||||||
Messenger *messenger_handle;
|
uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
|
||||||
|
|
||||||
uint32_t frequ;
|
|
||||||
uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
|
|
||||||
|
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
void *timer_handler;
|
void *timer_handler;
|
||||||
|
MSICallbackCont callbacks[11]; /* Callbacks used by this session */
|
||||||
} MSISession;
|
} MSISession;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callbacks ids that handle the states
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
/* Requests */
|
|
||||||
MSI_OnInvite,
|
|
||||||
MSI_OnStart,
|
|
||||||
MSI_OnCancel,
|
|
||||||
MSI_OnReject,
|
|
||||||
MSI_OnEnd,
|
|
||||||
|
|
||||||
/* Responses */
|
|
||||||
MSI_OnRinging,
|
|
||||||
MSI_OnStarting,
|
|
||||||
MSI_OnEnding,
|
|
||||||
|
|
||||||
/* Protocol */
|
|
||||||
MSI_OnError,
|
|
||||||
MSI_OnRequestTimeout,
|
|
||||||
MSI_OnPeerTimeout
|
|
||||||
|
|
||||||
} MSICallbackID;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback setter.
|
* @brief Callback setter.
|
||||||
*
|
*
|
||||||
|
* @param session The container.
|
||||||
* @param callback The callback.
|
* @param callback The callback.
|
||||||
* @param id The id.
|
* @param id The id.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
void msi_register_callback(MSICallback callback, MSICallbackID id, void *userdata);
|
void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,7 +222,20 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
|
||||||
* @param reason Set optional reason header. Pass NULL if none.
|
* @param reason Set optional reason header. Pass NULL if none.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason );
|
int msi_reject ( MSISession *session, int32_t call_index, const char *reason );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send invite request to friend_id.
|
||||||
|
*
|
||||||
|
* @param session Control session.
|
||||||
|
* @param call_index Call index.
|
||||||
|
* @param call_type Type of the call. Audio or Video(both audio and video)
|
||||||
|
* @param rngsec Ringing timeout.
|
||||||
|
* @param friend_id The friend.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int msi_change_type ( MSISession *session, int32_t call_index, MSICallType call_type );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
133
toxav/rtp.c
133
toxav/rtp.c
|
@ -1,4 +1,4 @@
|
||||||
/** toxrtp.c
|
/** rtp.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||||
*
|
*
|
||||||
|
@ -372,11 +372,6 @@ int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _session->queue_limit <= _session->queue_size ) {
|
|
||||||
LOGGER_WARNING("Queue limit reached!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_msg = msg_parse ( data + 1, length - 1 );
|
_msg = msg_parse ( data + 1, length - 1 );
|
||||||
|
|
||||||
if ( !_msg ) {
|
if ( !_msg ) {
|
||||||
|
@ -390,18 +385,7 @@ int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
|
||||||
_session->timestamp = _msg->header->timestamp;
|
_session->timestamp = _msg->header->timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&_session->mutex);
|
toxav_handle_packet(_session, _msg);
|
||||||
|
|
||||||
if ( _session->last_msg ) {
|
|
||||||
_session->last_msg->next = _msg;
|
|
||||||
_session->last_msg = _msg;
|
|
||||||
} else {
|
|
||||||
_session->last_msg = _session->oldest_msg = _msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
_session->queue_size++;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&_session->mutex);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -467,105 +451,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Release all messages held by session.
|
|
||||||
*
|
|
||||||
* @param session The session.
|
|
||||||
* @return int
|
|
||||||
* @retval -1 Error occurred.
|
|
||||||
* @retval 0 Success.
|
|
||||||
*/
|
|
||||||
int rtp_release_session_recv ( RTPSession *session )
|
|
||||||
{
|
|
||||||
if ( !session ) {
|
|
||||||
LOGGER_WARNING("No session!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTPMessage *_tmp, * _it;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&session->mutex);
|
|
||||||
|
|
||||||
for ( _it = session->oldest_msg; _it; _it = _tmp ) {
|
|
||||||
_tmp = _it->next;
|
|
||||||
rtp_free_msg( session, _it);
|
|
||||||
}
|
|
||||||
|
|
||||||
session->last_msg = session->oldest_msg = NULL;
|
|
||||||
session->queue_size = 0;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Call this to change queue limit
|
|
||||||
*
|
|
||||||
* @param session The session
|
|
||||||
* @param limit new limit
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
void rtp_queue_adjust_limit(RTPSession *session, uint64_t limit)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&session->mutex);
|
|
||||||
|
|
||||||
RTPMessage *_tmp, * _it = session->oldest_msg;
|
|
||||||
|
|
||||||
for ( ; session->queue_size > limit; _it = _tmp ) {
|
|
||||||
_tmp = _it->next;
|
|
||||||
rtp_free_msg( session, _it);
|
|
||||||
session->queue_size --;
|
|
||||||
}
|
|
||||||
|
|
||||||
session->oldest_msg = _it;
|
|
||||||
session->queue_limit = limit;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets oldest message in the list.
|
|
||||||
*
|
|
||||||
* @param session Where the list is.
|
|
||||||
* @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it.
|
|
||||||
* @retval NULL No messages in the list, or no list.
|
|
||||||
*/
|
|
||||||
RTPMessage *rtp_recv_msg ( RTPSession *session )
|
|
||||||
{
|
|
||||||
if ( !session ) {
|
|
||||||
LOGGER_WARNING("No session!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&session->mutex);
|
|
||||||
|
|
||||||
if ( session->queue_size == 0 ) {
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RTPMessage *_retu = session->oldest_msg;
|
|
||||||
|
|
||||||
/*if (_retu)*/
|
|
||||||
session->oldest_msg = _retu->next;
|
|
||||||
|
|
||||||
if ( !session->oldest_msg )
|
|
||||||
session->last_msg = NULL;
|
|
||||||
|
|
||||||
session->queue_size --;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
|
||||||
|
|
||||||
|
|
||||||
return _retu;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends data to _RTPSession::dest
|
* @brief Sends data to _RTPSession::dest
|
||||||
*
|
*
|
||||||
|
@ -627,7 +512,6 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
|
||||||
free ( msg );
|
free ( msg );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Must be called before calling any other rtp function. It's used
|
* @brief Must be called before calling any other rtp function. It's used
|
||||||
* to initialize RTP control session.
|
* to initialize RTP control session.
|
||||||
|
@ -682,11 +566,6 @@ RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int frien
|
||||||
/* Also set payload type as prefix */
|
/* Also set payload type as prefix */
|
||||||
_retu->prefix = payload_type;
|
_retu->prefix = payload_type;
|
||||||
|
|
||||||
_retu->oldest_msg = _retu->last_msg = NULL;
|
|
||||||
_retu->queue_limit = 100; /* Default */
|
|
||||||
_retu->queue_size = 0;
|
|
||||||
|
|
||||||
pthread_mutex_init(&_retu->mutex, NULL);
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -709,17 +588,9 @@ void rtp_terminate_session ( RTPSession *session, Messenger *messenger )
|
||||||
|
|
||||||
custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
|
custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
|
||||||
|
|
||||||
rtp_release_session_recv(session);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&session->mutex);
|
|
||||||
|
|
||||||
free ( session->ext_header );
|
free ( session->ext_header );
|
||||||
free ( session->csrc );
|
free ( session->csrc );
|
||||||
|
|
||||||
pthread_mutex_unlock(&session->mutex);
|
|
||||||
|
|
||||||
pthread_mutex_destroy(&session->mutex);
|
|
||||||
|
|
||||||
LOGGER_DEBUG("Terminated RTP session: %p", session);
|
LOGGER_DEBUG("Terminated RTP session: %p", session);
|
||||||
|
|
||||||
/* And finally free session */
|
/* And finally free session */
|
||||||
|
|
12
toxav/rtp.h
12
toxav/rtp.h
|
@ -1,4 +1,4 @@
|
||||||
/** toxrtp.h
|
/** rtp.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||||
*
|
*
|
||||||
|
@ -105,17 +105,12 @@ typedef struct _RTPSession {
|
||||||
*/
|
*/
|
||||||
RTPExtHeader *ext_header;
|
RTPExtHeader *ext_header;
|
||||||
|
|
||||||
RTPMessage *oldest_msg;
|
|
||||||
RTPMessage *last_msg; /* tail */
|
|
||||||
|
|
||||||
uint64_t queue_limit;/* Default 100; modify per thy liking */
|
|
||||||
uint64_t queue_size; /* currently holding << messages */
|
|
||||||
|
|
||||||
/* Msg prefix for core to know when recving */
|
/* Msg prefix for core to know when recving */
|
||||||
uint8_t prefix;
|
uint8_t prefix;
|
||||||
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
int dest;
|
int dest;
|
||||||
|
int32_t call_index;
|
||||||
|
struct _ToxAv *av;
|
||||||
|
|
||||||
} RTPSession;
|
} RTPSession;
|
||||||
|
|
||||||
|
@ -172,7 +167,6 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
|
||||||
*/
|
*/
|
||||||
void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
|
void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Must be called before calling any other rtp function. It's used
|
* @brief Must be called before calling any other rtp function. It's used
|
||||||
* to initialize RTP control session.
|
* to initialize RTP control session.
|
||||||
|
|
428
toxav/toxav.c
428
toxav/toxav.c
|
@ -76,6 +76,10 @@ struct _ToxAv {
|
||||||
Messenger *messenger;
|
Messenger *messenger;
|
||||||
MSISession *msi_session; /** Main msi session */
|
MSISession *msi_session; /** Main msi session */
|
||||||
CallSpecific *calls; /** Per-call params */
|
CallSpecific *calls; /** Per-call params */
|
||||||
|
|
||||||
|
void (*audio_callback)(ToxAv *, int32_t, int16_t *, int);
|
||||||
|
void (*video_callback)(ToxAv *, int32_t, vpx_image_t *);
|
||||||
|
|
||||||
uint32_t max_calls;
|
uint32_t max_calls;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,10 +119,8 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
|
||||||
}
|
}
|
||||||
|
|
||||||
av->messenger = (Messenger *)messenger;
|
av->messenger = (Messenger *)messenger;
|
||||||
|
|
||||||
av->msi_session = msi_init_session(av->messenger, max_calls);
|
av->msi_session = msi_init_session(av->messenger, max_calls);
|
||||||
av->msi_session->agent_handler = av;
|
av->msi_session->agent_handler = av;
|
||||||
|
|
||||||
av->calls = calloc(sizeof(CallSpecific), max_calls);
|
av->calls = calloc(sizeof(CallSpecific), max_calls);
|
||||||
av->max_calls = max_calls;
|
av->max_calls = max_calls;
|
||||||
|
|
||||||
|
@ -133,8 +135,6 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
|
||||||
*/
|
*/
|
||||||
void toxav_kill ( ToxAv *av )
|
void toxav_kill ( ToxAv *av )
|
||||||
{
|
{
|
||||||
msi_terminate_session(av->msi_session);
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < av->max_calls; i ++) {
|
for (; i < av->max_calls; i ++) {
|
||||||
|
@ -152,6 +152,8 @@ void toxav_kill ( ToxAv *av )
|
||||||
if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
|
if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msi_terminate_session(av->msi_session);
|
||||||
|
|
||||||
free(av->calls);
|
free(av->calls);
|
||||||
free(av);
|
free(av);
|
||||||
}
|
}
|
||||||
|
@ -159,13 +161,36 @@ void toxav_kill ( ToxAv *av )
|
||||||
/**
|
/**
|
||||||
* @brief Register callback for call state.
|
* @brief Register callback for call state.
|
||||||
*
|
*
|
||||||
|
* @param av Handler.
|
||||||
* @param callback The callback
|
* @param callback The callback
|
||||||
* @param id One of the ToxAvCallbackID values
|
* @param id One of the ToxAvCallbackID values
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
|
void toxav_register_callstate_callback ( ToxAv* av, ToxAVCallback callback, ToxAvCallbackID id, void* userdata )
|
||||||
{
|
{
|
||||||
msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata);
|
msi_register_callback(av->msi_session, (MSICallbackType)callback, (MSICallbackID) id, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register callback for recieving audio data
|
||||||
|
*
|
||||||
|
* @param callback The callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int))
|
||||||
|
{
|
||||||
|
av->audio_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register callback for recieving video data
|
||||||
|
*
|
||||||
|
* @param callback The callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *))
|
||||||
|
{
|
||||||
|
av->video_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -272,6 +297,24 @@ int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reaso
|
||||||
return msi_cancel(av->msi_session, call_index, peer_id, reason);
|
return msi_cancel(av->msi_session, call_index, peer_id, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify peer that we are changing call type
|
||||||
|
*
|
||||||
|
* @param av Handler.
|
||||||
|
* @return int
|
||||||
|
* @param call_type Change to...
|
||||||
|
* @retval 0 Success.
|
||||||
|
* @retval ToxAvError On error.
|
||||||
|
*/
|
||||||
|
int toxav_change_type(ToxAv* av, int32_t call_index, ToxAvCallType call_type)
|
||||||
|
{
|
||||||
|
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
|
||||||
|
return ErrorNoCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
return msi_change_type(av->msi_session, call_index, call_type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
|
* @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
|
||||||
*
|
*
|
||||||
|
@ -300,7 +343,7 @@ int toxav_stop_call ( ToxAv *av, int32_t call_index )
|
||||||
int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
|
int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
|
||||||
{
|
{
|
||||||
if ( !av->msi_session || cii(call_index, av->msi_session) ||
|
if ( !av->msi_session || cii(call_index, av->msi_session) ||
|
||||||
!av->msi_session->calls[call_index] || av->calls[call_index].call_active) {
|
!av->msi_session->calls[call_index] || av->calls[call_index].call_active) {
|
||||||
LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
|
LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
}
|
}
|
||||||
|
@ -316,17 +359,21 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
call->crtps[audio_index]->call_index = call_index;
|
||||||
|
call->crtps[audio_index]->av = av;
|
||||||
|
|
||||||
if ( support_video ) {
|
if ( support_video ) {
|
||||||
call->crtps[video_index] =
|
call->crtps[video_index] =
|
||||||
rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
|
rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
|
||||||
|
|
||||||
|
|
||||||
if ( !call->crtps[video_index] ) {
|
if ( !call->crtps[video_index] ) {
|
||||||
LOGGER_ERROR("Error while starting video RTP session!\n");
|
LOGGER_ERROR("Error while starting video RTP session!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
call->crtps[video_index]->call_index = call_index;
|
||||||
|
call->crtps[video_index]->av = av;
|
||||||
|
|
||||||
call->frame_limit = 0;
|
call->frame_limit = 0;
|
||||||
call->frame_id = 0;
|
call->frame_id = 0;
|
||||||
call->frame_outid = 0;
|
call->frame_outid = 0;
|
||||||
|
@ -350,8 +397,8 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
|
||||||
codec_settings->audio_sample_rate,
|
codec_settings->audio_sample_rate,
|
||||||
codec_settings->audio_channels,
|
codec_settings->audio_channels,
|
||||||
codec_settings->audio_VAD_tolerance,
|
codec_settings->audio_VAD_tolerance,
|
||||||
codec_settings->video_width,
|
codec_settings->max_video_width,
|
||||||
codec_settings->video_height,
|
codec_settings->max_video_height,
|
||||||
codec_settings->video_bitrate) )) {
|
codec_settings->video_bitrate) )) {
|
||||||
|
|
||||||
if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error;
|
if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error;
|
||||||
|
@ -390,18 +437,23 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
|
||||||
|
|
||||||
pthread_mutex_lock(&call->mutex);
|
pthread_mutex_lock(&call->mutex);
|
||||||
|
|
||||||
if (!call->call_active){
|
if (!call->call_active) {
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
call->call_active = 0;
|
call->call_active = 0;
|
||||||
|
|
||||||
rtp_terminate_session(call->crtps[audio_index], av->messenger); call->crtps[audio_index] = NULL;
|
rtp_terminate_session(call->crtps[audio_index], av->messenger);
|
||||||
rtp_terminate_session(call->crtps[video_index], av->messenger); call->crtps[video_index] = NULL;
|
call->crtps[audio_index] = NULL;
|
||||||
terminate_queue(call->j_buf); call->j_buf = NULL;
|
rtp_terminate_session(call->crtps[video_index], av->messenger);
|
||||||
codec_terminate_session(call->cs); call->cs = NULL;
|
call->crtps[video_index] = NULL;
|
||||||
|
terminate_queue(call->j_buf);
|
||||||
|
call->j_buf = NULL;
|
||||||
|
codec_terminate_session(call->cs);
|
||||||
|
call->cs = NULL;
|
||||||
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
pthread_mutex_destroy(&call->mutex);
|
pthread_mutex_destroy(&call->mutex);
|
||||||
|
@ -424,7 +476,8 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
|
||||||
inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
|
inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
|
||||||
unsigned int length )
|
unsigned int length )
|
||||||
{
|
{
|
||||||
CallSpecific* call = &av->calls[call_index];
|
CallSpecific *call = &av->calls[call_index];
|
||||||
|
|
||||||
if (call->crtps[type - TypeAudio]) {
|
if (call->crtps[type - TypeAudio]) {
|
||||||
|
|
||||||
if (type == TypeAudio) {
|
if (type == TypeAudio) {
|
||||||
|
@ -468,141 +521,6 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Receive RTP payload.
|
|
||||||
*
|
|
||||||
* @param av Handler.
|
|
||||||
* @param type Type of the payload.
|
|
||||||
* @param dest Storage.
|
|
||||||
* @return int
|
|
||||||
* @retval ToxAvError On Error.
|
|
||||||
* @retval >=0 Size of received payload.
|
|
||||||
*/
|
|
||||||
inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
|
|
||||||
{
|
|
||||||
if ( !dest ) return ErrorInternal;
|
|
||||||
|
|
||||||
CallSpecific *call = &av->calls[call_index];
|
|
||||||
|
|
||||||
if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
|
|
||||||
|
|
||||||
RTPMessage *message;
|
|
||||||
|
|
||||||
if ( type == TypeAudio ) {
|
|
||||||
|
|
||||||
do {
|
|
||||||
message = rtp_recv_msg(call->crtps[audio_index]);
|
|
||||||
|
|
||||||
if (message) {
|
|
||||||
/* push the packet into the queue */
|
|
||||||
queue(call->j_buf, message);
|
|
||||||
}
|
|
||||||
} while (message);
|
|
||||||
|
|
||||||
int success = 0;
|
|
||||||
message = dequeue(call->j_buf, &success);
|
|
||||||
|
|
||||||
if ( success == 2) return ErrorAudioPacketLost;
|
|
||||||
} else {
|
|
||||||
message = rtp_recv_msg(call->crtps[video_index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( message ) {
|
|
||||||
memcpy(dest, message->data, message->length);
|
|
||||||
|
|
||||||
int length = message->length;
|
|
||||||
|
|
||||||
rtp_free_msg(NULL, message);
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Receive decoded video packet.
|
|
||||||
*
|
|
||||||
* @param av Handler.
|
|
||||||
* @param output Storage.
|
|
||||||
* @return int
|
|
||||||
* @retval 0 Success.
|
|
||||||
* @retval ToxAvError On Error.
|
|
||||||
*/
|
|
||||||
inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output)
|
|
||||||
{
|
|
||||||
if ( !output ) return ErrorInternal;
|
|
||||||
|
|
||||||
if (cii(call_index, av->msi_session)) {
|
|
||||||
LOGGER_WARNING("Invalid call index: %d", call_index);
|
|
||||||
return ErrorNoCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
CallSpecific *call = &av->calls[call_index];
|
|
||||||
pthread_mutex_lock(&call->mutex);
|
|
||||||
|
|
||||||
if (!call->call_active){
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
|
||||||
return ErrorNoCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t packet [RTP_PAYLOAD_SIZE];
|
|
||||||
int recved_size;
|
|
||||||
|
|
||||||
while ((recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet)) > 0) {
|
|
||||||
if (recved_size < VIDEOFRAME_HEADER_SIZE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t i = packet[0] - call->frame_id;
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
/* piece of current frame */
|
|
||||||
} else if (i > 0 && i < 128) {
|
|
||||||
/* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
|
|
||||||
int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
|
|
||||||
call->frame_id = packet[0];
|
|
||||||
memset(call->frame_buf, 0, call->frame_limit);
|
|
||||||
call->frame_limit = 0;
|
|
||||||
|
|
||||||
if (rc != VPX_CODEC_OK) {
|
|
||||||
LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* old packet, dont read */
|
|
||||||
LOGGER_DEBUG("Old packet: %u\n", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
|
|
||||||
VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
|
|
||||||
/* packet out of buffer range */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
|
|
||||||
memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
|
|
||||||
recved_size - VIDEOFRAME_HEADER_SIZE);
|
|
||||||
uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
|
|
||||||
|
|
||||||
if (limit > call->frame_limit) {
|
|
||||||
call->frame_limit = limit;
|
|
||||||
LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vpx_codec_iter_t iter = NULL;
|
|
||||||
vpx_image_t *img;
|
|
||||||
img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
|
|
||||||
|
|
||||||
*output = img;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
|
||||||
return ErrorNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode and send video packet.
|
* @brief Encode and send video packet.
|
||||||
*
|
*
|
||||||
|
@ -619,11 +537,11 @@ inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *fr
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallSpecific* call = &av->calls[call_index];
|
CallSpecific *call = &av->calls[call_index];
|
||||||
pthread_mutex_lock(&call->mutex);
|
pthread_mutex_lock(&call->mutex);
|
||||||
|
|
||||||
|
|
||||||
if (!call->call_active){
|
if (!call->call_active) {
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
|
@ -657,13 +575,16 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
|
||||||
CallSpecific *call = &av->calls[call_index];
|
CallSpecific *call = &av->calls[call_index];
|
||||||
pthread_mutex_lock(&call->mutex);
|
pthread_mutex_lock(&call->mutex);
|
||||||
|
|
||||||
if (!call->call_active){
|
if (!call->call_active) {
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h);
|
if (reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) {
|
||||||
|
pthread_mutex_unlock(&call->mutex);
|
||||||
|
return ErrorInternal;
|
||||||
|
}
|
||||||
|
|
||||||
int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
|
int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
|
||||||
|
|
||||||
|
@ -695,67 +616,6 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Receive decoded audio frame.
|
|
||||||
*
|
|
||||||
* @param av Handler.
|
|
||||||
* @param frame_size The size of dest in frames/samples (one frame/sample is 16 bits or 2 bytes
|
|
||||||
* and corresponds to one sample of audio.)
|
|
||||||
* @param dest Destination of the raw audio (16 bit signed pcm with AUDIO_CHANNELS channels).
|
|
||||||
* Make sure it has enough space for frame_size frames/samples.
|
|
||||||
* @return int
|
|
||||||
* @retval >=0 Size of received data in frames/samples.
|
|
||||||
* @retval ToxAvError On error.
|
|
||||||
*/
|
|
||||||
inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
|
|
||||||
{
|
|
||||||
if ( !dest ) return ErrorInternal;
|
|
||||||
|
|
||||||
if (cii(call_index, av->msi_session)) {
|
|
||||||
LOGGER_WARNING("Invalid call index: %d", call_index);
|
|
||||||
return ErrorNoCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CallSpecific *call = &av->calls[call_index];
|
|
||||||
pthread_mutex_lock(&call->mutex);
|
|
||||||
|
|
||||||
|
|
||||||
if (!call->call_active){
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
|
||||||
return ErrorNoCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t packet [RTP_PAYLOAD_SIZE];
|
|
||||||
|
|
||||||
int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
|
|
||||||
|
|
||||||
if ( recved_size == ErrorAudioPacketLost ) {
|
|
||||||
int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
|
||||||
|
|
||||||
if ( dec_size < 0 ) {
|
|
||||||
LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
|
|
||||||
return ErrorInternal;
|
|
||||||
} else return dec_size;
|
|
||||||
|
|
||||||
} else if ( recved_size ) {
|
|
||||||
int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
|
||||||
|
|
||||||
if ( dec_size < 0 ) {
|
|
||||||
LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
|
|
||||||
return ErrorInternal;
|
|
||||||
} else return dec_size;
|
|
||||||
} else {
|
|
||||||
pthread_mutex_unlock(&call->mutex);
|
|
||||||
return 0; /* Nothing received */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send audio frame.
|
* @brief Send audio frame.
|
||||||
*
|
*
|
||||||
|
@ -774,11 +634,11 @@ inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *fr
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallSpecific* call = &av->calls[call_index];
|
CallSpecific *call = &av->calls[call_index];
|
||||||
pthread_mutex_lock(&call->mutex);
|
pthread_mutex_lock(&call->mutex);
|
||||||
|
|
||||||
|
|
||||||
if (!call->call_active){
|
if (!call->call_active) {
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
|
@ -810,11 +670,11 @@ inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallSpecific* call = &av->calls[call_index];
|
CallSpecific *call = &av->calls[call_index];
|
||||||
pthread_mutex_lock(&call->mutex);
|
pthread_mutex_lock(&call->mutex);
|
||||||
|
|
||||||
|
|
||||||
if (!call->call_active){
|
if (!call->call_active) {
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
LOGGER_WARNING("Action on inactive call: %d", call_index);
|
||||||
return ErrorNoCall;
|
return ErrorNoCall;
|
||||||
|
@ -823,7 +683,6 @@ inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t
|
||||||
int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
|
int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
|
||||||
pthread_mutex_unlock(&call->mutex);
|
pthread_mutex_unlock(&call->mutex);
|
||||||
|
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
|
LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
|
||||||
return ErrorInternal;
|
return ErrorInternal;
|
||||||
|
@ -898,42 +757,6 @@ inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCa
|
||||||
/* 0 is error here */
|
/* 0 is error here */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set queue limit
|
|
||||||
*
|
|
||||||
* @param av Handler
|
|
||||||
* @param call_index index
|
|
||||||
* @param limit the limit
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
|
|
||||||
{
|
|
||||||
if ( av->calls[call_index].crtps[audio_index] )
|
|
||||||
rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
|
|
||||||
else
|
|
||||||
return ErrorNoRtpSession;
|
|
||||||
|
|
||||||
return ErrorNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set queue limit
|
|
||||||
*
|
|
||||||
* @param av Handler
|
|
||||||
* @param call_index index
|
|
||||||
* @param limit the limit
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
|
|
||||||
{
|
|
||||||
if ( av->calls[call_index].crtps[video_index] )
|
|
||||||
rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
|
|
||||||
else
|
|
||||||
return ErrorNoRtpSession;
|
|
||||||
|
|
||||||
return ErrorNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline__ Tox *toxav_get_tox(ToxAv *av)
|
inline__ Tox *toxav_get_tox(ToxAv *av)
|
||||||
{
|
{
|
||||||
return (Tox *)av->messenger;
|
return (Tox *)av->messenger;
|
||||||
|
@ -945,3 +768,94 @@ int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t fra
|
||||||
|
|
||||||
return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
|
return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
|
||||||
|
{
|
||||||
|
ToxAv *av = _session->av;
|
||||||
|
int32_t call_index = _session->call_index;
|
||||||
|
CallSpecific *call = &av->calls[call_index];
|
||||||
|
|
||||||
|
if (!call->call_active) return;
|
||||||
|
|
||||||
|
if (_session->payload_type == type_audio % 128) {
|
||||||
|
queue(call->j_buf, _msg);
|
||||||
|
|
||||||
|
int success = 0, dec_size;
|
||||||
|
int frame_size = 960;
|
||||||
|
int16_t dest[frame_size];
|
||||||
|
|
||||||
|
while ((_msg = dequeue(call->j_buf, &success)) || success == 2) {
|
||||||
|
if (success == 2) {
|
||||||
|
dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
|
||||||
|
} else {
|
||||||
|
dec_size = opus_decode(call->cs->audio_decoder, _msg->data, _msg->length, dest, frame_size, 0);
|
||||||
|
rtp_free_msg(NULL, _msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dec_size < 0) {
|
||||||
|
LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( av->audio_callback )
|
||||||
|
av->audio_callback(av, call_index, dest, frame_size);
|
||||||
|
else
|
||||||
|
LOGGER_WARNING("Audio packet dropped due to missing callback!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint8_t *packet = _msg->data;
|
||||||
|
int recved_size = _msg->length;
|
||||||
|
|
||||||
|
if (recved_size < VIDEOFRAME_HEADER_SIZE) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t i = packet[0] - call->frame_id;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
/* piece of current frame */
|
||||||
|
} else if (i > 0 && i < 128) {
|
||||||
|
/* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
|
||||||
|
int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
|
||||||
|
call->frame_id = packet[0];
|
||||||
|
memset(call->frame_buf, 0, call->frame_limit);
|
||||||
|
call->frame_limit = 0;
|
||||||
|
|
||||||
|
if (rc != VPX_CODEC_OK) {
|
||||||
|
LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* old packet, dont read */
|
||||||
|
LOGGER_DEBUG("Old packet: %u\n", i);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
|
||||||
|
VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
|
||||||
|
/* packet out of buffer range */
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
|
||||||
|
memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
|
||||||
|
recved_size - VIDEOFRAME_HEADER_SIZE);
|
||||||
|
uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
|
||||||
|
|
||||||
|
if (limit > call->frame_limit) {
|
||||||
|
call->frame_limit = limit;
|
||||||
|
LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
end:;
|
||||||
|
vpx_codec_iter_t iter = NULL;
|
||||||
|
vpx_image_t *img;
|
||||||
|
img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
|
||||||
|
|
||||||
|
if (img && av->video_callback) {
|
||||||
|
av->video_callback(av, call_index, img);
|
||||||
|
} else
|
||||||
|
LOGGER_WARNING("Video packet dropped due to missing callback or no image!");
|
||||||
|
|
||||||
|
rtp_free_msg(NULL, _msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ extern "C" {
|
||||||
/* vpx_image_t */
|
/* vpx_image_t */
|
||||||
#include <vpx/vpx_image.h>
|
#include <vpx/vpx_image.h>
|
||||||
|
|
||||||
typedef void ( *ToxAVCallback ) ( int32_t, void *arg );
|
typedef void ( *ToxAVCallback ) ( void* agent, int32_t call_idx, void *arg );
|
||||||
typedef struct _ToxAv ToxAv;
|
typedef struct _ToxAv ToxAv;
|
||||||
|
|
||||||
#ifndef __TOX_DEFINED__
|
#ifndef __TOX_DEFINED__
|
||||||
|
@ -59,9 +59,9 @@ typedef enum {
|
||||||
av_OnEnding,
|
av_OnEnding,
|
||||||
|
|
||||||
/* Protocol */
|
/* Protocol */
|
||||||
av_OnError,
|
|
||||||
av_OnRequestTimeout,
|
av_OnRequestTimeout,
|
||||||
av_OnPeerTimeout
|
av_OnPeerTimeout,
|
||||||
|
av_OnMediaChange
|
||||||
} ToxAvCallbackID;
|
} ToxAvCallbackID;
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,8 +120,8 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
typedef struct _ToxAvCodecSettings {
|
typedef struct _ToxAvCodecSettings {
|
||||||
uint32_t video_bitrate; /* In kbits/s */
|
uint32_t video_bitrate; /* In kbits/s */
|
||||||
uint16_t video_width; /* In px */
|
uint16_t max_video_width; /* In px */
|
||||||
uint16_t video_height; /* In px */
|
uint16_t max_video_height; /* In px */
|
||||||
|
|
||||||
uint32_t audio_bitrate; /* In bits/s */
|
uint32_t audio_bitrate; /* In bits/s */
|
||||||
uint16_t audio_frame_duration; /* In ms */
|
uint16_t audio_frame_duration; /* In ms */
|
||||||
|
@ -158,11 +158,30 @@ void toxav_kill(ToxAv *av);
|
||||||
/**
|
/**
|
||||||
* @brief Register callback for call state.
|
* @brief Register callback for call state.
|
||||||
*
|
*
|
||||||
|
* @param av Handler.
|
||||||
* @param callback The callback
|
* @param callback The callback
|
||||||
* @param id One of the ToxAvCallbackID values
|
* @param id One of the ToxAvCallbackID values
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id, void *userdata);
|
void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register callback for recieving audio data
|
||||||
|
*
|
||||||
|
* @param av Handler.
|
||||||
|
* @param callback The callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register callback for recieving video data
|
||||||
|
*
|
||||||
|
* @param av Handler.
|
||||||
|
* @param callback The callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Call user. Use its friend_id.
|
* @brief Call user. Use its friend_id.
|
||||||
|
@ -221,6 +240,16 @@ int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
|
||||||
*/
|
*/
|
||||||
int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
|
int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify peer that we are changing call type
|
||||||
|
*
|
||||||
|
* @param av Handler.
|
||||||
|
* @return int
|
||||||
|
* @retval 0 Success.
|
||||||
|
* @retval ToxAvError On error.
|
||||||
|
*/
|
||||||
|
int toxav_change_type(ToxAv *av, int32_t call_index, ToxAvCallType call_type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
|
* @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
|
||||||
*
|
*
|
||||||
|
@ -252,31 +281,6 @@ int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings
|
||||||
*/
|
*/
|
||||||
int toxav_kill_transmission(ToxAv *av, int32_t call_index);
|
int toxav_kill_transmission(ToxAv *av, int32_t call_index);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Receive decoded video packet.
|
|
||||||
*
|
|
||||||
* @param av Handler.
|
|
||||||
* @param output Storage.
|
|
||||||
* @return int
|
|
||||||
* @retval 0 Success.
|
|
||||||
* @retval ToxAvError On Error.
|
|
||||||
*/
|
|
||||||
int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Receive decoded audio frame.
|
|
||||||
*
|
|
||||||
* @param av Handler.
|
|
||||||
* @param frame_size The size of dest in frames/samples (one frame/sample is 16 bits or 2 bytes
|
|
||||||
* and corresponds to one sample of audio.)
|
|
||||||
* @param dest Destination of the raw audio (16 bit signed pcm with AUDIO_CHANNELS channels).
|
|
||||||
* Make sure it has enough space for frame_size frames/samples.
|
|
||||||
* @return int
|
|
||||||
* @retval >=0 Size of received data in frames/samples.
|
|
||||||
* @retval ToxAvError On error.
|
|
||||||
*/
|
|
||||||
int toxav_recv_audio( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Encode and send video packet.
|
* @brief Encode and send video packet.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue
Block a user