mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Done with encryption and core adaptations.
This commit is contained in:
parent
51d8c41390
commit
65d320e31d
737
toxav/phone.c
Executable file
737
toxav/phone.c
Executable file
|
@ -0,0 +1,737 @@
|
|||
/** phone.c
|
||||
*
|
||||
* NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
*
|
||||
* This file is for testing/reference purposes only, hence
|
||||
* it is _poorly_ designed and it does not fully reflect the
|
||||
* quaility of msi nor rtp. Although toxmsi* and toxrtp* are tested
|
||||
* there is always possiblity of crashes. If crash occures,
|
||||
* contact me ( mannol ) on either irc channel #tox-dev @ freenode.net:6667
|
||||
* or eniz_vukovic@hotmail.com
|
||||
*
|
||||
* NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#define _BSD_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "toxmsi.h"
|
||||
#include "toxrtp.h"
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../toxcore/network.h"
|
||||
#include "../toxcore/event.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
/* Define client version */
|
||||
#define _USERAGENT "v.0.3.0"
|
||||
|
||||
|
||||
typedef struct av_friend_s {
|
||||
int _id;
|
||||
int _active; /* 0=false; 1=true; */
|
||||
} av_friend_t;
|
||||
|
||||
typedef struct av_session_s {
|
||||
MSISession* _msi;
|
||||
|
||||
RTPSession* _rtp_audio;
|
||||
RTPSession* _rtp_video;
|
||||
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
Tox* _messenger;
|
||||
av_friend_t* _friends;
|
||||
int _friend_cout;
|
||||
uint8_t _my_public_id[200];
|
||||
} av_session_t;
|
||||
|
||||
|
||||
void av_allocate_friend(av_session_t* _phone, int _id, int _active)
|
||||
{
|
||||
static int _new_id = 0;
|
||||
|
||||
if ( !_phone->_friends ) {
|
||||
_phone->_friends = calloc(sizeof(av_friend_t), 1);
|
||||
_phone->_friend_cout = 1;
|
||||
} else{
|
||||
_phone->_friend_cout ++;
|
||||
_phone->_friends = realloc(_phone->_friends, sizeof(av_friend_t) * _phone->_friend_cout);
|
||||
}
|
||||
|
||||
if ( _id = -1 ) {
|
||||
_phone->_friends->_id = _new_id;
|
||||
_new_id ++;
|
||||
} else _phone->_friends->_id = _id;
|
||||
|
||||
_phone->_friends->_active = _active;
|
||||
}
|
||||
av_friend_t* av_get_friend(av_session_t* _phone, int _id)
|
||||
{
|
||||
av_friend_t* _friends = _phone->_friends;
|
||||
|
||||
if ( !_friends ) return NULL;
|
||||
|
||||
int _it = 0;
|
||||
for (; _it < _phone->_friend_cout; _it ++)
|
||||
if ( _friends[_it]._id == _id )
|
||||
return _friends + _it;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/***************** MISC *****************/
|
||||
|
||||
void INFO (const char* _format, ...)
|
||||
{
|
||||
printf("\r[!] ");
|
||||
va_list _arg;
|
||||
va_start (_arg, _format);
|
||||
vfprintf (stdout, _format, _arg);
|
||||
va_end (_arg);
|
||||
printf("\n\r >> ");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
unsigned char *hex_string_to_bin(char hex_string[])
|
||||
{
|
||||
size_t i, len = strlen(hex_string);
|
||||
unsigned char *val = calloc(sizeof(char), len);
|
||||
char *pos = hex_string;
|
||||
|
||||
for (i = 0; i < len; ++i, pos += 2)
|
||||
sscanf(pos, "%2hhx", &val[i]);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int getinput( char* _buff, size_t _limit, int* _len )
|
||||
{
|
||||
if ( fgets(_buff, _limit, stdin) == NULL )
|
||||
return -1;
|
||||
|
||||
*_len = strlen(_buff) - 1;
|
||||
|
||||
/* Get rid of newline */
|
||||
_buff[*_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* trim_spaces ( char* buff )
|
||||
{
|
||||
|
||||
int _i = 0, _len = strlen(buff);
|
||||
|
||||
char* container = calloc(sizeof(char), _len);
|
||||
int _ci = 0;
|
||||
|
||||
for ( ; _i < _len; _i++ ) {
|
||||
while ( _i < _len && buff[_i] == ' ' )
|
||||
_i++;
|
||||
|
||||
if ( _i < _len ){
|
||||
container[_ci] = buff[_i];
|
||||
_ci ++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy( buff, container, _ci );
|
||||
buff[_ci] = '\0';
|
||||
free(container);
|
||||
return buff;
|
||||
}
|
||||
|
||||
#define FRADDR_TOSTR_CHUNK_LEN 8
|
||||
|
||||
static void fraddr_to_str(uint8_t *id_bin, char *id_str)
|
||||
{
|
||||
uint i, delta = 0, pos_extra, sum_extra = 0;
|
||||
|
||||
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
|
||||
sprintf(&id_str[2 * i + delta], "%02hhX", id_bin[i]);
|
||||
|
||||
if ((i + 1) == TOX_CLIENT_ID_SIZE)
|
||||
pos_extra = 2 * (i + 1) + delta;
|
||||
|
||||
if (i >= TOX_CLIENT_ID_SIZE)
|
||||
sum_extra |= id_bin[i];
|
||||
|
||||
if (!((i + 1) % FRADDR_TOSTR_CHUNK_LEN)) {
|
||||
id_str[2 * (i + 1) + delta] = ' ';
|
||||
delta++;
|
||||
}
|
||||
}
|
||||
|
||||
id_str[2 * i + delta] = 0;
|
||||
|
||||
if (!sum_extra)
|
||||
id_str[pos_extra] = 0;
|
||||
}
|
||||
|
||||
void* phone_handle_media_transport_poll ( void* _hmtc_args_p )
|
||||
{
|
||||
RTPMessage* _audio_msg, * _video_msg;
|
||||
av_session_t* _phone = _hmtc_args_p;
|
||||
MSISession* _session = _phone->_msi;
|
||||
|
||||
RTPSession* _rtp_audio = _phone->_rtp_audio;
|
||||
RTPSession* _rtp_video = _phone->_rtp_video;
|
||||
|
||||
|
||||
Tox* _messenger = _phone->_messenger;
|
||||
|
||||
|
||||
while ( _session->call ) {
|
||||
|
||||
_audio_msg = rtp_recv_msg ( _rtp_audio );
|
||||
_video_msg = rtp_recv_msg ( _rtp_video );
|
||||
|
||||
if ( _audio_msg ) {
|
||||
/* Do whatever with msg
|
||||
printf("%d - %s\n", _audio_msg->header->sequnum, _audio_msg->data);*/
|
||||
rtp_free_msg ( _rtp_audio, _audio_msg );
|
||||
}
|
||||
|
||||
if ( _video_msg ) {
|
||||
/* Do whatever with msg
|
||||
p rintf("%d - %s\n", _video_msg->header->sequnum, _video_msg->data);*/
|
||||
rtp_free_msg ( _rtp_video, _video_msg );
|
||||
}
|
||||
|
||||
/*
|
||||
* Send test message to the 'remote'
|
||||
*/
|
||||
rtp_send_msg ( _rtp_audio, _messenger, (const uint8_t*)"audio\0", 6 );
|
||||
|
||||
if ( _session->call->type_local == type_video ){ /* if local call send video */
|
||||
rtp_send_msg ( _rtp_video, _messenger, (const uint8_t*)"video\0", 6 );
|
||||
}
|
||||
|
||||
_audio_msg = _video_msg = NULL;
|
||||
|
||||
|
||||
/* Send ~1k messages per second
|
||||
* That _should_ be enough for both Audio and Video
|
||||
*/
|
||||
usleep ( 1000 );
|
||||
/* -------------------- */
|
||||
}
|
||||
|
||||
if ( _audio_msg ) rtp_free_msg(_rtp_audio, _audio_msg);
|
||||
rtp_release_session_recv(_rtp_audio);
|
||||
rtp_terminate_session(_rtp_audio, _messenger);
|
||||
|
||||
if ( _video_msg ) rtp_free_msg(_rtp_video, _video_msg);
|
||||
rtp_release_session_recv(_rtp_video);
|
||||
rtp_terminate_session(_rtp_video, _messenger);
|
||||
|
||||
INFO("Media thread finished!");
|
||||
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
int phone_startmedia_loop ( av_session_t* _phone )
|
||||
{
|
||||
if ( !_phone ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
_phone->_rtp_audio = rtp_init_session (
|
||||
type_audio,
|
||||
_phone->_messenger,
|
||||
_phone->_msi->call->peers[0],
|
||||
_phone->_msi->call->key_peer,
|
||||
_phone->_msi->call->key_local,
|
||||
_phone->_msi->call->nonce_peer,
|
||||
_phone->_msi->call->nonce_local
|
||||
);
|
||||
|
||||
_phone->_rtp_audio = rtp_init_session (
|
||||
type_video,
|
||||
_phone->_messenger,
|
||||
_phone->_msi->call->peers[0],
|
||||
_phone->_msi->call->key_peer,
|
||||
_phone->_msi->call->key_local,
|
||||
_phone->_msi->call->nonce_peer,
|
||||
_phone->_msi->call->nonce_local
|
||||
);
|
||||
|
||||
|
||||
if ( 0 > event.rise(phone_handle_media_transport_poll, _phone) )
|
||||
{
|
||||
printf("Error while starting phone_handle_media_transport_poll()\n");
|
||||
return -1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Some example callbacks */
|
||||
|
||||
void* callback_recv_invite ( void* _arg )
|
||||
{
|
||||
const char* _call_type;
|
||||
|
||||
MSISession* _msi = _arg;
|
||||
|
||||
switch ( _msi->call->type_peer[_msi->call->peer_count - 1] ){
|
||||
case type_audio:
|
||||
_call_type = "audio";
|
||||
break;
|
||||
case type_video:
|
||||
_call_type = "video";
|
||||
break;
|
||||
}
|
||||
|
||||
INFO( "Incoming %s call!", _call_type );
|
||||
|
||||
}
|
||||
void* callback_recv_ringing ( void* _arg )
|
||||
{
|
||||
INFO ( "Ringing!" );
|
||||
}
|
||||
void* callback_recv_starting ( void* _arg )
|
||||
{
|
||||
MSISession* _session = _arg;
|
||||
if ( 0 != phone_startmedia_loop(_session->agent_handler) ){
|
||||
INFO("Starting call failed!");
|
||||
} else {
|
||||
INFO ("Call started! ( press h to hangup )");
|
||||
}
|
||||
}
|
||||
void* callback_recv_ending ( void* _arg )
|
||||
{
|
||||
INFO ( "Call ended!" );
|
||||
}
|
||||
|
||||
void* callback_recv_error ( void* _arg )
|
||||
{
|
||||
MSISession* _session = _arg;
|
||||
|
||||
INFO( "Error: %s", _session->last_error_str );
|
||||
}
|
||||
|
||||
void* callback_call_started ( void* _arg )
|
||||
{
|
||||
MSISession* _session = _arg;
|
||||
if ( 0 != phone_startmedia_loop(_session->agent_handler) ){
|
||||
INFO("Starting call failed!");
|
||||
} else {
|
||||
INFO ("Call started! ( press h to hangup )");
|
||||
}
|
||||
|
||||
}
|
||||
void* callback_call_canceled ( void* _arg )
|
||||
{
|
||||
INFO ( "Call canceled!" );
|
||||
}
|
||||
void* callback_call_rejected ( void* _arg )
|
||||
{
|
||||
INFO ( "Call rejected!" );
|
||||
}
|
||||
void* callback_call_ended ( void* _arg )
|
||||
{
|
||||
INFO ( "Call ended!" );
|
||||
}
|
||||
|
||||
void* callback_requ_timeout ( void* _arg )
|
||||
{
|
||||
INFO( "No answer! " );
|
||||
}
|
||||
|
||||
int av_connect_to_dht(av_session_t* _phone, char* _dht_key, const char* _dht_addr, unsigned short _dht_port)
|
||||
{
|
||||
unsigned char *_binary_string = hex_string_to_bin(_dht_key);
|
||||
|
||||
uint16_t _port = htons(_dht_port);
|
||||
|
||||
int _if = tox_bootstrap_from_address(_phone->_messenger, _dht_addr, 1, _port, _binary_string );
|
||||
|
||||
free(_binary_string);
|
||||
|
||||
return _if ? 0 : -1;
|
||||
}
|
||||
|
||||
av_session_t* av_init_session()
|
||||
{
|
||||
av_session_t* _retu = malloc(sizeof(av_session_t));
|
||||
|
||||
/* Initialize our mutex */
|
||||
pthread_mutex_init ( &_retu->_mutex, NULL );
|
||||
|
||||
_retu->_messenger = tox_new(1);
|
||||
|
||||
if ( !_retu->_messenger ) {
|
||||
fprintf ( stderr, "tox_new() failed!\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->_friends = NULL;
|
||||
|
||||
_retu->_rtp_audio = NULL;
|
||||
_retu->_rtp_video = NULL;
|
||||
|
||||
uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(_retu->_messenger, _byte_address );
|
||||
fraddr_to_str( _byte_address, _retu->_my_public_id );
|
||||
|
||||
|
||||
/* Initialize msi */
|
||||
_retu->_msi = msi_init_session ( _retu->_messenger, _USERAGENT );
|
||||
|
||||
if ( !_retu->_msi ) {
|
||||
fprintf ( stderr, "msi_init_session() failed\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->_msi->agent_handler = _retu;
|
||||
|
||||
/* ------------------ */
|
||||
msi_register_callback(callback_call_started, cb_onstart);
|
||||
msi_register_callback(callback_call_canceled, cb_oncancel);
|
||||
msi_register_callback(callback_call_rejected, cb_onreject);
|
||||
msi_register_callback(callback_call_ended, cb_onend);
|
||||
msi_register_callback(callback_recv_invite, cb_oninvite);
|
||||
|
||||
msi_register_callback(callback_recv_ringing, cb_ringing);
|
||||
msi_register_callback(callback_recv_starting, cb_starting);
|
||||
msi_register_callback(callback_recv_ending, cb_ending);
|
||||
|
||||
msi_register_callback(callback_recv_error, cb_error);
|
||||
msi_register_callback(callback_requ_timeout, cb_timeout);
|
||||
/* ------------------ */
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
int av_terminate_session(av_session_t* _phone)
|
||||
{
|
||||
if ( _phone->_msi->call ){
|
||||
msi_hangup(_phone->_msi); /* Hangup the phone first */
|
||||
}
|
||||
|
||||
free(_phone->_friends);
|
||||
msi_terminate_session(_phone->_msi);
|
||||
pthread_mutex_destroy ( &_phone->_mutex );
|
||||
|
||||
Tox* _p = _phone->_messenger;
|
||||
_phone->_messenger = NULL; usleep(100000); /* Wait for tox_pool to end */
|
||||
tox_kill(_p);
|
||||
|
||||
printf("\r[i] Quit!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****** AV HELPER FUNCTIONS ******/
|
||||
|
||||
/* Auto accept friend request */
|
||||
void av_friend_requ(uint8_t *_public_key, uint8_t *_data, uint16_t _length, void *_userdata)
|
||||
{
|
||||
av_session_t* _phone = _userdata;
|
||||
av_allocate_friend (_phone, -1, 0);
|
||||
|
||||
INFO("Got friend request with message: %s", _data);
|
||||
|
||||
tox_add_friend_norequest(_phone->_messenger, _public_key);
|
||||
|
||||
INFO("Auto-accepted! Friend id: %d", _phone->_friends->_id );
|
||||
}
|
||||
|
||||
void av_friend_active(Tox *_messenger, int _friendnumber, uint8_t *_string, uint16_t _length, void *_userdata)
|
||||
{
|
||||
av_session_t* _phone = _userdata;
|
||||
INFO("Friend no. %d is online", _friendnumber);
|
||||
|
||||
av_friend_t* _this_friend = av_get_friend(_phone, _friendnumber);
|
||||
|
||||
if ( !_this_friend ) {
|
||||
INFO("But it's not registered!");
|
||||
return;
|
||||
}
|
||||
|
||||
(*_this_friend)._active = 1;
|
||||
}
|
||||
|
||||
int av_add_friend(av_session_t* _phone, char* _friend_hash)
|
||||
{
|
||||
trim_spaces(_friend_hash);
|
||||
|
||||
unsigned char *_bin_string = hex_string_to_bin(_friend_hash);
|
||||
int _number = tox_add_friend(_phone->_messenger, _bin_string, (uint8_t *)"Tox phone "_USERAGENT, sizeof("Tox phone "_USERAGENT));
|
||||
free(_bin_string);
|
||||
|
||||
if ( _number >= 0) {
|
||||
INFO("Added friend as %d", _number );
|
||||
av_allocate_friend(_phone, _number, 0);
|
||||
}
|
||||
else
|
||||
INFO("Unknown error %i", _number );
|
||||
|
||||
return _number;
|
||||
}
|
||||
/*********************************/
|
||||
|
||||
void do_phone ( av_session_t* _phone )
|
||||
{
|
||||
INFO("Welcome to tox_phone version: " _USERAGENT "\n"
|
||||
"Usage: \n"
|
||||
"f [pubkey] (add friend)\n"
|
||||
"c [a/v] (type) [friend] (friend id) (calls friend if online)\n"
|
||||
"h (if call is active hang up)\n"
|
||||
"a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n"
|
||||
"r (reject incoming call)\n"
|
||||
"q (quit)\n"
|
||||
"================================================================================"
|
||||
);
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
char _line [ 1500 ];
|
||||
int _len;
|
||||
|
||||
if ( -1 == getinput(_line, 1500, &_len) ){
|
||||
printf(" >> ");
|
||||
fflush(stdout);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ){
|
||||
INFO("Invalid input!");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (_line[0]){
|
||||
|
||||
case 'f':
|
||||
{
|
||||
char _id [128];
|
||||
strncpy(_id, _line + 2, 128);
|
||||
|
||||
av_add_friend(_phone, _id);
|
||||
|
||||
} break;
|
||||
case 'c':
|
||||
{
|
||||
if ( _phone->_msi->call ){
|
||||
INFO("Already in a call");
|
||||
break;
|
||||
}
|
||||
|
||||
MSICallType _ctype;
|
||||
|
||||
if ( _len < 5 ){
|
||||
INFO("Invalid input; usage: c a/v [friend]");
|
||||
break;
|
||||
}
|
||||
else if ( _line[2] == 'a' || _line[2] != 'v' ){ /* default and audio */
|
||||
_ctype = type_audio;
|
||||
}
|
||||
else { /* video */
|
||||
_ctype = type_video;
|
||||
}
|
||||
|
||||
char* _end;
|
||||
int _friend = strtol(_line + 4, &_end, 10);
|
||||
|
||||
if ( *_end ){
|
||||
INFO("Friend num has to be numerical value");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set timeout */
|
||||
msi_invite ( _phone->_msi, _ctype, 10 * 1000, _friend );
|
||||
INFO("Calling friend: %d!", _friend);
|
||||
|
||||
} break;
|
||||
case 'h':
|
||||
{
|
||||
if ( !_phone->_msi->call ){
|
||||
INFO("No call!");
|
||||
break;
|
||||
}
|
||||
|
||||
msi_hangup(_phone->_msi);
|
||||
|
||||
INFO("Hung up...");
|
||||
|
||||
} break;
|
||||
case 'a':
|
||||
{
|
||||
|
||||
if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( _len > 1 && _line[2] == 'v' )
|
||||
msi_answer(_phone->_msi, type_video);
|
||||
else
|
||||
msi_answer(_phone->_msi, type_audio);
|
||||
|
||||
} break;
|
||||
case 'r':
|
||||
{
|
||||
if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ){
|
||||
break;
|
||||
}
|
||||
|
||||
msi_reject(_phone->_msi);
|
||||
|
||||
INFO("Call Rejected...");
|
||||
|
||||
} break;
|
||||
case 'q':
|
||||
{
|
||||
INFO("Quitting!");
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
INFO("Invalid command!");
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void* tox_poll (void* _messenger_p)
|
||||
{
|
||||
Tox** _messenger = _messenger_p;
|
||||
while( *_messenger ) {
|
||||
tox_do(*_messenger);
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int av_wait_dht(av_session_t* _phone, int _wait_seconds, const char* _ip, char* _key, unsigned short _port)
|
||||
{
|
||||
if ( !_wait_seconds )
|
||||
return -1;
|
||||
|
||||
int _waited = 0;
|
||||
|
||||
while( !tox_isconnected(_phone->_messenger) ) {
|
||||
|
||||
if ( -1 == av_connect_to_dht(_phone, _key, _ip, _port) )
|
||||
{
|
||||
INFO("Could not connect to: %s", _ip);
|
||||
av_terminate_session(_phone);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( _waited >= _wait_seconds ) return 0;
|
||||
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
|
||||
_waited ++;
|
||||
usleep(1000000);
|
||||
}
|
||||
|
||||
int _r = _wait_seconds - _waited;
|
||||
return _r ? _r : 1;
|
||||
}
|
||||
/* ---------------------- */
|
||||
|
||||
int print_help ( const char* _name )
|
||||
{
|
||||
printf ( "Usage: %s [IP] [PORT] [KEY]\n"
|
||||
"\t[IP] (DHT ip)\n"
|
||||
"\t[PORT] (DHT port)\n"
|
||||
"\t[KEY] (DHT public key)\n"
|
||||
"P.S. Friends and key are stored in ./tox_phone.conf\n"
|
||||
,_name );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main ( int argc, char* argv [] )
|
||||
{
|
||||
if ( argc < 1 || argc < 4 )
|
||||
return print_help(argv[0]);
|
||||
|
||||
char* _convertable;
|
||||
|
||||
int _wait_seconds = 5;
|
||||
|
||||
const char* _ip = argv[1];
|
||||
char* _key = argv[3];
|
||||
unsigned short _port = strtol(argv[2], &_convertable, 10);
|
||||
|
||||
if ( *_convertable ){
|
||||
printf("Invalid port: cannot convert string to long: %s", _convertable);
|
||||
return 1;
|
||||
}
|
||||
|
||||
av_session_t* _phone = av_init_session();
|
||||
|
||||
tox_callback_friend_request(_phone->_messenger, av_friend_requ, _phone);
|
||||
tox_callback_status_message(_phone->_messenger, av_friend_active, _phone);
|
||||
|
||||
system("clear");
|
||||
|
||||
INFO("\r================================================================================\n"
|
||||
"[!] Trying dht@%s:%d"
|
||||
, _ip, _port);
|
||||
|
||||
/* Start tox protocol */
|
||||
event.rise( tox_poll, &_phone->_messenger );
|
||||
|
||||
/* Just clean one line */
|
||||
printf("\r \r");
|
||||
fflush(stdout);
|
||||
|
||||
int _r;
|
||||
for ( _r = 0; _r == 0; _r = av_wait_dht(_phone, _wait_seconds, _ip, _key, _port) ) _wait_seconds --;
|
||||
|
||||
|
||||
if ( -1 == _r ) {
|
||||
INFO("Error while connecting to dht: %s:%d", _ip, _port);
|
||||
av_terminate_session(_phone);
|
||||
return 1;
|
||||
}
|
||||
|
||||
INFO("CONNECTED!\n"
|
||||
"================================================================================\n"
|
||||
"%s\n"
|
||||
"================================================================================"
|
||||
, _phone->_my_public_id );
|
||||
|
||||
|
||||
do_phone (_phone);
|
||||
|
||||
av_terminate_session(_phone);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -70,7 +70,7 @@
|
|||
#define DEFAULT_WEBCAM "/dev/video0"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
|
||||
#ifdef WIN32
|
||||
#define VIDEO_DRIVER "vfwcap"
|
||||
#define DEFAULT_WEBCAM "0"
|
||||
#endif
|
1337
toxav/toxmsi.c
Executable file
1337
toxav/toxmsi.c
Executable file
File diff suppressed because it is too large
Load Diff
231
toxav/toxmsi.h
Executable file
231
toxav/toxmsi.h
Executable file
|
@ -0,0 +1,231 @@
|
|||
/** toxmsi.h
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
#ifndef __TOXMSI
|
||||
#define __TOXMSI
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "../toxcore/tox.h"
|
||||
#include <pthread.h>
|
||||
|
||||
/* define size for call_id */
|
||||
#define CALL_ID_LEN 12
|
||||
|
||||
|
||||
typedef void* ( *MSICallback ) ( void* arg );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Call type identifier. Also used as rtp callback prefix.
|
||||
*/
|
||||
typedef enum {
|
||||
type_audio = 70,
|
||||
type_video,
|
||||
} MSICallType;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Call state identifiers.
|
||||
*/
|
||||
typedef enum {
|
||||
call_inviting, /* when sending call invite */
|
||||
call_starting, /* when getting call invite */
|
||||
call_active,
|
||||
call_hold
|
||||
|
||||
} MSICallState;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief The call struct.
|
||||
*
|
||||
*/
|
||||
typedef struct _MSICall { /* Call info structure */
|
||||
MSICallState state;
|
||||
|
||||
MSICallType type_local; /* Type of payload user is ending */
|
||||
MSICallType* type_peer; /* Type of payload others are sending */
|
||||
|
||||
uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
|
||||
|
||||
uint8_t* key_local; /* The key for encryption */
|
||||
uint8_t* key_peer; /* The key for decryption */
|
||||
|
||||
uint8_t* nonce_local; /* Local nonce */
|
||||
uint8_t* nonce_peer; /* Peer nonce */
|
||||
|
||||
int ringing_tout_ms; /* Ringing timeout in ms */
|
||||
|
||||
int request_timer_id; /* Timer id for outgoing request/action */
|
||||
int ringing_timer_id; /* Timer id for ringing timeout */
|
||||
|
||||
pthread_mutex_t mutex; /* It's to be assumed that call will have
|
||||
* seperate thread so add mutex
|
||||
*/
|
||||
uint32_t* peers;
|
||||
uint16_t peer_count;
|
||||
|
||||
|
||||
} MSICall;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Control session struct
|
||||
*
|
||||
*/
|
||||
typedef struct _MSISession {
|
||||
|
||||
/* Call handler */
|
||||
struct _MSICall* call;
|
||||
|
||||
int last_error_id; /* Determine the last error */
|
||||
const uint8_t* last_error_str;
|
||||
|
||||
const uint8_t* user_agent;
|
||||
|
||||
void* agent_handler; /* Pointer to an object that is handling msi */
|
||||
Tox* messenger_handle;
|
||||
|
||||
uint32_t frequ;
|
||||
uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
|
||||
|
||||
|
||||
} MSISession;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks ids that handle the states
|
||||
*/
|
||||
typedef enum {
|
||||
/* Requests */
|
||||
cb_oninvite,
|
||||
cb_onstart,
|
||||
cb_oncancel,
|
||||
cb_onreject,
|
||||
cb_onend,
|
||||
|
||||
/* Responses */
|
||||
cb_ringing,
|
||||
cb_starting,
|
||||
cb_ending,
|
||||
|
||||
/* Protocol */
|
||||
cb_error,
|
||||
cb_timeout,
|
||||
|
||||
} MSICallbackID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback setter.
|
||||
*
|
||||
* @param callback The callback.
|
||||
* @param id The id.
|
||||
* @return void
|
||||
*/
|
||||
void msi_register_callback(MSICallback callback, MSICallbackID id);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the control session.
|
||||
*
|
||||
* @param messenger Tox* object.
|
||||
* @param user_agent User agent, i.e. 'Venom'; 'QT-gui'
|
||||
* @return MSISession* The created session.
|
||||
* @retval NULL Error occured.
|
||||
*/
|
||||
MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Terminate control session.
|
||||
*
|
||||
* @param session The session
|
||||
* @return int
|
||||
*/
|
||||
int msi_terminate_session ( MSISession* session );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send invite request to friend_id.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @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_invite ( MSISession* session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Hangup active call.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @return int
|
||||
* @retval -1 Error occured.
|
||||
* @retval 0 Success.
|
||||
*/
|
||||
int msi_hangup ( MSISession* session );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Answer active call request.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @param call_type Answer with Audio or Video(both).
|
||||
* @return int
|
||||
*/
|
||||
int msi_answer ( MSISession* session, MSICallType call_type );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cancel request.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @param friend_id The friend.
|
||||
* @return int
|
||||
*/
|
||||
int msi_cancel ( MSISession* session, int friend_id );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reject request.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @return int
|
||||
*/
|
||||
int msi_reject ( MSISession* session );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Terminate the current call.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @return int
|
||||
*/
|
||||
int msi_stopcall ( MSISession* session );
|
||||
|
||||
#endif /* __TOXMSI */
|
878
toxav/toxrtp.c
Executable file
878
toxav/toxrtp.c
Executable file
|
@ -0,0 +1,878 @@
|
|||
/** toxrtp.c
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp.h"
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "../toxcore/util.h"
|
||||
#include "../toxcore/network.h"
|
||||
#include "../toxcore/net_crypto.h"
|
||||
#include "../toxcore/Messenger.h"
|
||||
|
||||
#define PAYLOAD_ID_VALUE_OPUS 1
|
||||
#define PAYLOAD_ID_VALUE_VP8 2
|
||||
|
||||
#define MAX_SEQU_NUM 65535
|
||||
|
||||
#define size_32 4
|
||||
|
||||
#define inline__ inline __attribute__((always_inline))
|
||||
|
||||
|
||||
#define ADD_FLAG_VERSION(_h, _v) do { ( _h->flags ) &= 0x3F; ( _h->flags ) |= ( ( ( _v ) << 6 ) & 0xC0 ); } while(0)
|
||||
#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0)
|
||||
#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0)
|
||||
#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0)
|
||||
#define ADD_SETTING_MARKER(_h, _v) do { if ( _v > 1 ) _v = 1; ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0)
|
||||
#define ADD_SETTING_PAYLOAD(_h, _v) do { if ( _v > 127 ) _v = 127; ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0)
|
||||
|
||||
#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6)
|
||||
#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5)
|
||||
#define GET_FLAG_EXTENSION(_h) (( _h->flags & 0x10 ) >> 4)
|
||||
#define GET_FLAG_CSRCC(_h) ( _h->flags & 0x0f )
|
||||
#define GET_SETTING_MARKER(_h) (( _h->marker_payloadt ) >> 7)
|
||||
#define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if message came in late.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @param msg The message.
|
||||
* @return int
|
||||
* @retval -1 The message came in order.
|
||||
* @retval 0 The message came late.
|
||||
*/
|
||||
inline__ int check_late_message (RTPSession* session, RTPMessage* msg)
|
||||
{
|
||||
/*
|
||||
* Check Sequence number. If this new msg has lesser number then the session->rsequnum
|
||||
* it shows that the message came in late. Also check timestamp to be 100% certain.
|
||||
*
|
||||
*/
|
||||
return ( msg->header->sequnum < session->rsequnum && msg->header->timestamp < session->timestamp ) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Increases nonce value by 'target'
|
||||
*
|
||||
* @param nonce The nonce
|
||||
* @param target The target
|
||||
* @return void
|
||||
*/
|
||||
inline__ void increase_nonce(uint8_t* nonce, uint16_t target)
|
||||
{
|
||||
uint16_t _nonce_counter = ((uint16_t)(
|
||||
(((uint16_t) nonce [crypto_box_NONCEBYTES - 1]) << 8 ) |
|
||||
(((uint16_t) nonce [crypto_box_NONCEBYTES - 2]) )));
|
||||
|
||||
/* Check overflow */
|
||||
if (_nonce_counter > USHRT_MAX - target ) { /* 2 bytes are not long enough */
|
||||
int _it = 3;
|
||||
while ( _it <= crypto_box_NONCEBYTES ) _it += ++nonce[crypto_box_NONCEBYTES - _it] ? crypto_box_NONCEBYTES : 1;
|
||||
|
||||
_nonce_counter = _nonce_counter - (USHRT_MAX - target ); /* Assign the rest of it */
|
||||
} else { /* Increase nonce */
|
||||
|
||||
_nonce_counter+= target;
|
||||
}
|
||||
|
||||
/* Assign the 8 last bytes */
|
||||
|
||||
nonce [crypto_box_NONCEBYTES - 1] = (uint8_t) (_nonce_counter >> 8);
|
||||
nonce [crypto_box_NONCEBYTES - 2] = (uint8_t) (_nonce_counter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Speaks for it self.
|
||||
*
|
||||
*/
|
||||
static const uint32_t payload_table[] =
|
||||
{
|
||||
8000, 8000, 8000, 8000, 8000, 8000, 16000, 8000, 8000, 8000, /* 0-9 */
|
||||
44100, 44100, 0, 0, 90000, 8000, 11025, 22050, 0, 0, /* 10-19 */
|
||||
0, 0, 0, 0, 0, 90000, 90000, 0, 90000, 0, /* 20-29 */
|
||||
0, 90000, 90000, 90000, 90000, 0, 0, 0, 0, 0, /* 30-39 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-49 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-59 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-69 */
|
||||
PAYLOAD_ID_VALUE_OPUS, PAYLOAD_ID_VALUE_VP8, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-79 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-89 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-99 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 100-109 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 110-119 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0 /* 120-127 */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Extracts header from payload.
|
||||
*
|
||||
* @param payload The payload.
|
||||
* @param length The size of payload.
|
||||
* @return RTPHeader* Extracted header.
|
||||
* @retval NULL Error occurred while extracting header.
|
||||
*/
|
||||
RTPHeader* extract_header ( const uint8_t* payload, size_t length )
|
||||
{
|
||||
if ( !payload ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint8_t* _it = payload;
|
||||
|
||||
RTPHeader* _retu = calloc(sizeof(RTPHeader), 1);
|
||||
assert(_retu);
|
||||
|
||||
_retu->flags = *_it; ++_it;
|
||||
|
||||
/* This indicates if the first 2 bytes are valid.
|
||||
* Now it my 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 */
|
||||
free(_retu);
|
||||
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 );
|
||||
uint32_t _length = 12 /* Minimum header len */ + ( _cc * 4 );
|
||||
|
||||
if ( length < _length ) {
|
||||
/* Deallocate */
|
||||
free(_retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( _cc > 0 ) {
|
||||
_retu->csrc = calloc ( sizeof ( uint32_t ), _cc );
|
||||
assert(_retu->csrc);
|
||||
|
||||
} else { /* But this should not happen ever */
|
||||
/* Deallocate */
|
||||
free(_retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
_retu->marker_payloadt = *_it; ++_it;
|
||||
_retu->length = _length;
|
||||
|
||||
_retu->timestamp = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( * ( _it + 3 ) ) ;
|
||||
|
||||
_it += 4;
|
||||
|
||||
_retu->ssrc = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( ( uint32_t ) * ( _it + 3 ) ) ;
|
||||
|
||||
|
||||
size_t _x;
|
||||
for ( _x = 0; _x < _cc; _x++ ) {
|
||||
_it += 4;
|
||||
_retu->csrc[_x] = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( ( uint32_t ) * ( _it + 3 ) ) ;
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts external header from payload. Must be called AFTER extract_header()!
|
||||
*
|
||||
* @param payload The ITERATED payload.
|
||||
* @param length The size of payload.
|
||||
* @return RTPExtHeader* Extracted extension header.
|
||||
* @retval NULL Error occurred while extracting extension header.
|
||||
*/
|
||||
RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length )
|
||||
{
|
||||
const uint8_t* _it = payload;
|
||||
|
||||
RTPExtHeader* _retu = calloc(sizeof(RTPExtHeader), 1);
|
||||
assert(_retu);
|
||||
|
||||
uint16_t _ext_length = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it += 2;
|
||||
|
||||
if ( length < ( _ext_length * sizeof(uint32_t) ) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->length = _ext_length;
|
||||
_retu->type = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it -= 2;
|
||||
|
||||
_retu->table = calloc(sizeof(uint32_t), _ext_length );
|
||||
assert(_retu->table);
|
||||
|
||||
uint32_t* _table = _retu->table;
|
||||
size_t _i;
|
||||
for ( _i = 0; _i < _ext_length; _i++ ) {
|
||||
_it += 4;
|
||||
_table[_i] = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( ( uint32_t ) * ( _it + 3 ) ) ;
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds header to payload. Make sure _payload_ has enough space.
|
||||
*
|
||||
* @param header The header.
|
||||
* @param payload The payload.
|
||||
* @return uint8_t* Iterated position.
|
||||
*/
|
||||
uint8_t* add_header ( RTPHeader* header, uint8_t* payload )
|
||||
{
|
||||
uint8_t _cc = GET_FLAG_CSRCC ( header );
|
||||
|
||||
uint8_t* _it = payload;
|
||||
|
||||
|
||||
/* Add sequence number first */
|
||||
*_it = ( header->sequnum >> 8 ); ++_it;
|
||||
*_it = ( header->sequnum ); ++_it;
|
||||
|
||||
*_it = header->flags; ++_it;
|
||||
*_it = header->marker_payloadt; ++_it;
|
||||
|
||||
|
||||
uint32_t _timestamp = header->timestamp;
|
||||
*_it = ( _timestamp >> 24 ); ++_it;
|
||||
*_it = ( _timestamp >> 16 ); ++_it;
|
||||
*_it = ( _timestamp >> 8 ); ++_it;
|
||||
*_it = ( _timestamp ); ++_it;
|
||||
|
||||
uint32_t _ssrc = header->ssrc;
|
||||
*_it = ( _ssrc >> 24 ); ++_it;
|
||||
*_it = ( _ssrc >> 16 ); ++_it;
|
||||
*_it = ( _ssrc >> 8 ); ++_it;
|
||||
*_it = ( _ssrc );
|
||||
|
||||
uint32_t *_csrc = header->csrc;
|
||||
size_t _x;
|
||||
for ( _x = 0; _x < _cc; _x++ ) {
|
||||
++_it;
|
||||
*_it = ( _csrc[_x] >> 24 ); ++_it;
|
||||
*_it = ( _csrc[_x] >> 16 ); ++_it;
|
||||
*_it = ( _csrc[_x] >> 8 ); ++_it;
|
||||
*_it = ( _csrc[_x] );
|
||||
}
|
||||
|
||||
return _it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds extension header to payload. Make sure _payload_ has enough space.
|
||||
*
|
||||
* @param header The header.
|
||||
* @param payload The payload.
|
||||
* @return uint8_t* Iterated position.
|
||||
*/
|
||||
uint8_t* add_ext_header ( RTPExtHeader* header, uint8_t* payload )
|
||||
{
|
||||
uint8_t* _it = payload;
|
||||
|
||||
*_it = ( header->length >> 8 ); _it++;
|
||||
*_it = ( header->length ); _it++;
|
||||
|
||||
*_it = ( header->type >> 8 ); ++_it;
|
||||
*_it = ( header->type );
|
||||
|
||||
size_t x;
|
||||
|
||||
uint32_t* _hd_ext = header->table;
|
||||
for ( x = 0; x < header->length; x++ ) {
|
||||
++_it;
|
||||
*_it = ( _hd_ext[x] >> 24 ); ++_it;
|
||||
*_it = ( _hd_ext[x] >> 16 ); ++_it;
|
||||
*_it = ( _hd_ext[x] >> 8 ); ++_it;
|
||||
*_it = ( _hd_ext[x] );
|
||||
}
|
||||
|
||||
return _it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Builds header from control session values.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @return RTPHeader* Created header.
|
||||
*/
|
||||
RTPHeader* build_header ( RTPSession* session )
|
||||
{
|
||||
RTPHeader* _retu;
|
||||
_retu = calloc ( sizeof * _retu, 1 );
|
||||
assert(_retu);
|
||||
|
||||
ADD_FLAG_VERSION ( _retu, session->version );
|
||||
ADD_FLAG_PADDING ( _retu, session->padding );
|
||||
ADD_FLAG_EXTENSION ( _retu, session->extension );
|
||||
ADD_FLAG_CSRCC ( _retu, session->cc );
|
||||
ADD_SETTING_MARKER ( _retu, session->marker );
|
||||
ADD_SETTING_PAYLOAD ( _retu, session->payload_type );
|
||||
|
||||
_retu->sequnum = session->sequnum;
|
||||
_retu->timestamp = ((uint32_t)(current_time() / 1000)); /* micro to milli */
|
||||
_retu->ssrc = session->ssrc;
|
||||
|
||||
if ( session->cc > 0 ) {
|
||||
_retu->csrc = calloc(sizeof(uint32_t), session->cc);
|
||||
assert(_retu->csrc);
|
||||
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < session->cc; i++ ) {
|
||||
_retu->csrc[i] = session->csrc[i];
|
||||
}
|
||||
} else {
|
||||
_retu->csrc = NULL;
|
||||
}
|
||||
|
||||
_retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parses data into RTPMessage struct. Stores headers separately from the payload data
|
||||
* and so the length variable is set accordingly. _sequnum_ argument is
|
||||
* passed by the handle_packet() since it's parsed already.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @param sequnum Sequence number that's parsed from payload in handle_packet()
|
||||
* @param data Payload data.
|
||||
* @param length Payload size.
|
||||
* @return RTPMessage*
|
||||
* @retval NULL Error occurred.
|
||||
*/
|
||||
RTPMessage* msg_parse ( RTPSession* session, uint16_t sequnum, const uint8_t* data, uint32_t length )
|
||||
{
|
||||
assert( length != -1);
|
||||
|
||||
RTPMessage* _retu = calloc(sizeof(RTPMessage), 1);
|
||||
assert(_retu);
|
||||
|
||||
_retu->header = extract_header ( data, length ); /* It allocates memory and all */
|
||||
|
||||
if ( !_retu->header ){
|
||||
free(_retu);
|
||||
return NULL;
|
||||
}
|
||||
_retu->header->sequnum = sequnum;
|
||||
|
||||
_retu->length = length - _retu->header->length;
|
||||
|
||||
uint16_t _from_pos = _retu->header->length - 2 /* Since sequ num is excluded */ ;
|
||||
|
||||
|
||||
if ( GET_FLAG_EXTENSION ( _retu->header ) ) {
|
||||
_retu->ext_header = extract_ext_header ( data + _from_pos, length );
|
||||
if ( _retu->ext_header ){
|
||||
_retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
||||
_from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
||||
} else {
|
||||
free (_retu->ext_header);
|
||||
free (_retu->header);
|
||||
free (_retu);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
_retu->ext_header = NULL;
|
||||
}
|
||||
|
||||
/* Get the payload */
|
||||
_retu->data = calloc ( sizeof ( uint8_t ), _retu->length );
|
||||
assert(_retu->data);
|
||||
|
||||
memcpy ( _retu->data, data + _from_pos, length - _from_pos );
|
||||
|
||||
_retu->next = NULL;
|
||||
|
||||
|
||||
if ( session && check_late_message ( session, _retu) < 0 ){
|
||||
session->rsequnum = _retu->header->sequnum;
|
||||
session->timestamp = _retu->header->timestamp;
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback for networking core.
|
||||
*
|
||||
* @param object RTPSession object.
|
||||
* @param ip_port Where the message comes from.
|
||||
* @param data Message data.
|
||||
* @param length Message length.
|
||||
* @return int
|
||||
* @retval -1 Error occurred.
|
||||
* @retval 0 Success.
|
||||
*/
|
||||
int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t length )
|
||||
{
|
||||
RTPSession* _session = object;
|
||||
RTPMessage* _msg;
|
||||
|
||||
if ( !_session )
|
||||
return -1;
|
||||
|
||||
uint8_t _plain[MAX_UDP_PACKET_SIZE];
|
||||
|
||||
uint16_t _sequnum = ( ( uint16_t ) data[1] << 8 ) | data[2];
|
||||
|
||||
/* Clculate the right nonce */
|
||||
uint8_t _calculated[crypto_box_NONCEBYTES];
|
||||
memcpy(_calculated, _session->decrypt_nonce, crypto_box_NONCEBYTES);
|
||||
increase_nonce ( _calculated, _sequnum );
|
||||
|
||||
/* Decrypt message */
|
||||
int _decrypted_length = decrypt_data_symmetric(
|
||||
(uint8_t*)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
|
||||
|
||||
/* This packet is either not encrypted properly or late
|
||||
*/
|
||||
if ( -1 == _decrypted_length ){
|
||||
|
||||
/* If this is the case, then the packet is most likely late.
|
||||
* Try with old nonce cycle.
|
||||
*/
|
||||
if ( _session->rsequnum < _sequnum ) {
|
||||
_decrypted_length = decrypt_data_symmetric(
|
||||
(uint8_t*)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain );
|
||||
|
||||
if ( !_decrypted_length ) return -1; /* This packet is not encrypted properly */
|
||||
|
||||
/* Otherwise, if decryption is ok with new cycle, set new cycle
|
||||
*/
|
||||
} else {
|
||||
increase_nonce ( _calculated, MAX_SEQU_NUM );
|
||||
_decrypted_length = decrypt_data_symmetric(
|
||||
(uint8_t*)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
|
||||
|
||||
if ( !_decrypted_length ) return -1; /* This is just an error */
|
||||
|
||||
/* A new cycle setting. */
|
||||
memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(_session->decrypt_nonce, _calculated, crypto_box_NONCEBYTES);
|
||||
}
|
||||
}
|
||||
|
||||
_msg = msg_parse ( NULL, _sequnum, _plain, _decrypted_length );
|
||||
|
||||
if ( !_msg )
|
||||
return -1;
|
||||
|
||||
/* Hopefully this goes well
|
||||
* NOTE: Is this even used?
|
||||
*/
|
||||
memcpy(&_msg->from, &ip_port, sizeof(tox_IP_Port));
|
||||
|
||||
/* Check if message came in late */
|
||||
if ( check_late_message(_session, _msg) < 0 ) { /* Not late */
|
||||
_session->rsequnum = _msg->header->sequnum;
|
||||
_session->timestamp = _msg->header->timestamp;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_session->mutex);
|
||||
|
||||
if ( _session->last_msg ) {
|
||||
_session->last_msg->next = _msg;
|
||||
_session->last_msg = _msg;
|
||||
} else {
|
||||
_session->last_msg = _session->oldest_msg = _msg;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_session->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stores headers and payload data in one container ( data )
|
||||
* and the length is set accordingly. Returned message is used for sending _only_.
|
||||
*
|
||||
* @param session The control session.
|
||||
* @param data Payload data to send ( This is what you pass ).
|
||||
* @param length Size of the payload data.
|
||||
* @return RTPMessage* Created message.
|
||||
* @retval NULL Error occurred.
|
||||
*/
|
||||
RTPMessage* rtp_new_message ( RTPSession* session, const uint8_t* data, uint32_t length )
|
||||
{
|
||||
if ( !session )
|
||||
return NULL;
|
||||
|
||||
uint8_t* _from_pos;
|
||||
RTPMessage* _retu = calloc(sizeof(RTPMessage), 1);
|
||||
assert(_retu);
|
||||
|
||||
/* Sets header values and copies the extension header in _retu */
|
||||
_retu->header = build_header ( session ); /* It allocates memory and all */
|
||||
_retu->ext_header = session->ext_header;
|
||||
|
||||
|
||||
uint32_t _total_length = length + _retu->header->length;
|
||||
|
||||
if ( _retu->ext_header ) {
|
||||
_total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
|
||||
/* Allocate Memory for _retu->_data */
|
||||
_retu->data = calloc ( sizeof _retu->data, _total_length );
|
||||
assert(_retu->data);
|
||||
|
||||
_from_pos = add_header ( _retu->header, _retu->data );
|
||||
_from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 );
|
||||
} else {
|
||||
/* Allocate Memory for _retu->_data */
|
||||
_retu->data = calloc ( sizeof _retu->data, _total_length );
|
||||
assert(_retu->data);
|
||||
|
||||
_from_pos = add_header ( _retu->header, _retu->data );
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the extension header into the message
|
||||
* Of course if any
|
||||
*/
|
||||
|
||||
/* Appends _data on to _retu->_data */
|
||||
memcpy ( _from_pos + 1, data, length );
|
||||
|
||||
_retu->length = _total_length;
|
||||
|
||||
_retu->next = NULL;
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
* PUBLIC API FUNCTIONS IMPLEMENTATIONS
|
||||
*
|
||||
*
|
||||
*
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @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 ){
|
||||
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;
|
||||
|
||||
pthread_mutex_unlock(&session->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get's oldes 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 )
|
||||
return NULL;
|
||||
|
||||
RTPMessage* _retu = session->oldest_msg;
|
||||
|
||||
pthread_mutex_lock(&session->mutex);
|
||||
|
||||
if ( _retu )
|
||||
session->oldest_msg = _retu->next;
|
||||
|
||||
if ( !session->oldest_msg )
|
||||
session->last_msg = NULL;
|
||||
|
||||
pthread_mutex_unlock(&session->mutex);
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends data to _RTPSession::dest
|
||||
*
|
||||
* @param session The session.
|
||||
* @param messenger Tox* object.
|
||||
* @param data The payload.
|
||||
* @param length Size of the payload.
|
||||
* @return int
|
||||
* @retval -1 On error.
|
||||
* @retval 0 On success.
|
||||
*/
|
||||
int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length )
|
||||
{
|
||||
RTPMessage* msg = rtp_new_message (session, data, length);
|
||||
|
||||
if ( !msg ) return -1;
|
||||
|
||||
uint8_t _send_data [ MAX_UDP_PACKET_SIZE ];
|
||||
|
||||
_send_data[0] = session->prefix;
|
||||
|
||||
/* Generate the right nonce */
|
||||
uint8_t _calculated[crypto_box_NONCEBYTES];
|
||||
memcpy(_calculated, session->encrypt_nonce, crypto_box_NONCEBYTES);
|
||||
increase_nonce ( _calculated, msg->header->sequnum );
|
||||
|
||||
/* Need to skip 2 bytes that are for sequnum */
|
||||
int encrypted_length = encrypt_data_symmetric(
|
||||
(uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length - 2, _send_data + 3 );
|
||||
|
||||
int full_length = encrypted_length + 3;
|
||||
|
||||
_send_data[1] = msg->data[0];
|
||||
_send_data[2] = msg->data[1];
|
||||
|
||||
|
||||
if ( full_length != sendpacket ( ((Messenger*)messenger)->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {
|
||||
printf("Rtp error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Set sequ number */
|
||||
if ( session->sequnum >= MAX_SEQU_NUM ) {
|
||||
session->sequnum = 0;
|
||||
memcpy(session->encrypt_nonce, _calculated, crypto_box_NONCEBYTES);
|
||||
} else {
|
||||
session->sequnum++;
|
||||
}
|
||||
|
||||
rtp_free_msg ( session, msg );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Speaks for it self.
|
||||
*
|
||||
* @param session The control session msg belongs to. It can be NULL.
|
||||
* @param msg The message.
|
||||
* @return void
|
||||
*/
|
||||
void rtp_free_msg ( RTPSession* session, RTPMessage* msg )
|
||||
{
|
||||
free ( msg->data );
|
||||
|
||||
if ( !session ){
|
||||
free ( msg->header->csrc );
|
||||
if ( msg->ext_header ){
|
||||
free ( msg->ext_header->table );
|
||||
free ( msg->ext_header );
|
||||
}
|
||||
} else {
|
||||
if ( session->csrc != msg->header->csrc )
|
||||
free ( msg->header->csrc );
|
||||
if ( msg->ext_header && session->ext_header != msg->ext_header ) {
|
||||
free ( msg->ext_header->table );
|
||||
free ( msg->ext_header );
|
||||
}
|
||||
}
|
||||
|
||||
free ( msg->header );
|
||||
free ( msg );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Must be called before calling any other rtp function. It's used
|
||||
* to initialize RTP control session.
|
||||
*
|
||||
* @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType
|
||||
* @param messenger Tox* object.
|
||||
* @param friend_num Friend id.
|
||||
* @param encrypt_key Speaks for it self.
|
||||
* @param decrypt_key Speaks for it self.
|
||||
* @param encrypt_nonce Speaks for it self.
|
||||
* @param decrypt_nonce Speaks for it self.
|
||||
* @return RTPSession* Created control session.
|
||||
* @retval NULL Error occurred.
|
||||
*/
|
||||
RTPSession* rtp_init_session ( int payload_type,
|
||||
Tox* messenger,
|
||||
int friend_num,
|
||||
const uint8_t* encrypt_key,
|
||||
const uint8_t* decrypt_key,
|
||||
const uint8_t* encrypt_nonce,
|
||||
const uint8_t* decrypt_nonce
|
||||
)
|
||||
{
|
||||
Messenger* _messenger_casted = (Messenger*) messenger;
|
||||
|
||||
IP_Port _dest = get_friend_ipport(_messenger_casted, friend_num );
|
||||
|
||||
/* This should be enough eh? */
|
||||
if ( _dest.port == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RTPSession* _retu = calloc(sizeof(RTPSession), 1);
|
||||
assert(_retu);
|
||||
|
||||
networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu);
|
||||
|
||||
_retu->version = RTP_VERSION; /* It's always 2 */
|
||||
_retu->padding = 0; /* If some additional data is needed about the packet */
|
||||
_retu->extension = 0; /* If extension to header is needed */
|
||||
_retu->cc = 1; /* Amount of contributors */
|
||||
_retu->csrc = NULL; /* Container */
|
||||
_retu->ssrc = randombytes_random();
|
||||
_retu->marker = 0;
|
||||
_retu->payload_type = payload_table[payload_type];
|
||||
|
||||
_retu->dest = *((tox_IP_Port*)&_dest);
|
||||
|
||||
_retu->rsequnum = _retu->sequnum = 1;
|
||||
|
||||
_retu->ext_header = NULL; /* When needed allocate */
|
||||
_retu->framerate = -1;
|
||||
_retu->resolution = -1;
|
||||
|
||||
_retu->encrypt_key = encrypt_key;
|
||||
_retu->decrypt_key = decrypt_key;
|
||||
|
||||
/* Need to allocate new memory */
|
||||
_retu->encrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->encrypt_nonce);
|
||||
_retu->decrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->decrypt_nonce);
|
||||
_retu->nonce_cycle = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->nonce_cycle);
|
||||
|
||||
memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_box_NONCEBYTES);
|
||||
memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_box_NONCEBYTES);
|
||||
|
||||
_retu->csrc = calloc(sizeof(uint32_t), 1);
|
||||
assert(_retu->csrc);
|
||||
|
||||
_retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */
|
||||
|
||||
/* Also set payload type as prefix */
|
||||
_retu->prefix = payload_type;
|
||||
|
||||
_retu->oldest_msg = _retu->last_msg = NULL;
|
||||
|
||||
pthread_mutex_init(&_retu->mutex, NULL);
|
||||
/*
|
||||
*
|
||||
*/
|
||||
return _retu;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Terminate the session.
|
||||
*
|
||||
* @param session The session.
|
||||
* @param messenger The messenger who owns the session
|
||||
* @return int
|
||||
* @retval -1 Error occurred.
|
||||
* @retval 0 Success.
|
||||
*/
|
||||
int rtp_terminate_session ( RTPSession* session, Tox* messenger )
|
||||
{
|
||||
if ( !session )
|
||||
return -1;
|
||||
|
||||
networking_registerhandler(((Messenger*)messenger)->net, session->prefix, NULL, NULL);
|
||||
|
||||
free ( session->ext_header );
|
||||
free ( session->csrc );
|
||||
free ( session->decrypt_nonce );
|
||||
free ( session->encrypt_nonce );
|
||||
free ( session->nonce_cycle );
|
||||
|
||||
pthread_mutex_destroy(&session->mutex);
|
||||
|
||||
/* And finally free session */
|
||||
free ( session );
|
||||
|
||||
return 0;
|
||||
}
|
211
toxav/toxrtp.h
Executable file
211
toxav/toxrtp.h
Executable file
|
@ -0,0 +1,211 @@
|
|||
/** toxrtp.h
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
#ifndef __TOXRTP
|
||||
#define __TOXRTP
|
||||
|
||||
#define RTP_VERSION 2
|
||||
#include <inttypes.h>
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
/**
|
||||
* Standard rtp header
|
||||
*/
|
||||
|
||||
typedef struct _RTPHeader {
|
||||
uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */
|
||||
uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */
|
||||
uint16_t sequnum; /* Sequence Number */
|
||||
uint32_t timestamp; /* Timestamp */
|
||||
uint32_t ssrc; /* SSRC */
|
||||
uint32_t* csrc; /* CSRC's table */
|
||||
uint32_t length; /* Length of the header in payload string. */
|
||||
|
||||
} RTPHeader;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Standard rtp extension header.
|
||||
*
|
||||
*/
|
||||
typedef struct _RTPExtHeader {
|
||||
uint16_t type; /* Extension profile */
|
||||
uint16_t length; /* Number of extensions */
|
||||
uint32_t* table; /* Extension's table */
|
||||
|
||||
} RTPExtHeader;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Standard rtp message.
|
||||
*
|
||||
*/
|
||||
typedef struct _RTPMessage {
|
||||
RTPHeader* header;
|
||||
RTPExtHeader* ext_header;
|
||||
|
||||
uint8_t* data;
|
||||
uint32_t length;
|
||||
tox_IP_Port from;
|
||||
|
||||
struct _RTPMessage* next;
|
||||
} RTPMessage;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Our main session descriptor.
|
||||
* It measures the session variables and controls
|
||||
* the entire session. There are functions for manipulating
|
||||
* the session so tend to use those instead of directly modifying
|
||||
* session parameters.
|
||||
*
|
||||
*/
|
||||
typedef struct _RTPSession {
|
||||
uint8_t version;
|
||||
uint8_t padding;
|
||||
uint8_t extension;
|
||||
uint8_t cc;
|
||||
uint8_t marker;
|
||||
uint8_t payload_type;
|
||||
uint16_t sequnum; /* Set when sending */
|
||||
uint16_t rsequnum; /* Check when recving msg */
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t* csrc;
|
||||
|
||||
/* If some additional data must be sent via message
|
||||
* apply it here. Only by allocating this member you will be
|
||||
* automatically placing it within a message.
|
||||
*/
|
||||
RTPExtHeader* ext_header;
|
||||
|
||||
/* External header identifiers */
|
||||
int resolution;
|
||||
int framerate;
|
||||
|
||||
|
||||
/* Since these are only references of the
|
||||
* call structure don't allocate or free
|
||||
*/
|
||||
|
||||
const uint8_t* encrypt_key;
|
||||
const uint8_t* decrypt_key;
|
||||
uint8_t* encrypt_nonce;
|
||||
uint8_t* decrypt_nonce;
|
||||
|
||||
uint8_t* nonce_cycle;
|
||||
|
||||
RTPMessage* oldest_msg;
|
||||
RTPMessage* last_msg; /* tail */
|
||||
|
||||
/* Msg prefix for core to know when recving */
|
||||
uint8_t prefix;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
tox_IP_Port dest;
|
||||
|
||||
} RTPSession;
|
||||
|
||||
|
||||
/**
|
||||
* @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 );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get's oldest message in the list.
|
||||
*
|
||||
* @param session Where the list is.
|
||||
* @return RTPMessage* The message. You need to call rtp_msg_free() to free it.
|
||||
* @retval NULL No messages in the list, or no list.
|
||||
*/
|
||||
RTPMessage* rtp_recv_msg ( RTPSession* session );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends msg to _RTPSession::dest
|
||||
*
|
||||
* @param session The session.
|
||||
* @param msg The message
|
||||
* @param messenger Tox* object.
|
||||
* @return int
|
||||
* @retval -1 On error.
|
||||
* @retval 0 On success.
|
||||
*/
|
||||
int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Speaks for it self.
|
||||
*
|
||||
* @param session The control session msg belongs to. It can be NULL.
|
||||
* @param msg The message.
|
||||
* @return void
|
||||
*/
|
||||
void rtp_free_msg ( RTPSession* session, RTPMessage* msg );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Must be called before calling any other rtp function. It's used
|
||||
* to initialize RTP control session.
|
||||
*
|
||||
* @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType
|
||||
* @param messenger Tox* object.
|
||||
* @param friend_num Friend id.
|
||||
* @param encrypt_key Speaks for it self.
|
||||
* @param decrypt_key Speaks for it self.
|
||||
* @param encrypt_nonce Speaks for it self.
|
||||
* @param decrypt_nonce Speaks for it self.
|
||||
* @return RTPSession* Created control session.
|
||||
* @retval NULL Error occurred.
|
||||
*/
|
||||
RTPSession* rtp_init_session ( int payload_type,
|
||||
Tox* messenger,
|
||||
int friend_num,
|
||||
const uint8_t* encrypt_key,
|
||||
const uint8_t* decrypt_key,
|
||||
const uint8_t* encrypt_nonce,
|
||||
const uint8_t* decrypt_nonce );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Terminate the session.
|
||||
*
|
||||
* @param session The session.
|
||||
* @param messenger The messenger who owns the session
|
||||
* @return int
|
||||
* @retval -1 Error occurred.
|
||||
* @retval 0 Success.
|
||||
*/
|
||||
int rtp_terminate_session ( RTPSession* session, Tox* messenger );
|
||||
|
||||
|
||||
|
||||
#endif /* __TOXRTP */
|
|
@ -29,6 +29,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
|
|||
../toxcore/group_chats.c \
|
||||
../toxcore/assoc.h \
|
||||
../toxcore/assoc.c \
|
||||
../toxcore/event.h \
|
||||
../toxcore/event.c \
|
||||
../toxcore/onion.h \
|
||||
../toxcore/onion.c \
|
||||
../toxcore/onion_announce.h \
|
||||
|
|
335
toxcore/event.c
Executable file
335
toxcore/event.c
Executable file
|
@ -0,0 +1,335 @@
|
|||
/** event.c
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "event.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define RUN_IN_THREAD(func, args) { pthread_t _tid; \
|
||||
pthread_create(&_tid, NULL, func, args); assert( pthread_detach(_tid) == 0 ); }
|
||||
|
||||
#define LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex)
|
||||
#define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex)
|
||||
|
||||
#define FREQUENCY 10000
|
||||
|
||||
#define inline__ inline __attribute__((always_inline))
|
||||
|
||||
|
||||
typedef struct _EventContainer {
|
||||
void* (*func)(void*);
|
||||
void* func_args;
|
||||
unsigned timeout;
|
||||
long long id;
|
||||
|
||||
} EventContainer;
|
||||
|
||||
typedef struct _EventHandler {
|
||||
EventContainer* timed_events;
|
||||
size_t timed_events_count;
|
||||
|
||||
int running;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
} EventHandler;
|
||||
|
||||
int throw_event( void* (func)(void*), void* arg );
|
||||
int reset_timer_event ( int id, uint32_t timeout );
|
||||
int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout);
|
||||
int cancel_timer_event ( int id );
|
||||
int execute_timer_event ( int id );
|
||||
|
||||
struct _Event event =
|
||||
{
|
||||
throw_event,
|
||||
/* reset_timer_event */ NULL,
|
||||
throw_timer_event,
|
||||
cancel_timer_event,
|
||||
/*execute_timer_event*/ NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Random functions used by this file
|
||||
*/
|
||||
void clear_events (EventContainer** event_container, size_t* counter)
|
||||
{
|
||||
free(*event_container );
|
||||
|
||||
*event_container = NULL;
|
||||
*counter = 0;
|
||||
}
|
||||
|
||||
int pop_id ( EventContainer** event_container, size_t* counter, int id )
|
||||
{
|
||||
if ( !*event_container || !*counter || !id )
|
||||
return -1;
|
||||
|
||||
EventContainer* _it = *event_container;
|
||||
int i;
|
||||
|
||||
for ( i = *counter; i; -- i ){
|
||||
if ( _it->id == id ) { /* Hit! */
|
||||
break;
|
||||
}
|
||||
++_it;
|
||||
}
|
||||
|
||||
if ( i ) {
|
||||
for ( ; i; -- i ){ *_it = *(_it + 1); ++_it; }
|
||||
-- (*counter );
|
||||
*event_container = realloc(*event_container, sizeof(EventContainer) * (*counter )); /* resize */
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* not found here */
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void push_event ( EventContainer** container, size_t* counter, void* (func)(void*), void* arg )
|
||||
{
|
||||
(*container ) = realloc((*container ), sizeof(EventContainer) * ((*counter ) + 1));
|
||||
assert((*container ) != NULL);
|
||||
|
||||
(*container )[*counter].func = func;
|
||||
(*container )[*counter].func_args = arg;
|
||||
(*container )[*counter].timeout = 0;
|
||||
(*container )[*counter].id = 0;
|
||||
|
||||
(*counter )++;
|
||||
}
|
||||
|
||||
void reorder_events ( size_t counter, EventContainer* container, unsigned timeout )
|
||||
{
|
||||
if ( counter > 1 ) {
|
||||
|
||||
int i = counter - 1;
|
||||
|
||||
/* start from behind excluding last added member */
|
||||
EventContainer* _it = &container[i - 1];
|
||||
|
||||
EventContainer _last_added = container[i];
|
||||
|
||||
for ( ; i; --i ) {
|
||||
if ( _it->timeout > timeout ){
|
||||
*(_it + 1) = *_it;
|
||||
*_it = _last_added; -- _it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================= */
|
||||
|
||||
/* main poll for event execution */
|
||||
void* event_poll( void* arg )
|
||||
{
|
||||
EventHandler* _event_handler = arg;
|
||||
|
||||
while ( _event_handler->running )
|
||||
{
|
||||
|
||||
LOCK( _event_handler );
|
||||
|
||||
if ( _event_handler->timed_events ){
|
||||
|
||||
uint32_t _time = ((uint32_t)(current_time() / 1000));
|
||||
|
||||
if ( _event_handler->timed_events[0].timeout < _time ) {
|
||||
|
||||
RUN_IN_THREAD ( _event_handler->timed_events[0].func,
|
||||
_event_handler->timed_events[0].func_args );
|
||||
|
||||
pop_id(&_event_handler->timed_events,
|
||||
&_event_handler->timed_events_count,
|
||||
_event_handler->timed_events[0].id);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UNLOCK( _event_handler );
|
||||
|
||||
usleep(FREQUENCY);
|
||||
}
|
||||
|
||||
LOCK( _event_handler );
|
||||
|
||||
clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count);
|
||||
|
||||
UNLOCK( _event_handler );
|
||||
|
||||
_event_handler->running = -1;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int throw_event( void* (func)(void*), void* arg )
|
||||
{
|
||||
pthread_t _tid;
|
||||
int _rc =
|
||||
pthread_create(&_tid, NULL, func, arg );
|
||||
|
||||
return (0 != _rc ) ? _rc : pthread_detach(_tid);
|
||||
}
|
||||
|
||||
EventHandler event_handler;
|
||||
|
||||
/* Place and order array of timers */
|
||||
int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout)
|
||||
{
|
||||
static int _unique_id = 1;
|
||||
|
||||
push_event(&event_handler.timed_events, &(event_handler.timed_events_count), func, arg );
|
||||
|
||||
size_t _counter = event_handler.timed_events_count;
|
||||
|
||||
event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)(current_time() / 1000));
|
||||
event_handler.timed_events[_counter - 1].id = _unique_id; ++_unique_id;
|
||||
|
||||
|
||||
/* reorder */
|
||||
|
||||
reorder_events(_counter, event_handler.timed_events, timeout );
|
||||
|
||||
return _unique_id - 1;
|
||||
}
|
||||
|
||||
int execute_timer_event ( int id )
|
||||
{
|
||||
int _status;
|
||||
|
||||
LOCK((&event_handler));
|
||||
EventContainer* _it = event_handler.timed_events;
|
||||
|
||||
int _i = event_handler.timed_events_count;
|
||||
|
||||
/* Find it and execute */
|
||||
for ( ; _i; _i-- ) {
|
||||
if ( _it->id == id ) {
|
||||
RUN_IN_THREAD ( _it->func, _it->func_args );
|
||||
break;
|
||||
}
|
||||
++_it;
|
||||
}
|
||||
|
||||
/* Now remove it from the queue */
|
||||
|
||||
if ( _i ) {
|
||||
for ( ; _i; -- _i ){ *_it = *(_it + 1); ++_it; }
|
||||
-- event_handler.timed_events_count;
|
||||
|
||||
event_handler.timed_events = realloc
|
||||
(event_handler.timed_events, sizeof(EventContainer) * event_handler.timed_events_count); /* resize */
|
||||
|
||||
_status = 0;
|
||||
|
||||
}
|
||||
else _status = -1;
|
||||
|
||||
UNLOCK((&event_handler));
|
||||
|
||||
return _status;
|
||||
}
|
||||
|
||||
int reset_timer_event ( int id, uint32_t timeout )
|
||||
{
|
||||
int _status;
|
||||
|
||||
LOCK((&event_handler));
|
||||
|
||||
EventContainer* _it = event_handler.timed_events;
|
||||
|
||||
int _i = event_handler.timed_events_count;
|
||||
|
||||
/* Find it and change */
|
||||
for ( ; _i; _i-- ) {
|
||||
if ( _it->id == id ) {
|
||||
_it->timeout = timeout + ((uint32_t)(current_time() / 1000));
|
||||
break;
|
||||
}
|
||||
++_it;
|
||||
}
|
||||
|
||||
_status = _i ? -1 : 0;
|
||||
|
||||
UNLOCK((&event_handler));
|
||||
|
||||
return _status;
|
||||
}
|
||||
|
||||
/* Remove timer from array */
|
||||
inline__ int cancel_timer_event ( int id )
|
||||
{
|
||||
return pop_id (&event_handler.timed_events, &event_handler.timed_events_count, id );
|
||||
}
|
||||
|
||||
|
||||
/* Initialization and termination of event polls
|
||||
* This will be run at the beginning and the end of the program execution.
|
||||
* I think that's the best way to do it.
|
||||
*/
|
||||
|
||||
void __attribute__((constructor)) init_event_poll ()
|
||||
{
|
||||
event_handler.timed_events = NULL;
|
||||
event_handler.timed_events_count = 0;
|
||||
|
||||
event_handler.running = 1;
|
||||
|
||||
pthread_mutex_init(&event_handler.mutex, NULL);
|
||||
|
||||
RUN_IN_THREAD(event_poll, &event_handler);
|
||||
}
|
||||
|
||||
void __attribute__((destructor)) terminate_event_poll()
|
||||
{
|
||||
/* Exit thread */
|
||||
event_handler.running = 0;
|
||||
|
||||
/* Keep the global until thread exits */
|
||||
while (event_handler.running > -1) {
|
||||
event_handler.running;
|
||||
usleep(FREQUENCY*2);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy( &event_handler.mutex );
|
||||
}
|
51
toxcore/event.h
Executable file
51
toxcore/event.h
Executable file
|
@ -0,0 +1,51 @@
|
|||
/** event.h
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __TOXEVENT
|
||||
#define __TOXEVENT
|
||||
|
||||
|
||||
/**
|
||||
* - Events are, in fact, ran in their own threads upon execution.
|
||||
* - Event handler is initialized at the start, before the main() function
|
||||
* and terminated after it's execution.
|
||||
* - Timers are checked for timeout every ~10000 ns.
|
||||
* - Timers can be canceled or ran immediately via
|
||||
* timer_release() or timer_now() functions.
|
||||
* - Timeout is measured in milliseconds.
|
||||
*
|
||||
* NOTE: timer_reset () and timer_now() are not tested nor usable atm
|
||||
*
|
||||
*/
|
||||
extern struct _Event
|
||||
{
|
||||
int (*rise) (void* ( func ) ( void* ), void* arg);
|
||||
int (*timer_reset ) ( int id, unsigned timeout );
|
||||
int (*timer_alloc) (void* ( func ) ( void* ), void* arg, unsigned timeout);
|
||||
int (*timer_release) (int id);
|
||||
int (*timer_now) ( int id );
|
||||
} event;
|
||||
|
||||
#endif /* _MSI__EVENT_H_ */
|
|
@ -1,69 +0,0 @@
|
|||
if BUILD_AV
|
||||
|
||||
lib_LTLIBRARIES += libtoxmsi.la
|
||||
|
||||
libtoxmsi_la_include_HEADERS = \
|
||||
../toxmsi/toxmsi.h \
|
||||
../toxmsi/toxmedia.h
|
||||
|
||||
libtoxmsi_la_includedir = $(includedir)/tox
|
||||
|
||||
|
||||
libtoxmsi_la_SOURCES = ../toxmsi/toxmsi.h \
|
||||
../toxmsi/toxmsi.c \
|
||||
../toxmsi/toxmsi_message.h \
|
||||
../toxmsi/toxmsi_message.c \
|
||||
../toxmsi/toxmsi_header.h \
|
||||
../toxmsi/toxmsi_header.c \
|
||||
../toxmsi/toxmsi_event.h \
|
||||
../toxmsi/toxmsi_event.c \
|
||||
../toxrtp/tests/test_helper.h \
|
||||
../toxrtp/tests/test_helper.c
|
||||
|
||||
libtoxmsi_la_CFLAGS = -I../toxcore \
|
||||
-I../toxmsi \
|
||||
-I../toxrtp \
|
||||
$(NACL_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS)
|
||||
|
||||
libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \
|
||||
$(EXTRA_LT_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(PTHREAD_LIBS)
|
||||
|
||||
libtoxmsi_la_LIBS = $(NACL_LIBS)
|
||||
|
||||
noinst_PROGRAMS += phone
|
||||
|
||||
phone_SOURCES = ../toxmsi/phone.c \
|
||||
../toxmsi/toxmedia.c
|
||||
|
||||
phone_CFLAGS = -I../toxcore \
|
||||
-I../toxrtp \
|
||||
$(AVFORMAT_CFLAGS) \
|
||||
$(AVCODEC_CFLAGS) \
|
||||
$(AVUTIL_CFLAGS) \
|
||||
$(AVDEVICE_CFLAGS) \
|
||||
$(SWSCALE_CFLAGS) \
|
||||
$(SDL_CFLAGS) \
|
||||
$(OPENAL_CFLAGS) \
|
||||
$(NACL_CFLAGS) \
|
||||
$(OPUS_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS)
|
||||
|
||||
|
||||
phone_LDADD = $(PTHREAD_LIBS) \
|
||||
libtoxrtp.la \
|
||||
libtoxmsi.la \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(AVFORMAT_LIBS) \
|
||||
$(AVCODEC_LIBS) \
|
||||
$(AVUTIL_LIBS) \
|
||||
$(AVDEVICE_LIBS) \
|
||||
$(SWSCALE_LIBS) \
|
||||
$(SDL_LIBS) \
|
||||
$(OPENAL_LIBS) \
|
||||
$(NACL_LIBS) \
|
||||
$(OPUS_LIBS)
|
||||
|
||||
endif
|
668
toxmsi/phone.c
668
toxmsi/phone.c
|
@ -1,668 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#define _BSD_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#define _CT_PHONE
|
||||
|
||||
#ifdef _CT_PHONE
|
||||
#include "phone.h"
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
/* #include <termios.h> Can this be removed? */
|
||||
#include <pthread.h>
|
||||
#include "toxmedia.h"
|
||||
|
||||
|
||||
|
||||
void INFO (const char *_format, ...)
|
||||
{
|
||||
printf("\r[!] ");
|
||||
va_list _arg;
|
||||
va_start (_arg, _format);
|
||||
vfprintf (stdout, _format, _arg);
|
||||
va_end (_arg);
|
||||
printf("\n\r >> ");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int rtp_handlepacket ( void *_object, tox_IP_Port ip_port, uint8_t *data, uint32_t length )
|
||||
{
|
||||
phone_t *_phone = _object;
|
||||
rtp_msg_t *_msg;
|
||||
uint8_t _payload_id;
|
||||
|
||||
if ( _phone->_msi->_call && _phone->_msi->_call->_state == call_active ) {
|
||||
|
||||
_msg = rtp_msg_parse ( NULL, data + 1, length - 1 ); /* ignore marker byte */
|
||||
|
||||
if ( !_msg )
|
||||
return 0;
|
||||
|
||||
_payload_id = rtp_header_get_setting_payload_type(_msg->_header);
|
||||
|
||||
if ( _payload_id == _PAYLOAD_OPUS && _phone->_rtp_audio )
|
||||
rtp_store_msg(_phone->_rtp_audio, _msg);
|
||||
else if ( _payload_id == _PAYLOAD_VP8 && _phone->_rtp_video )
|
||||
rtp_store_msg(_phone->_rtp_video, _msg);
|
||||
else rtp_free_msg( NULL, _msg);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
int msi_handlepacket ( void *_object, tox_IP_Port ip_port, uint8_t *data, uint32_t length )
|
||||
{
|
||||
msi_session_t *_session = _object;
|
||||
msi_msg_t *_msg;
|
||||
|
||||
_msg = msi_parse_msg ( data + 1 ); /* ignore marker byte */
|
||||
|
||||
if ( _msg ) {
|
||||
/* my current solution for "hole punching" */
|
||||
_session->_friend_id = ip_port;
|
||||
} else {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/* place message in a session */
|
||||
msi_store_msg(_session, _msg);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void *phone_receivepacket ( void *_phone_p )
|
||||
{
|
||||
phone_t *_phone = _phone_p;
|
||||
|
||||
|
||||
networking_registerhandler(_phone->_networking, MSI_PACKET, msi_handlepacket, _phone->_msi);
|
||||
networking_registerhandler(_phone->_networking, RTP_PACKET, rtp_handlepacket, _phone);
|
||||
|
||||
/* Now start main networking loop */
|
||||
while ( _phone->_networking ) { /* so not thread safe */
|
||||
networking_poll(_phone->_networking);
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
/* Media transport callback */
|
||||
typedef struct hmtc_args_s {
|
||||
rtp_session_t **_rtp_audio;
|
||||
rtp_session_t **_rtp_video;
|
||||
call_type *_local_type_call;
|
||||
call_state *_this_call;
|
||||
void *_core_handler;
|
||||
} hmtc_args_t;
|
||||
|
||||
void *phone_handle_media_transport_poll ( void *_hmtc_args_p )
|
||||
{
|
||||
rtp_msg_t *_audio_msg, * _video_msg;
|
||||
|
||||
hmtc_args_t *_hmtc_args = _hmtc_args_p;
|
||||
|
||||
rtp_session_t *_rtp_audio = *_hmtc_args->_rtp_audio;
|
||||
rtp_session_t *_rtp_video = *_hmtc_args->_rtp_video;
|
||||
|
||||
call_type *_type = _hmtc_args->_local_type_call;
|
||||
void *_core_handler = _hmtc_args->_core_handler;
|
||||
|
||||
|
||||
call_state *_this_call = _hmtc_args->_this_call;
|
||||
|
||||
while ( *_this_call == call_active ) {
|
||||
|
||||
// THREADLOCK()
|
||||
|
||||
_audio_msg = rtp_recv_msg ( _rtp_audio );
|
||||
_video_msg = rtp_recv_msg ( _rtp_video );
|
||||
|
||||
if ( _audio_msg ) {
|
||||
/* Do whatever with msg */
|
||||
puts("audio");
|
||||
/* Do whatever with msg
|
||||
puts(_audio_msg->_data);*/
|
||||
rtp_free_msg ( _rtp_audio, _audio_msg );
|
||||
}
|
||||
|
||||
if ( _video_msg ) {
|
||||
/* Do whatever with msg */
|
||||
puts("video");
|
||||
/* Do whatever with msg
|
||||
puts(_video_msg->_data); */
|
||||
rtp_free_msg ( _rtp_video, _video_msg );
|
||||
_video_msg = NULL;
|
||||
}
|
||||
|
||||
/* -------------------- */
|
||||
|
||||
_audio_msg = rtp_msg_new ( _rtp_audio, (const uint8_t *)"audio\0", 6 ) ;
|
||||
rtp_send_msg ( _rtp_audio, _audio_msg, _core_handler );
|
||||
_audio_msg = NULL;
|
||||
|
||||
if ( *_type == type_video ) { /* if local call send video */
|
||||
_video_msg = rtp_msg_new ( _rtp_video, (const uint8_t *)"video\0", 6 ) ;
|
||||
rtp_send_msg ( _rtp_video, _video_msg, _core_handler );
|
||||
_video_msg = NULL;
|
||||
}
|
||||
|
||||
//THREADUNLOCK()
|
||||
|
||||
usleep ( 10000 );
|
||||
/* -------------------- */
|
||||
}
|
||||
|
||||
//THREADLOCK()
|
||||
|
||||
if ( _audio_msg ) {
|
||||
rtp_free_msg(_rtp_audio, _audio_msg);
|
||||
}
|
||||
|
||||
if ( _video_msg ) {
|
||||
rtp_free_msg(_rtp_video, _video_msg);
|
||||
}
|
||||
|
||||
rtp_release_session_recv(_rtp_video);
|
||||
rtp_release_session_recv(_rtp_audio);
|
||||
|
||||
rtp_terminate_session(_rtp_audio);
|
||||
rtp_terminate_session(_rtp_video);
|
||||
|
||||
*_hmtc_args->_rtp_audio = NULL;
|
||||
*_hmtc_args->_rtp_video = NULL;
|
||||
|
||||
free(_hmtc_args_p);
|
||||
|
||||
//THREADUNLOCK()
|
||||
|
||||
INFO("Media thread finished!");
|
||||
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
pthread_t phone_startmedia_loop ( phone_t *_phone )
|
||||
{
|
||||
if ( !_phone ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _status;
|
||||
|
||||
uint8_t _prefix = RTP_PACKET;
|
||||
|
||||
pthread_t _rtp_tid;
|
||||
int _rtp_thread_running = 1;
|
||||
|
||||
_phone->_rtp_audio = rtp_init_session ( -1, 1 );
|
||||
rtp_set_prefix ( _phone->_rtp_audio, &_prefix, 1 );
|
||||
rtp_add_receiver ( _phone->_rtp_audio, &_phone->_msi->_friend_id );
|
||||
rtp_set_payload_type(_phone->_rtp_audio, _PAYLOAD_OPUS);
|
||||
|
||||
_phone->_rtp_video = rtp_init_session ( -1, 1 );
|
||||
rtp_set_prefix ( _phone->_rtp_video, &_prefix, 1 );
|
||||
rtp_add_receiver ( _phone->_rtp_video, &_phone->_msi->_friend_id );
|
||||
rtp_set_payload_type(_phone->_rtp_video, _PAYLOAD_VP8);
|
||||
|
||||
|
||||
|
||||
hmtc_args_t *rtp_targs = calloc(sizeof(hmtc_args_t), 1);
|
||||
|
||||
|
||||
rtp_targs->_rtp_audio = &_phone->_rtp_audio;
|
||||
rtp_targs->_rtp_video = &_phone->_rtp_video;
|
||||
rtp_targs->_local_type_call = &_phone->_msi->_call->_type_local;
|
||||
rtp_targs->_this_call = &_phone->_msi->_call->_state;
|
||||
rtp_targs->_core_handler = _phone->_networking;
|
||||
|
||||
codec_state *cs;
|
||||
cs = _phone->cs;
|
||||
//_status = pthread_create ( &_rtp_tid, NULL, phone_handle_media_transport_poll, rtp_targs );
|
||||
cs->_rtp_audio = _phone->_rtp_audio;
|
||||
cs->_rtp_video = _phone->_rtp_video;
|
||||
cs->_networking = _phone->_networking;
|
||||
cs->socket = _phone->_tox_sock;
|
||||
cs->quit = 0;
|
||||
|
||||
printf("support: %d %d\n", cs->support_send_audio, cs->support_send_video);
|
||||
|
||||
if (cs->support_send_audio && cs->support_send_video) /* quick fix */
|
||||
pthread_create(&_phone->cs->encode_audio_thread, NULL, encode_audio_thread, _phone->cs);
|
||||
|
||||
if (cs->support_receive_audio)
|
||||
pthread_create(&_phone->cs->decode_audio_thread, NULL, decode_audio_thread, _phone->cs);
|
||||
|
||||
if (cs->support_send_video)
|
||||
pthread_create(&_phone->cs->encode_video_thread, NULL, encode_video_thread, _phone->cs);
|
||||
|
||||
if (cs->support_receive_video)
|
||||
pthread_create(&_phone->cs->decode_video_thread, NULL, decode_video_thread, _phone->cs);
|
||||
|
||||
//
|
||||
return 1;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Some example callbacks */
|
||||
|
||||
MCBTYPE callback_recv_invite ( MCBARGS )
|
||||
{
|
||||
const char *_call_type;
|
||||
|
||||
msi_session_t *_msi = _arg;
|
||||
|
||||
/* Get the last one */
|
||||
call_type _type = _msi->_call->_type_peer[_msi->_call->_participants - 1];
|
||||
|
||||
switch ( _type ) {
|
||||
case type_audio:
|
||||
_call_type = "audio";
|
||||
break;
|
||||
|
||||
case type_video:
|
||||
_call_type = "video";
|
||||
break;
|
||||
}
|
||||
|
||||
INFO( "Incoming %s call!", _call_type );
|
||||
|
||||
}
|
||||
MCBTYPE callback_recv_trying ( MCBARGS )
|
||||
{
|
||||
INFO ( "Trying...");
|
||||
}
|
||||
MCBTYPE callback_recv_ringing ( MCBARGS )
|
||||
{
|
||||
INFO ( "Ringing!" );
|
||||
}
|
||||
MCBTYPE callback_recv_starting ( MCBARGS )
|
||||
{
|
||||
msi_session_t *_session = _arg;
|
||||
|
||||
if ( !phone_startmedia_loop(_session->_agent_handler) ) {
|
||||
INFO("Starting call failed!");
|
||||
} else {
|
||||
INFO ("Call started! ( press h to hangup )");
|
||||
}
|
||||
}
|
||||
MCBTYPE callback_recv_ending ( MCBARGS )
|
||||
{
|
||||
msi_session_t *_session = _arg;
|
||||
phone_t *_phone = _session->_agent_handler;
|
||||
_phone->cs->quit = 1;
|
||||
|
||||
if (_phone->cs->encode_video_thread)
|
||||
pthread_join(_phone->cs->encode_video_thread, NULL);
|
||||
|
||||
if (_phone->cs->encode_audio_thread)
|
||||
pthread_join(_phone->cs->encode_audio_thread, NULL);
|
||||
|
||||
if (_phone->cs->decode_audio_thread)
|
||||
pthread_join(_phone->cs->decode_audio_thread, NULL);
|
||||
|
||||
if (_phone->cs->decode_video_thread)
|
||||
pthread_join(_phone->cs->decode_video_thread, NULL);
|
||||
|
||||
SDL_Quit();
|
||||
printf("all A/V threads successfully shut down\n");
|
||||
|
||||
INFO ( "Call ended!" );
|
||||
}
|
||||
|
||||
MCBTYPE callback_recv_error ( MCBARGS )
|
||||
{
|
||||
msi_session_t *_session = _arg;
|
||||
|
||||
INFO( "Error: %s", _session->_last_error_str );
|
||||
}
|
||||
|
||||
MCBTYPE callback_call_started ( MCBARGS )
|
||||
{
|
||||
msi_session_t *_session = _arg;
|
||||
|
||||
if ( !phone_startmedia_loop(_session->_agent_handler) ) {
|
||||
INFO("Starting call failed!");
|
||||
} else {
|
||||
INFO ("Call started! ( press h to hangup )");
|
||||
}
|
||||
|
||||
}
|
||||
MCBTYPE callback_call_canceled ( MCBARGS )
|
||||
{
|
||||
INFO ( "Call canceled!" );
|
||||
}
|
||||
MCBTYPE callback_call_rejected ( MCBARGS )
|
||||
{
|
||||
INFO ( "Call rejected!\n" );
|
||||
}
|
||||
MCBTYPE callback_call_ended ( MCBARGS )
|
||||
{
|
||||
|
||||
msi_session_t *_session = _arg;
|
||||
phone_t *_phone = _session->_agent_handler;
|
||||
_phone->cs->quit = 1;
|
||||
|
||||
if (_phone->cs->encode_video_thread)
|
||||
pthread_join(_phone->cs->encode_video_thread, NULL);
|
||||
|
||||
if (_phone->cs->encode_audio_thread)
|
||||
pthread_join(_phone->cs->encode_audio_thread, NULL);
|
||||
|
||||
if (_phone->cs->decode_audio_thread)
|
||||
pthread_join(_phone->cs->decode_audio_thread, NULL);
|
||||
|
||||
if (_phone->cs->decode_video_thread)
|
||||
pthread_join(_phone->cs->decode_video_thread, NULL);
|
||||
|
||||
SDL_Quit();
|
||||
printf("all A/V threads successfully shut down\n");
|
||||
|
||||
INFO ( "Call ended!" );
|
||||
}
|
||||
|
||||
MCBTYPE callback_requ_timeout ( MCBARGS )
|
||||
{
|
||||
INFO( "No answer! " );
|
||||
}
|
||||
|
||||
|
||||
phone_t *initPhone(uint16_t _listen_port, uint16_t _send_port)
|
||||
{
|
||||
phone_t *_retu = calloc(sizeof(phone_t), 1);
|
||||
_retu->cs = av_calloc(sizeof(codec_state), 1);
|
||||
|
||||
/* Initialize our mutex */
|
||||
pthread_mutex_init ( &_mutex, NULL );
|
||||
|
||||
IP_Port _local;
|
||||
ip_init(&_local.ip, 0);
|
||||
_local.ip.ip4.uint32 = htonl ( INADDR_ANY );
|
||||
|
||||
/* Bind local receive port to any address */
|
||||
_retu->_networking = new_networking ( _local.ip, _listen_port );
|
||||
|
||||
if ( !_retu->_networking ) {
|
||||
fprintf ( stderr, "new_networking() failed!\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->_send_port = _send_port;
|
||||
_retu->_recv_port = _listen_port;
|
||||
|
||||
_retu->_tox_sock = _retu->_networking->sock;
|
||||
|
||||
_retu->_rtp_audio = NULL;
|
||||
_retu->_rtp_video = NULL;
|
||||
|
||||
|
||||
/* Initialize msi */
|
||||
_retu->_msi = msi_init_session ( _retu->_networking, (const uint8_t *)_USERAGENT );
|
||||
|
||||
if ( !_retu->_msi ) {
|
||||
fprintf ( stderr, "msi_init_session() failed\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initiate codecs */
|
||||
init_encoder(_retu->cs);
|
||||
init_decoder(_retu->cs);
|
||||
|
||||
_retu->_msi->_agent_handler = _retu;
|
||||
/* Initiate callbacks */
|
||||
msi_register_callback_send ( sendpacket ); /* Using core's send */
|
||||
|
||||
msi_register_callback_call_started ( callback_call_started );
|
||||
msi_register_callback_call_canceled ( callback_call_canceled );
|
||||
msi_register_callback_call_rejected ( callback_call_rejected );
|
||||
msi_register_callback_call_ended ( callback_call_ended );
|
||||
|
||||
msi_register_callback_recv_invite ( callback_recv_invite );
|
||||
msi_register_callback_recv_ringing ( callback_recv_ringing );
|
||||
msi_register_callback_recv_starting ( callback_recv_starting );
|
||||
msi_register_callback_recv_ending ( callback_recv_ending );
|
||||
msi_register_callback_recv_error(callback_recv_error);
|
||||
|
||||
msi_register_callback_requ_timeout ( callback_requ_timeout );
|
||||
/* ------------------ */
|
||||
|
||||
/* Now start msi main loop. It's a must!
|
||||
* Define a frequency in ms; 10 ms is just fine
|
||||
*/
|
||||
msi_start_main_loop ( _retu->_msi, 10 );
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
pthread_t phone_startmain_loop(phone_t *_phone)
|
||||
{
|
||||
int _status;
|
||||
/* Start receive thread */
|
||||
pthread_t _recv_thread, _phone_loop_thread;
|
||||
_status = pthread_create ( &_recv_thread, NULL, phone_receivepacket, _phone );
|
||||
|
||||
if ( _status < 0 ) {
|
||||
printf ( "Error while starting handle call: %d, %s\n", errno, strerror ( errno ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
_status = pthread_detach ( _recv_thread );
|
||||
|
||||
if ( _status < 0 ) {
|
||||
printf ( "Error while starting handle call: %d, %s\n", errno, strerror ( errno ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
_status = pthread_create ( &_phone_loop_thread, NULL, phone_poll, _phone );
|
||||
|
||||
if ( _status < 0 ) {
|
||||
printf ( "Error while starting main phone loop: %d, %s\n", errno, strerror ( errno ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
_status = pthread_join ( _phone_loop_thread, NULL );
|
||||
|
||||
if ( _status < 0 ) {
|
||||
printf ( "Error while starting main phone loop: %d, %s\n", errno, strerror ( errno ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _phone_loop_thread;
|
||||
}
|
||||
|
||||
void *phone_poll ( void *_p_phone )
|
||||
{
|
||||
phone_t *_phone = _p_phone;
|
||||
|
||||
int _status = SUCCESS;
|
||||
|
||||
char _line[100];
|
||||
size_t _len;
|
||||
|
||||
|
||||
char _dest[17]; /* For parsing destination ip */
|
||||
memset(_dest, '\0', 17);
|
||||
|
||||
INFO("Welcome to tox_phone version: " _USERAGENT "\n"
|
||||
"Usage: \n"
|
||||
"c [a/v] (type) [0.0.0.0] (dest ip) (calls dest ip)\n"
|
||||
"h (if call is active hang up)\n"
|
||||
"a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n"
|
||||
"r (reject incoming call)\n"
|
||||
"q (quit)\n"
|
||||
"================================================================================"
|
||||
);
|
||||
|
||||
while ( 1 ) {
|
||||
fgets(_line, sizeof(_line), stdin);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (_line[i] == '\n') {
|
||||
_line[i] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
_len = strlen(_line);
|
||||
|
||||
if ( !_len ) {
|
||||
printf(" >> ");
|
||||
fflush(stdout);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ) {
|
||||
INFO("Invalid input!");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (_line[0]) {
|
||||
|
||||
case 'c': {
|
||||
if ( _phone->_msi->_call ) {
|
||||
INFO("Already in a call");
|
||||
break;
|
||||
}
|
||||
|
||||
call_type _ctype;
|
||||
|
||||
if ( _len < 11 ) {
|
||||
INFO("Invalid input; usage: c a/v 0.0.0.0");
|
||||
break;
|
||||
} else if ( _line[2] == 'a' || _line[2] != 'v' ) { /* default and audio */
|
||||
_ctype = type_audio;
|
||||
} else { /* video */
|
||||
_ctype = type_video;
|
||||
}
|
||||
|
||||
strcpy(_dest, _line + 4 );
|
||||
_status = t_setipport(_dest, _phone->_send_port, &(_phone->_msi->_friend_id));
|
||||
|
||||
if ( _status < 0 ) {
|
||||
INFO("Could not resolve address!");
|
||||
} else {
|
||||
/* Set timeout */
|
||||
msi_invite ( _phone->_msi, _ctype, 30 * 1000 );
|
||||
INFO("Calling!");
|
||||
}
|
||||
|
||||
t_memset((uint8_t *)_dest, '\0', 17);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h': {
|
||||
if ( !_phone->_msi->_call ) {
|
||||
break;
|
||||
}
|
||||
|
||||
msi_hangup(_phone->_msi);
|
||||
|
||||
INFO("Hung up...");
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a': {
|
||||
if ( _phone->_msi->_call && _phone->_msi->_call->_state != call_starting ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( _len > 1 && _line[2] == 'v' )
|
||||
msi_answer(_phone->_msi, type_video);
|
||||
else
|
||||
msi_answer(_phone->_msi, type_audio);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r': {
|
||||
if ( _phone->_msi->_call && _phone->_msi->_call->_state != call_starting ) {
|
||||
break;
|
||||
}
|
||||
|
||||
msi_reject(_phone->_msi);
|
||||
|
||||
INFO("Call Rejected...");
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'q': {
|
||||
INFO("Quitting!");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
default: {
|
||||
INFO("Invalid command!");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int quitPhone(phone_t *_phone)
|
||||
{
|
||||
if ( _phone->_msi->_call ) {
|
||||
msi_hangup(_phone->_msi); /* Hangup the phone first */
|
||||
}
|
||||
|
||||
msi_terminate_session(_phone->_msi);
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
|
||||
printf("\r[i] Quit!\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------- */
|
||||
|
||||
int print_help ( const char *_name )
|
||||
{
|
||||
printf ( "Usage: %s -m (mode) -r/s ( for setting the ports on test version )\n", _name );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int main ( int argc, char *argv [] )
|
||||
{
|
||||
arg_t *_args = parse_args ( argc, argv );
|
||||
|
||||
const char *_mode = find_arg_duble ( _args, "-m" );
|
||||
uint16_t _listen_port;
|
||||
uint16_t _send_port;
|
||||
|
||||
if ( !_mode )
|
||||
return print_help ( argv[0] );
|
||||
|
||||
if ( _mode[0] == 'r' ) {
|
||||
_send_port = 31000;
|
||||
_listen_port = 31001;
|
||||
} else if ( _mode[0] == 's' ) {
|
||||
_send_port = 31001;
|
||||
_listen_port = 31000;
|
||||
} else return print_help ( argv[0] );
|
||||
|
||||
phone_t *_phone = initPhone(_listen_port, _send_port);
|
||||
|
||||
if ( _phone ) {
|
||||
phone_startmain_loop(_phone);
|
||||
|
||||
quitPhone(_phone);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* _CT_PHONE */
|
|
@ -1,62 +0,0 @@
|
|||
#ifndef _PHONE_H_
|
||||
#define _PHONE_H_
|
||||
|
||||
#include "toxmsi.h"
|
||||
#include "../toxrtp/toxrtp.h"
|
||||
#include "toxmsi_message.h"
|
||||
#include "../toxrtp/toxrtp_message.h"
|
||||
#include "../toxrtp/tests/test_helper.h"
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include "toxmedia.h"
|
||||
|
||||
/* Define client version */
|
||||
#define _USERAGENT "tox_phone-v.0.2.1"
|
||||
|
||||
static pthread_mutex_t _mutex;
|
||||
|
||||
#define THREADLOCK() \
|
||||
pthread_mutex_lock ( &_mutex );
|
||||
|
||||
#define THREADUNLOCK() \
|
||||
pthread_mutex_unlock ( &_mutex );
|
||||
|
||||
typedef struct phone_s {
|
||||
msi_session_t* _msi;
|
||||
|
||||
rtp_session_t* _rtp_audio;
|
||||
rtp_session_t* _rtp_video;
|
||||
|
||||
uint32_t _frame_rate;
|
||||
|
||||
uint16_t _send_port, _recv_port;
|
||||
|
||||
int _tox_sock;
|
||||
|
||||
pthread_t _medialoop_id;
|
||||
codec_state *cs;
|
||||
|
||||
Networking_Core* _networking;
|
||||
} phone_t;
|
||||
|
||||
phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port);
|
||||
int quitPhone(phone_t* _phone);
|
||||
|
||||
/* My recv functions */
|
||||
int rtp_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length );
|
||||
int msi_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length );
|
||||
|
||||
/* This is basically representation of networking_poll of toxcore */
|
||||
void* phone_receivepacket ( void* _phone );
|
||||
|
||||
/* Phones main loop */
|
||||
void* phone_poll ( void* _phone );
|
||||
|
||||
pthread_t phone_startmain_loop(phone_t* _phone);
|
||||
pthread_t phone_startmedia_loop ( phone_t* _phone );
|
||||
|
||||
/* Thread handlers */
|
||||
void* phone_handle_receive_callback ( void* _p );
|
||||
void* phone_handle_media_transport_poll ( void* _hmtc_args_p );
|
||||
|
||||
#endif /* _PHONE_H_ */
|
835
toxmsi/toxmsi.c
835
toxmsi/toxmsi.c
|
@ -1,835 +0,0 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include "toxmsi.h"
|
||||
#include "toxmsi_event.h"
|
||||
#include "toxmsi_message.h"
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include "../toxcore/network.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define same(x, y) strcmp((const char*) x, (const char*) y) == 0
|
||||
|
||||
typedef enum {
|
||||
error_deadcall = 1, /* has call id but it's from old call */
|
||||
error_id_mismatch, /* non-existing call */
|
||||
|
||||
error_no_callid, /* not having call id */
|
||||
error_no_call, /* no call in session */
|
||||
|
||||
error_busy
|
||||
} msi_error_t; /* Error codes */
|
||||
|
||||
static inline const uint8_t *stringify_error(msi_error_t _error_code)
|
||||
{
|
||||
static const uint8_t* strings[] =
|
||||
{
|
||||
(uint8_t*)"",
|
||||
(uint8_t*)"Using dead call",
|
||||
(uint8_t*)"Call id not set to any call",
|
||||
(uint8_t*)"Call id not available",
|
||||
(uint8_t*)"No active call in session",
|
||||
(uint8_t*)"Callee busy"
|
||||
};
|
||||
|
||||
return strings[_error_code];
|
||||
}
|
||||
|
||||
static inline const uint8_t *stringify_error_code(msi_error_t _error_code)
|
||||
{
|
||||
static const uint8_t* strings[] =
|
||||
{
|
||||
(uint8_t*)"",
|
||||
(uint8_t*)"1",
|
||||
(uint8_t*)"2",
|
||||
(uint8_t*)"3",
|
||||
(uint8_t*)"4",
|
||||
(uint8_t*)"5"
|
||||
};
|
||||
|
||||
return strings[_error_code];
|
||||
}
|
||||
|
||||
/* ******************* */
|
||||
/* --------- GLOBAL FUNCTIONS USED BY THIS FILE --------- */
|
||||
|
||||
/* CALLBACKS */
|
||||
/*int (*msi_send_message_callback) ( int, uint8_t*, uint32_t ) = NULL;*/
|
||||
int ( *msi_send_message_callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) = NULL;
|
||||
int ( *msi_recv_message_callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) = NULL;
|
||||
|
||||
MCBTYPE ( *msi_recv_invite_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_start_call_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_reject_call_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_cancel_call_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_end_call_callback ) ( MCBARGS ) = NULL;
|
||||
|
||||
MCBTYPE ( *msi_ringing_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_starting_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_ending_callback ) ( MCBARGS ) = NULL;
|
||||
MCBTYPE ( *msi_error_callback ) ( MCBARGS ) = NULL;
|
||||
|
||||
MCBTYPE ( *msi_timeout_callback ) ( MCBARGS ) = NULL;
|
||||
/* End of CALLBACKS */
|
||||
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
/* REGISTER CALLBACKS */
|
||||
/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) )*/
|
||||
void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) )
|
||||
{
|
||||
msi_send_message_callback = callback;
|
||||
}
|
||||
|
||||
void msi_register_callback_recv ( int ( *callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) )
|
||||
{
|
||||
msi_recv_message_callback = callback;
|
||||
}
|
||||
|
||||
/* Function to be called when received invite.
|
||||
* This callback is all about what you do with it.
|
||||
* Everything else is done internally.
|
||||
*/
|
||||
void msi_register_callback_recv_invite ( MCALLBACK )
|
||||
{
|
||||
msi_recv_invite_callback = callback;
|
||||
}
|
||||
|
||||
/* Function to be called when the call is started
|
||||
* This callback is all about what you do with it.
|
||||
* Everything else is done internally.
|
||||
*/
|
||||
void msi_register_callback_call_started ( MCALLBACK )
|
||||
{
|
||||
msi_start_call_callback = callback;
|
||||
}
|
||||
|
||||
/* Function to be called when call is rejected
|
||||
* This callback is all about what you do with it.
|
||||
* Everything else is done internally.
|
||||
*/
|
||||
void msi_register_callback_call_rejected ( MCALLBACK )
|
||||
{
|
||||
msi_reject_call_callback = callback;
|
||||
}
|
||||
|
||||
/* Function to be called when call is canceled
|
||||
* This callback is all about what you do with it.
|
||||
* Everything else is done internally.
|
||||
*/
|
||||
void msi_register_callback_call_canceled ( MCALLBACK )
|
||||
{
|
||||
msi_cancel_call_callback = callback;
|
||||
}
|
||||
|
||||
void msi_register_callback_call_ended ( MCALLBACK )
|
||||
{
|
||||
msi_end_call_callback = callback;
|
||||
}
|
||||
|
||||
|
||||
/* Functions to be called when gotten x response */
|
||||
|
||||
void msi_register_callback_recv_ringing ( MCALLBACK )
|
||||
{
|
||||
msi_ringing_callback = callback;
|
||||
}
|
||||
void msi_register_callback_recv_starting ( MCALLBACK )
|
||||
{
|
||||
msi_starting_callback = callback;
|
||||
}
|
||||
void msi_register_callback_recv_ending ( MCALLBACK )
|
||||
{
|
||||
msi_ending_callback = callback;
|
||||
}
|
||||
|
||||
void msi_register_callback_recv_error ( MCALLBACK )
|
||||
{
|
||||
msi_error_callback = callback;
|
||||
}
|
||||
|
||||
/* Timeout */
|
||||
void msi_register_callback_requ_timeout ( MCALLBACK )
|
||||
{
|
||||
msi_timeout_callback = callback;
|
||||
}
|
||||
/* END REGISTERING */
|
||||
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
/* Function for receiving and parsing a message that will be used internally */
|
||||
|
||||
msi_msg_t* receive_message ( msi_session_t* _session )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
|
||||
msi_msg_t* _retu = _session->_oldest_msg;
|
||||
|
||||
pthread_mutex_lock ( &_session->_mutex );
|
||||
|
||||
if ( _retu )
|
||||
_session->_oldest_msg = _retu->_next;
|
||||
|
||||
if ( !_session->_oldest_msg )
|
||||
_session->_last_msg = NULL;
|
||||
|
||||
pthread_mutex_unlock ( &_session->_mutex );
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
void msi_store_msg ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
assert(_msg);
|
||||
|
||||
pthread_mutex_lock ( &_session->_mutex );
|
||||
|
||||
if ( _session->_last_msg ) {
|
||||
_session->_last_msg->_next = _msg;
|
||||
_session->_last_msg = _msg;
|
||||
} else {
|
||||
_session->_last_msg = _session->_oldest_msg = _msg;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock ( &_session->_mutex );
|
||||
}
|
||||
|
||||
int msi_send_msg ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
int _status;
|
||||
|
||||
if ( !_session->_call ) /* Which should never happen */
|
||||
return FAILURE;
|
||||
|
||||
msi_msg_set_call_id ( _msg, _session->_call->_id );
|
||||
|
||||
uint8_t _msg_string_final [MSI_MAXMSG_SIZE];
|
||||
t_memset ( _msg_string_final, '\0', MSI_MAXMSG_SIZE );
|
||||
|
||||
_msg_string_final[0] = 69;
|
||||
|
||||
uint8_t* _msg_string = msi_msg_to_string ( _msg );
|
||||
|
||||
size_t _lenght = t_memlen ( _msg_string );
|
||||
|
||||
memcpy ( _msg_string_final + 1, _msg_string, _lenght );
|
||||
|
||||
_lenght += 1;
|
||||
|
||||
_status = ( *msi_send_message_callback ) ( _session->_core_handler, _session->_friend_id, _msg_string_final, _lenght );
|
||||
|
||||
free ( _msg_string );
|
||||
|
||||
return _status;
|
||||
}
|
||||
|
||||
/* Random stuff */
|
||||
void flush_peer_type ( msi_session_t* _session, msi_msg_t* _msg, int _peer_id )
|
||||
{
|
||||
if ( _msg->_call_type ) {
|
||||
if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_AUDIO_HEADER_VALUE ) == 0 ) {
|
||||
_session->_call->_type_peer[_peer_id] = type_audio;
|
||||
|
||||
} else if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_VIDEO_HEADER_VALUE ) == 0 ) {
|
||||
_session->_call->_type_peer[_peer_id] = type_video;
|
||||
} else {} /* Error */
|
||||
} else {} /* Error */
|
||||
}
|
||||
|
||||
int has_call_error ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
|
||||
|
||||
if ( !_msg->_call_id ) {
|
||||
msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid) );
|
||||
|
||||
} else if ( !_session->_call ) {
|
||||
msi_msg_set_reason(_msg_error, stringify_error_code(error_no_call) );
|
||||
|
||||
} else if ( strcmp((const char*)_session->_call->_id, (const char*)_msg->_call_id->_header_value ) != 0 ) {
|
||||
msi_msg_set_reason(_msg_error, stringify_error_code(error_id_mismatch) );
|
||||
}
|
||||
|
||||
if ( _msg_error->_reason ) {
|
||||
msi_send_msg ( _session, _msg_error );
|
||||
msi_free_msg ( _msg_error );
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
msi_free_msg ( _msg_error );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/* --------- END OF GLOBAL FUNCTIONS USED BY THIS FILE --------- */
|
||||
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent )
|
||||
{
|
||||
assert(_core_handler);
|
||||
assert(_user_agent);
|
||||
|
||||
msi_session_t* _session = calloc ( sizeof ( msi_session_t ), 1 );
|
||||
assert(_session);
|
||||
|
||||
_session->_oldest_msg = _session->_last_msg = NULL;
|
||||
_session->_core_handler = _core_handler;
|
||||
|
||||
_session->_user_agent = t_strallcpy ( _user_agent );
|
||||
_session->_agent_handler = NULL;
|
||||
|
||||
_session->_key = 0;
|
||||
_session->_call = NULL;
|
||||
|
||||
_session->_frequ = 10000; /* default value? */
|
||||
_session->_call_timeout = 30000; /* default value? */
|
||||
|
||||
/* Use the same frequency */
|
||||
_session->_event_handler = init_event_poll ( _session->_frequ );
|
||||
|
||||
pthread_mutex_init ( &_session->_mutex, NULL );
|
||||
|
||||
return _session;
|
||||
}
|
||||
|
||||
int msi_terminate_session ( msi_session_t* _session )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
int _status = 0;
|
||||
|
||||
terminate_event_poll ( _session->_event_handler );
|
||||
free ( _session );
|
||||
/* TODO: terminate the rest of the session */
|
||||
|
||||
pthread_mutex_destroy ( &_session->_mutex );
|
||||
|
||||
return _status;
|
||||
}
|
||||
|
||||
msi_call_t* msi_init_call ( msi_session_t* _session, int _peers, uint32_t _timeoutms )
|
||||
{
|
||||
assert(_session);
|
||||
assert(_peers);
|
||||
|
||||
msi_call_t* _call = calloc ( sizeof ( msi_call_t ), 1 );
|
||||
_call->_type_peer = calloc ( sizeof ( call_type ), _peers );
|
||||
|
||||
assert(_call);
|
||||
assert(_call->_type_peer);
|
||||
|
||||
_call->_participants = _peers;
|
||||
_call->_key = _session->_key;
|
||||
_call->_timeoutst = _timeoutms;
|
||||
_call->_outgoing_timer_id = 0;
|
||||
|
||||
return _call;
|
||||
}
|
||||
|
||||
int msi_terminate_call ( msi_session_t* _session )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( _session->_call->_type_peer )
|
||||
free ( _session->_call->_type_peer );
|
||||
|
||||
cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id);
|
||||
|
||||
free ( _session->_call );
|
||||
|
||||
_session->_call = NULL;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
/* STATE HANDLERS */
|
||||
|
||||
/* REQUESTS */
|
||||
int msi_handle_recv_invite ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( _session->_call ) {
|
||||
msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
|
||||
msi_msg_set_reason(_msg_error, stringify_error_code(error_busy));
|
||||
msi_send_msg(_session, _msg_error);
|
||||
msi_free_msg(_msg_error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
if ( !_msg->_call_id ) {
|
||||
msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
|
||||
msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid));
|
||||
msi_send_msg(_session, _msg_error);
|
||||
msi_free_msg(_msg_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_session->_call = msi_init_call ( _session, 1, _session->_call_timeout );
|
||||
t_memcpy(_session->_call->_id, _msg->_call_id->_header_value, _CALL_ID_LEN);
|
||||
_session->_call->_state = call_starting;
|
||||
|
||||
flush_peer_type ( _session, _msg, 0 );
|
||||
|
||||
msi_msg_t* _msg_ringing = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ringing ) );
|
||||
msi_send_msg ( _session, _msg_ringing );
|
||||
msi_free_msg ( _msg_ringing );
|
||||
|
||||
throw_event ( _session->_event_handler, msi_recv_invite_callback, _session );
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_start ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
_session->_call->_state = call_active;
|
||||
|
||||
flush_peer_type ( _session, _msg, 0 );
|
||||
|
||||
throw_event ( _session->_event_handler, msi_start_call_callback, _session );
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_reject ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_end = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) );
|
||||
msi_send_msg ( _session, _msg_end );
|
||||
msi_free_msg ( _msg_end );
|
||||
|
||||
throw_event ( _session->_event_handler, msi_reject_call_callback, _session );
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_cancel ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) );
|
||||
msi_send_msg ( _session, _msg_ending );
|
||||
msi_free_msg ( _msg_ending );
|
||||
|
||||
msi_terminate_call ( _session );
|
||||
|
||||
throw_event ( _session->_event_handler, msi_cancel_call_callback, _session );
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_end ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) );
|
||||
msi_send_msg ( _session, _msg_ending );
|
||||
msi_free_msg ( _msg_ending );
|
||||
|
||||
msi_terminate_call ( _session );
|
||||
|
||||
throw_event ( _session->_event_handler, msi_end_call_callback, _session );
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*--------*/
|
||||
|
||||
/* RESPONSES */
|
||||
int msi_handle_recv_ringing ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
throw_event ( _session->_event_handler, msi_ringing_callback, _session );
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_starting ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
_session->_call->_state = call_active;
|
||||
|
||||
msi_msg_t* _msg_start = msi_msg_new ( TYPE_REQUEST, stringify_request ( _start ) );
|
||||
msi_send_msg ( _session, _msg_start );
|
||||
msi_free_msg ( _msg_start );
|
||||
|
||||
flush_peer_type ( _session, _msg, 0 );
|
||||
|
||||
throw_event ( _session->_event_handler, msi_starting_callback, _session );
|
||||
cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id);
|
||||
_session->_call->_outgoing_timer_id = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_ending ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( has_call_error(_session, _msg) == 0 )
|
||||
return 0;
|
||||
|
||||
msi_terminate_call ( _session );
|
||||
throw_event ( _session->_event_handler, msi_ending_callback, _session );
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_handle_recv_error ( msi_session_t* _session, msi_msg_t* _msg )
|
||||
{
|
||||
assert(_session);
|
||||
assert(_session->_call);
|
||||
|
||||
/* Handle error accordingly */
|
||||
if ( _msg->_reason ) {
|
||||
_session->_last_error_id = atoi((const char*)_msg->_reason->_header_value);
|
||||
_session->_last_error_str = stringify_error(_session->_last_error_id);
|
||||
}
|
||||
|
||||
msi_terminate_call(_session);
|
||||
|
||||
throw_event ( _session->_event_handler, msi_error_callback, _session );
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* ------------------ */
|
||||
|
||||
MCBTYPE msi_handle_timeout (void* _arg)
|
||||
{
|
||||
msi_session_t* _session = _arg;
|
||||
msi_terminate_call(_session);
|
||||
|
||||
(*msi_timeout_callback) (_arg);
|
||||
(*msi_ending_callback) (_arg);
|
||||
|
||||
}
|
||||
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( !msi_send_message_callback )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_invite = msi_msg_new ( TYPE_REQUEST, stringify_request ( _invite ) );
|
||||
|
||||
_session->_call = msi_init_call ( _session, 1, _timeoutms ); /* Just one for now */
|
||||
msi_genterate_call_id(_session->_call->_id, _CALL_ID_LEN);
|
||||
_session->_call->_type_local = _call_type;
|
||||
/* Do whatever with message */
|
||||
|
||||
if ( _call_type == type_audio ) {
|
||||
msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE );
|
||||
} else {
|
||||
msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE );
|
||||
}
|
||||
|
||||
msi_send_msg ( _session, _msg_invite );
|
||||
msi_free_msg ( _msg_invite );
|
||||
|
||||
_session->_call->_state = call_inviting;
|
||||
|
||||
_session->_call->_outgoing_timer_id = throw_timer_event(_session->_event_handler, msi_handle_timeout, _session, _timeoutms );
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_hangup ( msi_session_t* _session )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( !_session->_call || ( !msi_send_message_callback && _session->_call->_state != call_active ) )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_ending = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) );
|
||||
msi_send_msg ( _session, _msg_ending );
|
||||
msi_free_msg ( _msg_ending );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int msi_answer ( msi_session_t* _session, call_type _call_type )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( !msi_send_message_callback || !_session->_call )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_starting = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _starting ) );
|
||||
_session->_call->_type_local = _call_type;
|
||||
|
||||
if ( _call_type == type_audio ) {
|
||||
msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE );
|
||||
} else {
|
||||
msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE );
|
||||
}
|
||||
|
||||
msi_send_msg ( _session, _msg_starting );
|
||||
msi_free_msg ( _msg_starting );
|
||||
|
||||
_session->_call->_state = call_active;
|
||||
return 1;
|
||||
}
|
||||
int msi_cancel ( msi_session_t* _session )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( !_session->_call || !msi_send_message_callback )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_cancel = msi_msg_new ( TYPE_REQUEST, stringify_request ( _cancel ) );
|
||||
msi_send_msg ( _session, _msg_cancel );
|
||||
msi_free_msg ( _msg_cancel );
|
||||
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
int msi_reject ( msi_session_t* _session )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
if ( !_session->_call || !msi_send_message_callback )
|
||||
return 0;
|
||||
|
||||
msi_msg_t* _msg_reject = msi_msg_new ( TYPE_REQUEST, stringify_request ( _reject ) );
|
||||
msi_send_msg ( _session, _msg_reject );
|
||||
msi_free_msg ( _msg_reject );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
/* OUR MAIN POOL FUNCTION */
|
||||
/*
|
||||
* Forks it self to other thread and then handles the session initiation.
|
||||
*
|
||||
* BASIC call flow:
|
||||
*
|
||||
* ALICE BOB
|
||||
* | invite --> |
|
||||
* | |
|
||||
* | <-- ringing |
|
||||
* | |
|
||||
* | <-- starting |
|
||||
* | |
|
||||
* | start --> |
|
||||
* | |
|
||||
* | <-- MEDIA TRANS --> |
|
||||
* | |
|
||||
* | end --> |
|
||||
* | |
|
||||
* | <-- ending |
|
||||
*
|
||||
* Alice calls Bob by sending invite packet.
|
||||
* Bob recvs the packet and sends an ringing packet;
|
||||
* which notifies Alice that her invite is acknowledged.
|
||||
* Ringing screen shown on both sides.
|
||||
* Bob accepts the invite for a call by sending starting packet.
|
||||
* Alice recvs the starting packet and sends the started packet to
|
||||
* inform Bob that she recved the starting packet.
|
||||
* Now the media transmission is established ( i.e. RTP transmission ).
|
||||
* Alice hangs up and sends end packet.
|
||||
* Bob recves the end packet and sends ending packet
|
||||
* as the acknowledgement that the call is ending.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Needs a bit more work on the protocol
|
||||
*/
|
||||
void* msi_poll_stack ( void* _session_p )
|
||||
{
|
||||
msi_session_t* _session = ( msi_session_t* ) _session_p;
|
||||
msi_msg_t* _msg = NULL;
|
||||
|
||||
uint32_t* _frequ = &_session->_frequ;
|
||||
while ( _session ) {
|
||||
|
||||
/* At this point it's already parsed */
|
||||
_msg = receive_message ( _session );
|
||||
|
||||
if ( _msg ) {
|
||||
|
||||
if ( _msg->_request ) { /* Handle request */
|
||||
|
||||
const uint8_t* _request_value = _msg->_request->_header_value;
|
||||
|
||||
if ( same ( _request_value, stringify_request ( _invite ) ) ) {
|
||||
msi_handle_recv_invite ( _session, _msg );
|
||||
|
||||
} else if ( same ( _request_value, stringify_request ( _start ) ) ) {
|
||||
msi_handle_recv_start ( _session, _msg );
|
||||
|
||||
} else if ( same ( _request_value, stringify_request ( _cancel ) ) ) {
|
||||
msi_handle_recv_cancel ( _session, _msg );
|
||||
|
||||
} else if ( same ( _request_value, stringify_request ( _reject ) ) ) {
|
||||
msi_handle_recv_reject ( _session, _msg );
|
||||
|
||||
} else if ( same ( _request_value, stringify_request ( _end ) ) ) {
|
||||
msi_handle_recv_end ( _session, _msg );
|
||||
}
|
||||
|
||||
} else if ( _msg->_response ) { /* Handle response */
|
||||
|
||||
const uint8_t* _response_value = _msg->_response->_header_value;
|
||||
|
||||
if ( same ( _response_value, stringify_response ( _ringing ) ) ) {
|
||||
msi_handle_recv_ringing ( _session, _msg );
|
||||
|
||||
} else if ( same ( _response_value, stringify_response ( _starting ) ) ) {
|
||||
msi_handle_recv_starting ( _session, _msg );
|
||||
|
||||
} else if ( same ( _response_value, stringify_response ( _ending ) ) ) {
|
||||
msi_handle_recv_ending ( _session, _msg );
|
||||
|
||||
} else if ( same ( _response_value, stringify_response ( _error ) ) ) {
|
||||
msi_handle_recv_error ( _session, _msg );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
msi_free_msg ( _msg );
|
||||
|
||||
}
|
||||
usleep ( *_frequ );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
/*------------------------*/
|
||||
|
||||
/* Easy way to start the poll */
|
||||
|
||||
pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms )
|
||||
{
|
||||
assert(_session);
|
||||
|
||||
int _status;
|
||||
pthread_t _thread_id;
|
||||
|
||||
|
||||
_session->_frequ = _frequms * 1000;
|
||||
|
||||
_status = pthread_create ( &_thread_id, NULL, msi_poll_stack, _session );
|
||||
|
||||
if ( _status < 0 ) {
|
||||
printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) );
|
||||
return _status;
|
||||
}
|
||||
|
||||
_status = pthread_detach ( _thread_id );
|
||||
|
||||
if ( _status < 0 ) {
|
||||
printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) );
|
||||
}
|
||||
|
||||
return _thread_id;
|
||||
}
|
145
toxmsi/toxmsi.h
145
toxmsi/toxmsi.h
|
@ -1,145 +0,0 @@
|
|||
/* msi_initiation.h
|
||||
*
|
||||
* Has function for session initiation along with session description.
|
||||
* It follows the Tox API ( http://wiki.tox.im/index.php/Messaging_Protocol ). !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _MSI_IMPL_H_
|
||||
#define _MSI_IMPL_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "tox.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#define MCBTYPE void
|
||||
#define MCBARGS void* _arg
|
||||
#define MCALLBACK MCBTYPE(*callback)(void* _arg)
|
||||
|
||||
#define MSI_PACKET 69
|
||||
|
||||
#define CT_AUDIO_HEADER_VALUE "AUDIO"
|
||||
#define CT_VIDEO_HEADER_VALUE "VIDEO"
|
||||
|
||||
/* define size for call_id */
|
||||
#define _CALL_ID_LEN 12
|
||||
|
||||
typedef enum {
|
||||
type_audio = 1,
|
||||
type_video,
|
||||
} call_type;
|
||||
|
||||
typedef enum {
|
||||
call_inviting, /* when sending call invite */
|
||||
call_starting, /* when getting call invite */
|
||||
call_active,
|
||||
call_hold
|
||||
|
||||
} call_state;
|
||||
|
||||
typedef int crypto_key;
|
||||
|
||||
typedef struct msi_call_s { /* Call info structure */
|
||||
call_state _state;
|
||||
call_type _type_local;
|
||||
call_type* _type_peer; /* Support for conference starts with this */
|
||||
uint8_t _id[_CALL_ID_LEN]; /* Random value identifying the call */
|
||||
crypto_key _key; /* What is the type again? */
|
||||
uint16_t _participants; /* Number of participants */
|
||||
uint32_t _timeoutst; /* Time of the timeout for some action to end; 0 if infinite */
|
||||
int _outgoing_timer_id; /* Timer id */
|
||||
|
||||
} msi_call_t;
|
||||
|
||||
typedef struct msi_session_s {
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
crypto_key _key; /* The key */
|
||||
|
||||
/* Call information/handler. ( Maybe only information? ) */
|
||||
msi_call_t* _call;
|
||||
|
||||
/* Storage for message receiving */
|
||||
struct msi_msg_s* _oldest_msg;
|
||||
struct msi_msg_s* _last_msg; /* tail */
|
||||
|
||||
/*int _friend_id;*/
|
||||
tox_IP_Port _friend_id;
|
||||
|
||||
int _last_error_id; /* Determine the last error */
|
||||
const uint8_t* _last_error_str;
|
||||
|
||||
const uint8_t* _user_agent;
|
||||
|
||||
void* _agent_handler; /* Pointer to an object that is handling msi */
|
||||
void* _core_handler; /* Pointer to networking core or to anything that
|
||||
* should handle interaction with core/networking
|
||||
*/
|
||||
void* _event_handler; /* Pointer to an object which handles the events */
|
||||
|
||||
uint32_t _frequ;
|
||||
uint32_t _call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
|
||||
} msi_session_t;
|
||||
|
||||
|
||||
|
||||
msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent );
|
||||
int msi_terminate_session ( msi_session_t* _session );
|
||||
|
||||
pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms );
|
||||
|
||||
/* Registering callbacks */
|
||||
|
||||
/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) );*/
|
||||
void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) );
|
||||
|
||||
/* Callbacks that handle the states */
|
||||
void msi_register_callback_call_started ( MCALLBACK );
|
||||
void msi_register_callback_call_canceled ( MCALLBACK );
|
||||
void msi_register_callback_call_rejected ( MCALLBACK );
|
||||
void msi_register_callback_call_ended ( MCALLBACK );
|
||||
|
||||
void msi_register_callback_recv_invite ( MCALLBACK );
|
||||
void msi_register_callback_recv_ringing ( MCALLBACK );
|
||||
void msi_register_callback_recv_starting ( MCALLBACK );
|
||||
void msi_register_callback_recv_ending ( MCALLBACK );
|
||||
void msi_register_callback_recv_error ( MCALLBACK );
|
||||
|
||||
void msi_register_callback_requ_timeout ( MCALLBACK );
|
||||
/* -------- */
|
||||
|
||||
|
||||
/* Function handling receiving from core */
|
||||
/*static int msi_handlepacket ( tox_IP_Port ip_port, uint8_t* _data, uint16_t _lenght ); */
|
||||
|
||||
/* functions describing the usage of msi */
|
||||
int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms );
|
||||
int msi_hangup ( msi_session_t* _session );
|
||||
|
||||
int msi_answer ( msi_session_t* _session, call_type _call_type );
|
||||
int msi_cancel ( msi_session_t* _session );
|
||||
int msi_reject ( msi_session_t* _session );
|
||||
|
||||
int msi_send_msg ( msi_session_t* _session, struct msi_msg_s* _msg );
|
||||
void msi_store_msg ( msi_session_t* _session, struct msi_msg_s* _msg );
|
||||
|
||||
#endif /* _MSI_IMPL_H_ */
|
|
@ -1,214 +0,0 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "toxmsi_event.h"
|
||||
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int _unique_id = 1;
|
||||
|
||||
/* clear events */
|
||||
void clear_events (event_container_t** _event_container, size_t* _counter)
|
||||
{
|
||||
assert( *_event_container );
|
||||
|
||||
free(*_event_container);
|
||||
*_event_container = NULL;
|
||||
|
||||
*_counter = 0;
|
||||
}
|
||||
|
||||
int pop_id ( event_container_t** _event_container, size_t* _counter, int _id )
|
||||
{
|
||||
if ( !*_event_container || !*_counter || !_id )
|
||||
return FAILURE;
|
||||
|
||||
event_container_t* _it = *_event_container;
|
||||
int i;
|
||||
|
||||
for ( i = *_counter; i > 0 ; -- i ){
|
||||
if ( _it->_id == _id ) { /* Hit! */
|
||||
break;
|
||||
}
|
||||
++_it;
|
||||
}
|
||||
|
||||
if ( i ) {
|
||||
for ( ; i > 0; -- i ){ *_it = *(_it + 1); ++_it; }
|
||||
-- (*_counter);
|
||||
*_event_container = realloc(*_event_container, sizeof(event_container_t) * (*_counter)); /* resize */
|
||||
|
||||
if ( *_counter )
|
||||
assert(*_event_container);
|
||||
|
||||
return SUCCESS;
|
||||
|
||||
} else {
|
||||
assert(i);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* main poll for event execution */
|
||||
void* event_poll( void* _event_handler_p )
|
||||
{
|
||||
event_handler_t* _event_handler = _event_handler_p;
|
||||
uint32_t* _frequms = &_event_handler->_frequms;
|
||||
|
||||
|
||||
while ( _event_handler->_running )
|
||||
{
|
||||
|
||||
if ( _event_handler->_events_count ){
|
||||
pthread_mutex_lock(&_event_handler->_mutex);
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < _event_handler->_events_count; i ++ ){
|
||||
_event_handler->_events[i]._event(_event_handler->_events[i]._event_args);
|
||||
|
||||
}
|
||||
clear_events(&_event_handler->_events, &_event_handler->_events_count);
|
||||
|
||||
pthread_mutex_unlock(&_event_handler->_mutex);
|
||||
}
|
||||
|
||||
if ( _event_handler->_timed_events_count ){
|
||||
pthread_mutex_lock(&_event_handler->_mutex);
|
||||
|
||||
uint32_t _time = t_time();
|
||||
|
||||
if ( _event_handler->_timed_events[0]._timeout < _time ) {
|
||||
_event_handler->_timed_events[0]._event(_event_handler->_timed_events[0]._event_args);
|
||||
|
||||
pop_id(&_event_handler->_timed_events,
|
||||
&_event_handler->_timed_events_count,
|
||||
_event_handler->_timed_events[0]._id);
|
||||
}
|
||||
pthread_mutex_unlock(&_event_handler->_mutex);
|
||||
}
|
||||
|
||||
|
||||
usleep(*_frequms);
|
||||
}
|
||||
|
||||
_event_handler->_running = -1;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void push_event ( event_container_t** _container, size_t* _counter, event_t _func, event_arg_t _arg )
|
||||
{
|
||||
(*_counter)++;
|
||||
(*_container) = realloc((*_container), sizeof(event_container_t) * (*_counter));
|
||||
assert((*_container) != NULL);
|
||||
|
||||
(*_container[*_counter - 1])._event = _func;
|
||||
(*_container[*_counter - 1])._event_args = _arg;
|
||||
(*_container[*_counter - 1])._timeout = 0;
|
||||
(*_container[*_counter - 1])._id = 0;
|
||||
}
|
||||
|
||||
void throw_event( void* _event_handler_p, event_t _func, event_arg_t _arg )
|
||||
{
|
||||
if ( !_func )
|
||||
return;
|
||||
|
||||
event_handler_t* _event_handler = _event_handler_p;
|
||||
|
||||
pthread_mutex_lock(&_event_handler->_mutex);
|
||||
|
||||
push_event(&_event_handler->_events, &_event_handler->_events_count, _func, _arg);
|
||||
|
||||
pthread_mutex_unlock(&_event_handler->_mutex);
|
||||
}
|
||||
|
||||
int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout)
|
||||
{
|
||||
if ( !_func )
|
||||
return FAILURE;
|
||||
|
||||
event_handler_t* _event_handler = _event_handler_p;
|
||||
|
||||
pthread_mutex_lock(&_event_handler->_mutex);
|
||||
|
||||
push_event(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _func, _arg);
|
||||
size_t _counter = _event_handler->_timed_events_count;
|
||||
_event_handler->_timed_events[_counter - 1]._timeout = _timeout + t_time();
|
||||
_event_handler->_timed_events[_counter - 1]._id = _unique_id; ++_unique_id;
|
||||
|
||||
|
||||
/* reorder */
|
||||
if ( _counter > 1 ) {
|
||||
|
||||
int i = _counter - 1;
|
||||
/* start from behind excluding last added member */
|
||||
event_container_t* _it = &_event_handler->_timed_events[i - 1];
|
||||
|
||||
event_container_t _last_added = _event_handler->_timed_events[i];
|
||||
|
||||
for ( ; i > 0; --i ) {
|
||||
if ( _it->_timeout > _timeout ){
|
||||
*(_it + 1) = *_it;
|
||||
*_it = _last_added; -- _it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_event_handler->_mutex);
|
||||
|
||||
return _event_handler->_timed_events[_counter - 1]._id;
|
||||
}
|
||||
int cancel_timer_event ( void* _event_handler_p, int _id )
|
||||
{
|
||||
event_handler_t* _event_handler = _event_handler_p;
|
||||
return pop_id(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _id);
|
||||
}
|
||||
|
||||
event_handler_t* init_event_poll (uint32_t _frequms)
|
||||
{
|
||||
event_handler_t* _retu = calloc(sizeof(event_handler_t), 1);
|
||||
assert(_retu);
|
||||
/* Initialize basic events */
|
||||
_retu->_events = NULL ;
|
||||
|
||||
/* Initialize timed events */
|
||||
_retu->_timed_events = NULL;
|
||||
|
||||
_retu->_frequms = _frequms;
|
||||
_retu->_running = 1;
|
||||
pthread_mutex_init(&_retu->_mutex, NULL);
|
||||
|
||||
pthread_create(&_retu->_thread_id, NULL, event_poll, _retu);
|
||||
int _rc = pthread_detach(_retu->_thread_id);
|
||||
assert(_rc == 0);
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
int terminate_event_poll(event_handler_t* _handler)
|
||||
{
|
||||
if ( !_handler )
|
||||
return FAILURE;
|
||||
|
||||
_handler->_running = 0;
|
||||
while (_handler->_running != -1); /* Wait for execution */
|
||||
|
||||
if (_handler->_events)
|
||||
clear_events(&_handler->_events, &_handler->_events_count);
|
||||
if (_handler->_events)
|
||||
clear_events(&_handler->_timed_events, &_handler->_timed_events_count);
|
||||
|
||||
pthread_mutex_destroy( &_handler->_mutex );
|
||||
|
||||
free(_handler);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef _MSI__EVENT_H_
|
||||
#define _MSI__EVENT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
|
||||
typedef void* event_arg_t;
|
||||
|
||||
typedef void ( *event_t ) ( event_arg_t );
|
||||
typedef void ( *timed_event_t ) ( event_arg_t );
|
||||
|
||||
typedef struct event_container_s {
|
||||
event_t _event;
|
||||
event_arg_t _event_args;
|
||||
uint32_t _timeout;
|
||||
long long _id;
|
||||
|
||||
} event_container_t;
|
||||
|
||||
typedef struct event_handler_s {
|
||||
event_container_t* _events;
|
||||
size_t _events_count;
|
||||
|
||||
event_container_t* _timed_events;
|
||||
size_t _timed_events_count;
|
||||
|
||||
uint32_t _frequms;
|
||||
int _running;
|
||||
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_t _thread_id;
|
||||
|
||||
} event_handler_t;
|
||||
|
||||
event_handler_t* init_event_poll ( uint32_t _frequms );
|
||||
int terminate_event_poll ( event_handler_t* _event_handler );
|
||||
|
||||
void throw_event ( void* _event_handler_p, event_t _func, event_arg_t _arg );
|
||||
|
||||
/* Not yet ready for use */
|
||||
int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout);
|
||||
int cancel_timer_event ( void* _event_handler_p, int _id );
|
||||
|
||||
|
||||
#endif /* _MSI__EVENT_H_ */
|
|
@ -1,181 +0,0 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxmsi_message.h"
|
||||
#include <string.h>
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include "../toxcore/Lossless_UDP.h"
|
||||
|
||||
#define ALLOC_ADD_DATA(_tempval, _hdrlist, _fielddef, _msgvar, _alloctype) \
|
||||
_tempval = msi_search_field(_hdrlist, (const uint8_t*)_fielddef); \
|
||||
if ( _tempval ){ \
|
||||
_msgvar = calloc(sizeof(_alloctype), 1); \
|
||||
assert(_msgvar); \
|
||||
_msgvar->_header_value = _tempval; \
|
||||
}
|
||||
|
||||
uint8_t* msi_search_field ( msi_header_t* _list, const uint8_t* _field )
|
||||
{
|
||||
assert(_list);
|
||||
assert(_field);
|
||||
|
||||
msi_header_t* _iterator;
|
||||
|
||||
for ( _iterator = _list;
|
||||
_iterator && strcmp((const char*)_iterator->_header_field, (const char*)_field) != 0;
|
||||
_iterator = _iterator->next );
|
||||
|
||||
if ( _iterator ){
|
||||
return t_strallcpy(_iterator->_header_value);
|
||||
} else return NULL;
|
||||
}
|
||||
|
||||
int msi_parse_headers ( msi_msg_t* _msg )
|
||||
{
|
||||
assert(_msg);
|
||||
|
||||
if ( !_msg->_headers )
|
||||
return FAILURE;
|
||||
|
||||
msi_header_t* _list = _msg->_headers;
|
||||
uint8_t* _field_current;
|
||||
|
||||
ALLOC_ADD_DATA(_field_current, _list, _CALL_ID_FIELD, _msg->_call_id, msi_header_call_id_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _VERSION_FIELD, _msg->_version, msi_header_version_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _REQUEST_FIELD, _msg->_request, msi_header_request_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _RESPONSE_FIELD, _msg->_response, msi_header_response_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _FRIENDID_FIELD, _msg->_friend_id, msi_header_friendid_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _CALLTYPE_FIELD, _msg->_call_type, msi_header_call_type_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _USERAGENT_FIELD, _msg->_user_agent, msi_header_user_agent_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _INFO_FIELD, _msg->_info, msi_header_info_t)
|
||||
ALLOC_ADD_DATA(_field_current, _list, _REASON_FIELD, _msg->_reason, msi_header_reason_t)
|
||||
|
||||
/* Since we don't need the raw header anymore remove it */
|
||||
msi_header_t* _temp;
|
||||
while ( _list ){
|
||||
_temp = _list->next;
|
||||
free(_list->_header_field);
|
||||
free(_list->_header_value);
|
||||
free(_list);
|
||||
_list = _temp;
|
||||
}
|
||||
|
||||
_msg->_headers = NULL;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* If you find better way of parsing values let me know
|
||||
*/
|
||||
msi_header_t* msi_add_new_header ( uint8_t* _value )
|
||||
{
|
||||
if ( !_value )
|
||||
return NULL;
|
||||
|
||||
size_t _length = t_memlen(_value);
|
||||
|
||||
if ( !_length ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t _first_len = t_strfind(_value, (const uint8_t*)" ");
|
||||
if ( !_first_len ){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t _second_len = (_length - _first_len);
|
||||
if ( !_second_len ){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* _identifier = calloc(sizeof (uint8_t), (_first_len + 1) );
|
||||
uint8_t* _data = calloc(sizeof (uint8_t), (_second_len + 1) );
|
||||
|
||||
assert(_identifier);
|
||||
assert(_data);
|
||||
|
||||
|
||||
uint8_t* _p_it = _value;
|
||||
size_t _num_it;
|
||||
|
||||
for ( _num_it = 0; *_p_it != ' '; _num_it++ ){
|
||||
_identifier[_num_it] = *_p_it;
|
||||
++_p_it;
|
||||
}
|
||||
_identifier[_num_it] = '\0';
|
||||
++_p_it;
|
||||
|
||||
|
||||
for ( _num_it = 0; *_p_it != '\r'; _num_it++ ){
|
||||
_data[_num_it] = *_p_it;
|
||||
++_p_it;
|
||||
}
|
||||
_data[_num_it] = '\r';
|
||||
_data[_num_it + 1] = '\0';
|
||||
|
||||
msi_header_t* _retu = calloc(sizeof(msi_header_t), 1);
|
||||
assert(_retu);
|
||||
|
||||
_retu->_header_field = _identifier;
|
||||
_retu->_header_value = _data;
|
||||
|
||||
_retu->next = NULL;
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
msi_header_t* msi_parse_raw_data ( const uint8_t* _data )
|
||||
{
|
||||
assert(_data);
|
||||
|
||||
uint8_t* _header_string;
|
||||
|
||||
_header_string = (uint8_t*) strtok ((char*)_data, _RAW_TERMINATOR);
|
||||
|
||||
msi_header_t* _head = msi_add_new_header(_header_string);
|
||||
msi_header_t* _it = _head;
|
||||
|
||||
while ( _header_string && _it ){
|
||||
|
||||
_header_string = (uint8_t*) strtok (NULL, _RAW_TERMINATOR);
|
||||
_it->next = msi_add_new_header(_header_string);
|
||||
if ( _it->next ){
|
||||
_it = _it->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate through list and remove all fault headers if any */
|
||||
|
||||
msi_header_t* _tmp = _it;
|
||||
|
||||
for ( _it = _head; _it; _it = _it->next ){
|
||||
|
||||
if ( !_it->_header_value || !_it->_header_field ) {
|
||||
_tmp ->next = _it->next;
|
||||
|
||||
if ( _it->_header_field )
|
||||
free(_it->_header_field);
|
||||
if ( _it->_header_value )
|
||||
free(_it->_header_value);
|
||||
|
||||
if ( _it == _head ){
|
||||
_head = _head->next;
|
||||
}
|
||||
|
||||
free(_it);
|
||||
_it = _tmp;
|
||||
} else
|
||||
_tmp = _it;
|
||||
|
||||
}
|
||||
|
||||
return _head;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
#ifndef _MSI_HEADER_
|
||||
#define _MSI_HEADER_
|
||||
|
||||
/* Basic format of the unparsed header string
|
||||
* ( No spaces in field allowed )
|
||||
* Version 0.1.1\n\r
|
||||
* Request INVITE\n\r
|
||||
* Response\n\r
|
||||
* Friend-id ( from ip )\n\r
|
||||
* Call-type AUDIO\n\r
|
||||
* User-agent phone-v.1.0.0\n\r
|
||||
*/
|
||||
|
||||
|
||||
/* define raw header terminator */
|
||||
static const char* _RAW_TERMINATOR = "\n\r";
|
||||
|
||||
/* define string formats for the identifiers */
|
||||
#define _VERSION_FIELD "Version"
|
||||
#define _REQUEST_FIELD "Request"
|
||||
#define _RESPONSE_FIELD "Response"
|
||||
#define _FRIENDID_FIELD "Friend-id"
|
||||
#define _CALLTYPE_FIELD "Call-type"
|
||||
#define _USERAGENT_FIELD "User-agent"
|
||||
#define _INFO_FIELD "INFO"
|
||||
#define _REASON_FIELD "Reason"
|
||||
#define _CALL_ID_FIELD "Call-id"
|
||||
|
||||
#define HEADER_VALUES \
|
||||
/*uint8_t* _header_field */ \
|
||||
uint8_t* _header_value;
|
||||
|
||||
typedef struct msi_header_s { /* raw header list */
|
||||
uint8_t* _header_field;
|
||||
uint8_t* _header_value;
|
||||
|
||||
struct msi_header_s* next;
|
||||
|
||||
} msi_header_t;
|
||||
|
||||
|
||||
|
||||
typedef struct msi_header_version_s { /* Defines our version */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_version_t;
|
||||
|
||||
typedef struct msi_header_request_s { /* Defines our request */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_request_t;
|
||||
|
||||
typedef struct msi_header_response_s { /* Defines our response */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_response_t;
|
||||
|
||||
typedef struct msi_header_friendid_s { /* Defines source that sent the message */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_friendid_t;
|
||||
|
||||
typedef struct msi_header_call_type_s { /* Defines the type of the call */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_call_type_t;
|
||||
|
||||
typedef struct msi_header_user_agent_s { /* Defines the device of the participant */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_user_agent_t;
|
||||
|
||||
|
||||
typedef struct msi_header_call_id_s { /* Call id that is used to identify the call */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_call_id_t;
|
||||
|
||||
typedef struct msi_header_info_s { /* Defines informational message header */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_info_t;
|
||||
|
||||
typedef struct msi_header_reason_s { /* Defines reason mostly for error messages */
|
||||
HEADER_VALUES
|
||||
|
||||
} msi_header_reason_t;
|
||||
|
||||
struct msi_msg_s;
|
||||
|
||||
/*
|
||||
* Parses the header list to header types
|
||||
*/
|
||||
int msi_parse_headers ( struct msi_msg_s* _msg );
|
||||
|
||||
/* Make sure it's null terminated */
|
||||
msi_header_t* msi_parse_raw_data ( const uint8_t* _data );
|
||||
|
||||
#endif /* _MSI_HEADER_ */
|
|
@ -1,267 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxmsi_message.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ALLOCATE_HEADER(_header_type, _var, _m_header_value) \
|
||||
_var = calloc( sizeof(_header_type), 1 ); \
|
||||
assert(_var); \
|
||||
_var->_header_value = t_strallcpy((const uint8_t*)_m_header_value);
|
||||
|
||||
#define DEALLOCATE_HEADER(_header) \
|
||||
if ( _header && _header->_header_value ) { \
|
||||
free( _header->_header_value ); \
|
||||
free( _header ); }
|
||||
|
||||
#define SET_HEADER(_header_type, _var, _m_header_value) \
|
||||
if ( _var ){ \
|
||||
free(_var->_header_value); \
|
||||
free(_var);} \
|
||||
ALLOCATE_HEADER( _header_type, _var, _m_header_value )
|
||||
|
||||
|
||||
/* Sets empty message
|
||||
*/
|
||||
void set_msg ( msi_msg_t* _msg )
|
||||
{
|
||||
_msg->_call_type = NULL;
|
||||
_msg->_version = NULL;
|
||||
_msg->_request = NULL;
|
||||
_msg->_response = NULL;
|
||||
_msg->_friend_id = NULL;
|
||||
_msg->_user_agent = NULL;
|
||||
_msg->_call_id = NULL;
|
||||
_msg->_reason = NULL;
|
||||
_msg->_info = NULL;
|
||||
_msg->_next = NULL;
|
||||
_msg->_headers = NULL;
|
||||
}
|
||||
|
||||
void msi_free_msg ( msi_msg_t* _msg )
|
||||
{
|
||||
assert(_msg);
|
||||
|
||||
DEALLOCATE_HEADER(_msg->_call_type);
|
||||
DEALLOCATE_HEADER(_msg->_friend_id);
|
||||
DEALLOCATE_HEADER(_msg->_request);
|
||||
DEALLOCATE_HEADER(_msg->_response);
|
||||
DEALLOCATE_HEADER(_msg->_user_agent);
|
||||
DEALLOCATE_HEADER(_msg->_version);
|
||||
DEALLOCATE_HEADER(_msg->_info);
|
||||
DEALLOCATE_HEADER(_msg->_reason);
|
||||
DEALLOCATE_HEADER(_msg->_call_id);
|
||||
|
||||
free(_msg);
|
||||
}
|
||||
|
||||
void append_header_to_string ( uint8_t* _dest, const uint8_t* _header_field, const uint8_t* _header_value )
|
||||
{
|
||||
assert(_dest);
|
||||
assert(_header_value);
|
||||
assert(_header_field);
|
||||
|
||||
size_t _dest_len = t_memlen(_dest);
|
||||
|
||||
uint8_t* _storage_iterator = _dest + _dest_len;
|
||||
const uint8_t* _header_fit = _header_field;
|
||||
const uint8_t* _header_val = _header_value;
|
||||
const uint8_t* _term_it = (const uint8_t*) _RAW_TERMINATOR;
|
||||
|
||||
while ( *_header_fit ){
|
||||
*_storage_iterator = *_header_fit;
|
||||
++_header_fit;
|
||||
++_storage_iterator;
|
||||
}
|
||||
|
||||
*_storage_iterator = ' '; /* place space */
|
||||
++_storage_iterator;
|
||||
|
||||
while ( *_header_val ){
|
||||
*_storage_iterator = *_header_val;
|
||||
++_header_val;
|
||||
++_storage_iterator;
|
||||
}
|
||||
|
||||
while ( *_term_it ){
|
||||
*_storage_iterator = *_term_it;
|
||||
++_term_it;
|
||||
++_storage_iterator;
|
||||
}
|
||||
}
|
||||
|
||||
msi_msg_t* msi_parse_msg ( const uint8_t* _data )
|
||||
{
|
||||
assert(_data);
|
||||
|
||||
msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 );
|
||||
assert(_retu);
|
||||
|
||||
set_msg(_retu);
|
||||
|
||||
_retu->_headers = msi_parse_raw_data ( _data );
|
||||
|
||||
if ( msi_parse_headers (_retu) == FAILURE ) {
|
||||
msi_free_msg(_retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !_retu->_version || strcmp((const char*)_retu->_version->_header_value, VERSION_STRING) != 0 ){
|
||||
msi_free_msg(_retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* msi_msg_to_string ( msi_msg_t* _msg )
|
||||
{
|
||||
assert(_msg);
|
||||
|
||||
uint8_t* _retu = calloc(sizeof(uint8_t), MSI_MAXMSG_SIZE );
|
||||
assert(_retu);
|
||||
|
||||
t_memset(_retu, '\0', MSI_MAXMSG_SIZE);
|
||||
|
||||
if ( _msg->_version ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_VERSION_FIELD, _msg->_version->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_request ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_REQUEST_FIELD, _msg->_request->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_response ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_RESPONSE_FIELD, _msg->_response->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_friend_id ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_FRIENDID_FIELD, _msg->_friend_id->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_call_type ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_CALLTYPE_FIELD, _msg->_call_type->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_user_agent ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_USERAGENT_FIELD, _msg->_user_agent->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_info ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_INFO_FIELD, _msg->_info->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_call_id ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_CALL_ID_FIELD, _msg->_call_id->_header_value);
|
||||
}
|
||||
|
||||
if ( _msg->_reason ){
|
||||
append_header_to_string(_retu, (const uint8_t*)_REASON_FIELD, _msg->_reason->_header_value);
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _typeid )
|
||||
{
|
||||
msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 );
|
||||
assert(_retu);
|
||||
|
||||
set_msg(_retu);
|
||||
|
||||
if ( _type == TYPE_REQUEST ){
|
||||
ALLOCATE_HEADER( msi_header_request_t, _retu->_request, _typeid )
|
||||
_retu->_response = NULL;
|
||||
|
||||
} else if ( _type == TYPE_RESPONSE ) {
|
||||
ALLOCATE_HEADER( msi_header_response_t, _retu->_response, _typeid )
|
||||
_retu->_request = NULL;
|
||||
|
||||
} else {
|
||||
msi_free_msg(_retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ALLOCATE_HEADER( msi_header_version_t, _retu->_version, VERSION_STRING)
|
||||
|
||||
_retu->_friend_id = NULL;
|
||||
_retu->_call_type = NULL;
|
||||
_retu->_user_agent = NULL;
|
||||
_retu->_info = NULL;
|
||||
|
||||
_retu->_next = NULL;
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len )
|
||||
{
|
||||
assert(_storage);
|
||||
|
||||
static const char _alphanum[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"; /* avoids warning */
|
||||
|
||||
uint8_t _val = 0;
|
||||
size_t _it;
|
||||
|
||||
/* Generate random values 1-255 */
|
||||
for ( _it = 0; _it < _len; _it ++ ) {
|
||||
while ( !_val ) _val = (uint8_t) _alphanum[ t_random(61) ];
|
||||
|
||||
_storage[_it] = _val;
|
||||
_val = 0;
|
||||
}
|
||||
|
||||
return _storage;
|
||||
}
|
||||
|
||||
/* HEADER SETTING
|
||||
*/
|
||||
|
||||
void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field )
|
||||
{
|
||||
assert(_msg);
|
||||
assert(_header_field);
|
||||
|
||||
SET_HEADER(msi_header_call_type_t, _msg->_call_type, _header_field)
|
||||
}
|
||||
void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field )
|
||||
{
|
||||
assert(_msg);
|
||||
assert(_header_field);
|
||||
|
||||
SET_HEADER(msi_header_user_agent_t, _msg->_user_agent, _header_field)
|
||||
}
|
||||
void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field )
|
||||
{
|
||||
assert(_msg);
|
||||
assert(_header_field);
|
||||
|
||||
SET_HEADER(msi_header_friendid_t, _msg->_friend_id, _header_field)
|
||||
}
|
||||
void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field )
|
||||
{
|
||||
}
|
||||
void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field )
|
||||
{
|
||||
assert(_msg);
|
||||
assert(_header_field);
|
||||
|
||||
SET_HEADER(msi_header_reason_t, _msg->_reason, _header_field)
|
||||
}
|
||||
void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field )
|
||||
{
|
||||
assert(_msg);
|
||||
assert(_header_field);
|
||||
|
||||
SET_HEADER(msi_header_call_id_t, _msg->_call_id, _header_field)
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
#ifndef _MSI_MESSAGE_H_
|
||||
#define _MSI_MESSAGE_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "../toxcore/network.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
#include "toxmsi_header.h"
|
||||
|
||||
#define TYPE_REQUEST 1
|
||||
#define TYPE_RESPONSE 2
|
||||
|
||||
#define VERSION_STRING "0.2.2"
|
||||
|
||||
#define MSI_MAXMSG_SIZE 65535
|
||||
|
||||
typedef enum {
|
||||
_invite,
|
||||
_start,
|
||||
_cancel,
|
||||
_reject,
|
||||
_end,
|
||||
|
||||
} msi_request_t;
|
||||
|
||||
static inline const uint8_t *stringify_request(msi_request_t _request)
|
||||
{
|
||||
static const uint8_t* strings[] =
|
||||
{
|
||||
(uint8_t*)"INVITE",
|
||||
(uint8_t*)"START",
|
||||
(uint8_t*)"CANCEL",
|
||||
(uint8_t*)"REJECT",
|
||||
(uint8_t*)"END"
|
||||
};
|
||||
|
||||
return strings[_request];
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
_trying,
|
||||
_ringing,
|
||||
_starting,
|
||||
_ending,
|
||||
_error
|
||||
|
||||
} msi_response_t;
|
||||
|
||||
static inline const uint8_t *stringify_response(msi_response_t _response)
|
||||
{
|
||||
static const uint8_t* strings[] =
|
||||
{
|
||||
(uint8_t*)"trying",
|
||||
(uint8_t*)"ringing",
|
||||
(uint8_t*)"starting",
|
||||
(uint8_t*)"ending",
|
||||
(uint8_t*)"error"
|
||||
};
|
||||
|
||||
return strings[_response];
|
||||
}
|
||||
|
||||
|
||||
typedef struct msi_msg_s {
|
||||
/* This is the header list which contains unparsed headers */
|
||||
msi_header_t* _headers;
|
||||
|
||||
/* Headers parsed */
|
||||
msi_header_version_t* _version;
|
||||
msi_header_request_t* _request;
|
||||
msi_header_response_t* _response;
|
||||
msi_header_friendid_t* _friend_id;
|
||||
msi_header_call_type_t* _call_type;
|
||||
msi_header_user_agent_t* _user_agent;
|
||||
msi_header_info_t* _info;
|
||||
msi_header_reason_t* _reason;
|
||||
msi_header_call_id_t* _call_id;
|
||||
|
||||
/* Pointer to next member since it's list duuh */
|
||||
struct msi_msg_s* _next;
|
||||
|
||||
} msi_msg_t;
|
||||
|
||||
|
||||
/*
|
||||
* Parse data received from socket
|
||||
*/
|
||||
msi_msg_t* msi_parse_msg ( const uint8_t* _data );
|
||||
|
||||
/*
|
||||
* Make new message. Arguments: _type: (request, response); _type_field ( value )
|
||||
*/
|
||||
msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _type_field );
|
||||
|
||||
/* Header setting */
|
||||
void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field );
|
||||
void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field );
|
||||
void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field );
|
||||
void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field );
|
||||
void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field );
|
||||
void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field );
|
||||
|
||||
|
||||
uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len );
|
||||
/*
|
||||
* Parses message struct to string.
|
||||
* Allocates memory so don't forget to free it
|
||||
*/
|
||||
uint8_t* msi_msg_to_string ( msi_msg_t* _msg );
|
||||
|
||||
/*
|
||||
* msi_msg_s struct deallocator
|
||||
*/
|
||||
void msi_free_msg ( msi_msg_t* _msg );
|
||||
|
||||
#endif /* _MSI_MESSAGE_H_ */
|
|
@ -1,34 +0,0 @@
|
|||
if BUILD_AV
|
||||
|
||||
lib_LTLIBRARIES += libtoxrtp.la
|
||||
|
||||
libtoxrtp_la_include_HEADERS = \
|
||||
../toxrtp/toxrtp.h
|
||||
|
||||
libtoxrtp_la_includedir = $(includedir)/tox
|
||||
|
||||
libtoxrtp_la_SOURCES = ../toxrtp/toxrtp_error.h \
|
||||
../toxrtp/toxrtp_error.c \
|
||||
../toxrtp/toxrtp_error_id.h \
|
||||
../toxrtp/toxrtp_helper.h \
|
||||
../toxrtp/toxrtp_helper.c \
|
||||
../toxrtp/toxrtp.h \
|
||||
../toxrtp/toxrtp.c \
|
||||
../toxrtp/toxrtp_message.h \
|
||||
../toxrtp/toxrtp_message.c \
|
||||
../toxcore/network.h \
|
||||
../toxcore/network.c \
|
||||
../toxcore/util.h \
|
||||
../toxcore/util.c
|
||||
|
||||
libtoxrtp_la_CFLAGS = -I../toxcore \
|
||||
-I../toxrtp \
|
||||
$(NACL_CFLAGS)
|
||||
|
||||
libtoxrtp_la_LDFLAGS = $(TOXRTP_LT_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(EXTRA_LT_LDFLAGS)
|
||||
|
||||
libtoxrtp_la_LIBS = $(NACL_LIBS)
|
||||
|
||||
endif
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
#define _BSD_SOURCE
|
||||
|
||||
#include "../toxrtp.h"
|
||||
#include "../toxrtp_message.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utime.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "test_helper.h"
|
||||
#include "../../toxcore/tox.h"
|
||||
|
||||
#ifdef _CT_BIDIRECT
|
||||
|
||||
int _print_help( const char* name )
|
||||
{
|
||||
char* _help = malloc( 300 );
|
||||
memset(_help, '\0', 300);
|
||||
|
||||
strcat(_help, " Usage: ");
|
||||
strcat(_help, name);
|
||||
strcat(_help, "\n -d IP ( destination )\n"
|
||||
" -p PORT ( dest Port )\n"
|
||||
" -l PORT ( listen Port ) \n");
|
||||
|
||||
puts ( _help );
|
||||
|
||||
free(_help);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
int status;
|
||||
tox_IP_Port Ip_port;
|
||||
const char* ip, *psend, *plisten;
|
||||
uint16_t port_send, port_listen;
|
||||
const uint8_t* test_bytes = "0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789";
|
||||
|
||||
|
||||
rtp_session_t* _m_session;
|
||||
rtp_msg_t *_m_msg_R, *_m_msg_S;
|
||||
arg_t* _list = parse_args ( argc, argv );
|
||||
|
||||
ip = find_arg_duble(_list, "-d");
|
||||
psend = find_arg_duble(_list, "-p");
|
||||
plisten = find_arg_duble(_list, "-l");
|
||||
|
||||
if ( !ip || !plisten || !psend )
|
||||
return _print_help(argv[0]);
|
||||
|
||||
port_send = atoi(psend);
|
||||
port_listen = atoi(plisten);
|
||||
|
||||
IP_Port local, remote;
|
||||
|
||||
/*
|
||||
* This is the Local ip. We initiate networking on
|
||||
* this value for it's the local one. To make stuff simpler we receive over this value
|
||||
* and send on the other one ( see remote )
|
||||
*/
|
||||
local.ip.i = htonl(INADDR_ANY);
|
||||
local.port = port_listen;
|
||||
Networking_Core* _networking = new_networking(local.ip, port_listen);
|
||||
|
||||
if ( !_networking )
|
||||
return FAILURE;
|
||||
|
||||
int _socket = _networking->sock;
|
||||
/*
|
||||
* Now this is the remote. It's used by rtp_session_t to determine the receivers ip etc.
|
||||
*/
|
||||
t_setipport ( ip, port_send, &remote );
|
||||
_m_session = rtp_init_session(-1, -1);
|
||||
rtp_add_receiver( _m_session, &remote );
|
||||
|
||||
/* Now let's start our main loop in both recv and send mode */
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
/*
|
||||
* This part checks for received messages and if gotten one
|
||||
* display 'Received msg!' indicator and free message
|
||||
*/
|
||||
_m_msg_R = rtp_recv_msg ( _m_session );
|
||||
|
||||
if ( _m_msg_R ) {
|
||||
puts ( "Received msg!" );
|
||||
rtp_free_msg(_m_session, _m_msg_R);
|
||||
}
|
||||
/* -------------------- */
|
||||
|
||||
/*
|
||||
* This one makes a test msg and sends that message to the 'remote'
|
||||
*/
|
||||
_m_msg_S = rtp_msg_new ( _m_session, test_bytes, 280 ) ;
|
||||
rtp_send_msg ( _m_session, _m_msg_S, _socket );
|
||||
usleep ( 10000 );
|
||||
/* -------------------- */
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* _CT_BIDIRECT */
|
|
@ -1,316 +0,0 @@
|
|||
/* test_headers.c
|
||||
*
|
||||
* Tests header parsing. You probably won't need this. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "test_helper.h"
|
||||
#include "../toxrtp.h"
|
||||
#include "../toxrtp_message.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utime.h>
|
||||
#include <assert.h>
|
||||
#include "../toxrtp_error_id.h"
|
||||
|
||||
#define _CT_HEADERS_
|
||||
|
||||
#ifdef _CT_HEADERS
|
||||
|
||||
int _socket;
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
int print_help()
|
||||
{
|
||||
puts (
|
||||
" Usage: Tuxrtp [-s (send mode) -d IP ( destination ) -p PORT ( dest Port )] \n"
|
||||
" [-r ( recv mode ) ]"
|
||||
);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
void print_session_stats ( rtp_session_t* _m_session )
|
||||
{
|
||||
printf
|
||||
(
|
||||
"Session test:\n"
|
||||
"\tPackets sent:%d\n"
|
||||
"\tPackets recv:%d\n\n"
|
||||
"\tBytes sent:%d\n"
|
||||
"\tBytes recv:%d\n\n"
|
||||
"\tHeader CCSRs:%d\n"
|
||||
,
|
||||
_m_session->_packets_sent,
|
||||
_m_session->_packets_recv,
|
||||
_m_session->_bytes_sent,
|
||||
_m_session->_bytes_recv,
|
||||
_m_session->_cc
|
||||
);
|
||||
|
||||
uint8_t i;
|
||||
for ( i = 0; i < _m_session->_cc; i++ ) {
|
||||
printf (
|
||||
"\t%d > :%d\n", i, _m_session->_csrc[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void print_header_info ( rtp_header_t* _header )
|
||||
{
|
||||
printf
|
||||
(
|
||||
"Header info:\n"
|
||||
"\tVersion :%d\n"
|
||||
"\tPadding :%d\n"
|
||||
"\tExtension :%d\n"
|
||||
"\tCSRC count :%d\n"
|
||||
"\tPayload type :%d\n"
|
||||
"\tMarker :%d\n\n"
|
||||
|
||||
"\tSSrc :%d\n"
|
||||
"\tSequence num :%d\n"
|
||||
"\tLenght: :%d\n"
|
||||
"\tCSRC's:\n"
|
||||
,
|
||||
rtp_header_get_flag_version ( _header ),
|
||||
rtp_header_get_flag_padding ( _header ),
|
||||
rtp_header_get_flag_extension ( _header ),
|
||||
rtp_header_get_flag_CSRC_count ( _header ),
|
||||
rtp_header_get_setting_payload_type ( _header ),
|
||||
rtp_header_get_setting_marker ( _header ),
|
||||
|
||||
_header->_ssrc,
|
||||
_header->_sequence_number,
|
||||
_header->_length
|
||||
);
|
||||
|
||||
|
||||
uint8_t i;
|
||||
for ( i = 0; i < rtp_header_get_flag_CSRC_count ( _header ); i++ ) {
|
||||
printf (
|
||||
"\t%d > :%d\n", i, _header->_csrc[i]
|
||||
);
|
||||
}
|
||||
|
||||
puts ( "\n" );
|
||||
}
|
||||
|
||||
void print_ext_header_info(rtp_ext_header_t* _ext_header)
|
||||
{
|
||||
printf
|
||||
(
|
||||
"External Header info: \n"
|
||||
"\tLenght :%d\n"
|
||||
"\tID :%d\n"
|
||||
"\tValue H :%d\n"
|
||||
"\tValue W :%d\n\n",
|
||||
_ext_header->_ext_len,
|
||||
_ext_header->_ext_type,
|
||||
rtp_get_resolution_marking_height(_ext_header, 0),
|
||||
rtp_get_resolution_marking_width(_ext_header, 0)
|
||||
);
|
||||
}
|
||||
|
||||
int rtp_handlepacket ( rtp_session_t* _session, rtp_msg_t* _msg )
|
||||
{
|
||||
if ( !_msg )
|
||||
return FAILURE;
|
||||
|
||||
if ( rtp_check_late_message(_session, _msg) < 0 ) {
|
||||
rtp_register_msg(_session, _msg);
|
||||
}
|
||||
|
||||
if ( _session->_last_msg ) {
|
||||
_session->_last_msg->_next = _msg;
|
||||
_session->_last_msg = _msg;
|
||||
} else {
|
||||
_session->_last_msg = _session->_oldest_msg = _msg;
|
||||
}
|
||||
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void* receivepacket_callback(void* _p_session)
|
||||
{
|
||||
rtp_msg_t* _msg;
|
||||
rtp_session_t* _session = _p_session;
|
||||
|
||||
uint32_t _bytes;
|
||||
tox_IP_Port _from;
|
||||
uint8_t _socket_data[MAX_UDP_PACKET_SIZE];
|
||||
|
||||
int _m_socket = _socket;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
int _status = receivepacket ( _m_socket, &_from, _socket_data, &_bytes );
|
||||
|
||||
if ( _status == FAILURE ) { /* nothing recved */
|
||||
usleep(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_lock ( &_mutex );
|
||||
|
||||
_msg = rtp_msg_parse ( NULL, _socket_data, _bytes );
|
||||
rtp_handlepacket(_session, _msg);
|
||||
|
||||
pthread_mutex_unlock ( &_mutex );
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int main ( int argc, char* argv[] )
|
||||
{
|
||||
arg_t* _list = parse_args ( argc, argv );
|
||||
|
||||
if ( _list == NULL ) { /* failed */
|
||||
return print_help();
|
||||
}
|
||||
|
||||
pthread_mutex_init ( &_mutex, NULL );
|
||||
|
||||
int status;
|
||||
IP_Port Ip_port;
|
||||
const char* ip;
|
||||
uint16_t port;
|
||||
|
||||
|
||||
const uint8_t* test_bytes [300];
|
||||
memset(test_bytes, 'a', 300);
|
||||
|
||||
rtp_session_t* _m_session;
|
||||
rtp_msg_t* _m_msg;
|
||||
|
||||
if ( find_arg_simple ( _list, "-r" ) != FAILURE ) { /* Server mode */
|
||||
|
||||
IP_Port LOCAL_IP; /* since you need at least 1 recv-er */
|
||||
LOCAL_IP.ip.i = htonl(INADDR_ANY);
|
||||
LOCAL_IP.port = RTP_PORT;
|
||||
LOCAL_IP.padding = -1;
|
||||
|
||||
_m_session = rtp_init_session ( -1, -1 );
|
||||
Networking_Core* _networking = new_networking(LOCAL_IP.ip, RTP_PORT_LISTEN);
|
||||
_socket = _networking->sock;
|
||||
|
||||
|
||||
if ( !_networking ){
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int _socket = _networking->sock;
|
||||
|
||||
if ( status < 0 ) {
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
return FAILURE;
|
||||
}
|
||||
/* -- start in recv mode, get 1 message and then analyze it -- */
|
||||
pthread_t _tid;
|
||||
RUN_IN_THREAD(receivepacket_callback, _tid, _m_session)
|
||||
|
||||
for ( ; ; ) { /* Recv for x seconds */
|
||||
_m_msg = rtp_recv_msg ( _m_session );
|
||||
|
||||
/* _m_msg = rtp_session_get_message_queded ( _m_session ); DEPRECATED */
|
||||
if ( _m_msg ) {
|
||||
/*rtp_free_msg(_m_session, _m_msg);
|
||||
_m_msg = NULL;*/
|
||||
printf("Timestamp: %d\n", _m_msg->_header->_timestamp);
|
||||
}
|
||||
|
||||
usleep ( 10000 );
|
||||
}
|
||||
|
||||
if ( _m_msg->_header ) {
|
||||
rtp_header_print ( _m_msg->_header );
|
||||
}
|
||||
if ( _m_msg->_ext_header ){
|
||||
print_ext_header_info(_m_msg->_ext_header);
|
||||
}
|
||||
|
||||
//print_session_stats ( _m_session );
|
||||
|
||||
|
||||
//printf ( "Payload: ( %d ) \n%s\n", _m_msg->_length, _m_msg->_data );
|
||||
|
||||
|
||||
} else if ( find_arg_simple ( _list, "-s" ) != FAILURE ) {
|
||||
ip = find_arg_duble ( _list, "-d" );
|
||||
|
||||
if ( ip == NULL ) {
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
const char* _port = find_arg_duble ( _list, "-p" );
|
||||
|
||||
if ( _port != NULL ) {
|
||||
port = atoi ( _port );
|
||||
}
|
||||
|
||||
t_setipport ( ip, port, &Ip_port );
|
||||
printf ( "Remote: %s:%d\n", ip, port );
|
||||
|
||||
Networking_Core* _networking = new_networking(Ip_port.ip, RTP_PORT);
|
||||
|
||||
if ( !_networking ){
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int _socket = _networking->sock;
|
||||
|
||||
_m_session = rtp_init_session ( -1, -1 );
|
||||
rtp_add_receiver( _m_session, &Ip_port );
|
||||
//rtp_add_resolution_marking(_m_session, 1920, 1080);
|
||||
//rtp_add_framerate_marking(_m_session, 1000);
|
||||
|
||||
puts ( "Now sending payload!\n" );
|
||||
uint16_t _first_sequ = _m_session->_sequence_number;
|
||||
|
||||
/* use already defined buffer lenght */
|
||||
while ( 1 ){
|
||||
_m_msg = rtp_msg_new ( _m_session, test_bytes, 300 );
|
||||
rtp_send_msg ( _m_session, _m_msg, _socket );
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
if ( _m_session->_last_error ) {
|
||||
puts ( _m_session->_last_error );
|
||||
}
|
||||
|
||||
return rtp_terminate_session(_m_session);
|
||||
|
||||
} else {
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
return FAILURE;
|
||||
}
|
||||
pthread_mutex_destroy ( &_mutex );
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* _CT_HEADERS */
|
|
@ -1,83 +0,0 @@
|
|||
/* test_helper.c
|
||||
*
|
||||
* Tests support. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "test_helper.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
arg_t* parse_args ( int argc, char* argv[] )
|
||||
{
|
||||
arg_t* _list = calloc(sizeof(arg_t), 1);
|
||||
_list->next = _list->prev = NULL;
|
||||
|
||||
arg_t* it = _list;
|
||||
|
||||
size_t val;
|
||||
for ( val = 0; val < argc; val ++ ) {
|
||||
it->value = argv[val];
|
||||
|
||||
if ( val < argc - 1 ) { /* just about to end */
|
||||
it->next = calloc(sizeof(arg_t), 1);
|
||||
it->next->prev = it;
|
||||
it = it->next;
|
||||
it->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return _list;
|
||||
}
|
||||
|
||||
int find_arg_simple ( arg_t* _head, const char* _id )
|
||||
{
|
||||
arg_t* it = _head;
|
||||
|
||||
int i;
|
||||
for ( i = 1; it != NULL; it = it->next ) {
|
||||
if ( strcmp ( _id, it->value ) == 0 ) {
|
||||
return i;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
const char* find_arg_duble ( arg_t* _head, const char* _id )
|
||||
{
|
||||
arg_t* _it;
|
||||
for ( _it = _head; _it != NULL; _it = _it->next ) {
|
||||
if ( strcmp ( _id, _it->value ) == 0 ) {
|
||||
if ( _it->next && _it->next->value[0] != '-' ) { /* exclude option */
|
||||
return _it->next->value;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/* test_helper.h
|
||||
*
|
||||
* Tests support. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TEST__HELPER_
|
||||
#define _TEST__HELPER_
|
||||
|
||||
#include "../toxrtp_helper.h"
|
||||
|
||||
#define RTP_PORT 31003
|
||||
#define RTP_PORT_LISTEN 31001
|
||||
|
||||
#define _SLEEP_INTERVAL 1000
|
||||
|
||||
typedef struct arg_s {
|
||||
const char* value;
|
||||
struct arg_s* next;
|
||||
struct arg_s* prev;
|
||||
|
||||
} arg_t;
|
||||
|
||||
|
||||
|
||||
/* Parses arguments into d-list arg_t */
|
||||
arg_t* parse_args ( int argc, char* argv[] );
|
||||
|
||||
/* Get a single argument ( i.e. ./test -s |find if has 's' >> | find_arg_simple(_t, "-s") )
|
||||
* A little error checking, of course, returns FAILURE if not found and if found returns position
|
||||
* where it's found.
|
||||
*/
|
||||
int find_arg_simple ( arg_t* _head, const char* _id );
|
||||
|
||||
/* Get a single argument ( i.e. ./test -d 127.0.0.1 |get 'd' value >> | find_arg_duble(_t, "-d") )
|
||||
* A little error checking, of course, returns NULL if not found and if found returns value
|
||||
* of that argument ( i.e. '127.0.0.1').
|
||||
*/
|
||||
const char* find_arg_duble ( arg_t* _head, const char* _id );
|
||||
|
||||
#endif /* _TEST__HELPER_ */
|
||||
|
||||
|
693
toxrtp/toxrtp.c
693
toxrtp/toxrtp.c
|
@ -1,693 +0,0 @@
|
|||
/* rtp_impl.c
|
||||
*
|
||||
* Rtp implementation includes rtp_session_s struct which is a session identifier.
|
||||
* It contains session information and it's a must for every session.
|
||||
* It's best if you don't touch any variable directly but use callbacks to do so. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp.h"
|
||||
#include "toxrtp_message.h"
|
||||
#include "toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include "../toxcore/util.h"
|
||||
#include "../toxcore/network.h"
|
||||
|
||||
/* Some defines */
|
||||
#define PAYLOAD_ID_VALUE_OPUS 1
|
||||
#define PAYLOAD_ID_VALUE_VP8 2
|
||||
|
||||
#define size_32 4
|
||||
/* End of defines */
|
||||
|
||||
#ifdef _USE_ERRORS
|
||||
#include "toxrtp_error_id.h"
|
||||
#endif /* _USE_ERRORS */
|
||||
|
||||
static const uint32_t _payload_table[] = /* PAYLOAD TABLE */
|
||||
{
|
||||
8000, 8000, 8000, 8000, 8000, 8000, 16000, 8000, 8000, 8000, /* 0-9 */
|
||||
44100, 44100, 0, 0, 90000, 8000, 11025, 22050, 0, 0, /* 10-19 */
|
||||
0, 0, 0, 0, 0, 90000, 90000, 0, 90000, 0, /* 20-29 */
|
||||
0, 90000, 90000, 90000, 90000, 0, 0, 0, 0, 0, /* 30-39 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-49 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-59 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-69 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70-79 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-89 */
|
||||
0, 0, 0, 0, 0, 0, PAYLOAD_ID_VALUE_OPUS, 0, 0, 0, /* 90-99 */
|
||||
0, 0, 0, 0, 0, 0, PAYLOAD_ID_VALUE_VP8, 0, 0, 0, /* 100-109 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 110-119 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0 /* 120-127 */
|
||||
};
|
||||
|
||||
/* Current compatibility solution */
|
||||
int m_sendpacket(Networking_Core* _core_handler, void *ip_port, uint8_t *data, uint32_t length)
|
||||
{
|
||||
return sendpacket(_core_handler, *((IP_Port*) ip_port), data, length);
|
||||
}
|
||||
|
||||
rtp_session_t* rtp_init_session ( int max_users, int _multi_session )
|
||||
{
|
||||
#ifdef _USE_ERRORS
|
||||
REGISTER_RTP_ERRORS
|
||||
#endif /* _USE_ERRORS */
|
||||
|
||||
rtp_session_t* _retu = calloc(sizeof(rtp_session_t), 1);
|
||||
assert(_retu);
|
||||
|
||||
_retu->_dest_list = _retu->_last_user = NULL;
|
||||
|
||||
_retu->_max_users = max_users;
|
||||
_retu->_packets_recv = 0;
|
||||
_retu->_packets_sent = 0;
|
||||
_retu->_bytes_sent = 0;
|
||||
_retu->_bytes_recv = 0;
|
||||
_retu->_last_error = NULL;
|
||||
_retu->_packet_loss = 0;
|
||||
|
||||
/*
|
||||
* SET HEADER FIELDS
|
||||
*/
|
||||
|
||||
_retu->_version = RTP_VERSION; /* It's always 2 */
|
||||
_retu->_padding = 0; /* If some additional data is needed about
|
||||
* the packet */
|
||||
_retu->_extension = 0; /* If extension to header is needed */
|
||||
_retu->_cc = 1; /* It basically represents amount of contributors */
|
||||
_retu->_csrc = NULL; /* Container */
|
||||
_retu->_ssrc = t_random ( -1 );
|
||||
_retu->_marker = 0;
|
||||
_retu->_payload_type = 0; /* You should specify payload type */
|
||||
|
||||
/* Sequence starts at random number and goes to _MAX_SEQU_NUM */
|
||||
_retu->_sequence_number = t_random ( _MAX_SEQU_NUM );
|
||||
_retu->_last_sequence_number = _retu->_sequence_number; /* Do not touch this variable */
|
||||
|
||||
_retu->_initial_time = t_time(); /* In seconds */
|
||||
assert(_retu->_initial_time);
|
||||
_retu->_time_elapsed = 0; /* In seconds */
|
||||
|
||||
_retu->_ext_header = NULL; /* When needed allocate */
|
||||
_retu->_exthdr_framerate = -1;
|
||||
_retu->_exthdr_resolution = -1;
|
||||
|
||||
_retu->_csrc = calloc(sizeof(uint32_t), 1);
|
||||
assert(_retu->_csrc);
|
||||
|
||||
_retu->_csrc[0] = _retu->_ssrc; /* Set my ssrc to the list receive */
|
||||
|
||||
_retu->_prefix_length = 0;
|
||||
_retu->_prefix = NULL;
|
||||
|
||||
_retu->_multi_session = _multi_session;
|
||||
|
||||
/* Initial */
|
||||
_retu->_current_framerate = 0;
|
||||
|
||||
|
||||
_retu->_oldest_msg = _retu->_last_msg = NULL;
|
||||
|
||||
pthread_mutex_init(&_retu->_mutex, NULL);
|
||||
/*
|
||||
*
|
||||
*/
|
||||
return _retu;
|
||||
}
|
||||
|
||||
int rtp_terminate_session ( rtp_session_t* _session )
|
||||
{
|
||||
if ( !_session )
|
||||
return FAILURE;
|
||||
|
||||
if ( _session->_dest_list ){
|
||||
rtp_dest_list_t* _fordel = NULL;
|
||||
rtp_dest_list_t* _tmp = _session->_dest_list;
|
||||
|
||||
while( _tmp ){
|
||||
_fordel = _tmp;
|
||||
_tmp = _tmp->next;
|
||||
free(_fordel);
|
||||
}
|
||||
}
|
||||
|
||||
if ( _session->_ext_header )
|
||||
free ( _session->_ext_header );
|
||||
|
||||
if ( _session->_csrc )
|
||||
free ( _session->_csrc );
|
||||
|
||||
if ( _session->_prefix )
|
||||
free ( _session->_prefix );
|
||||
|
||||
pthread_mutex_destroy(&_session->_mutex);
|
||||
|
||||
/* And finally free session */
|
||||
free ( _session );
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint16_t rtp_get_resolution_marking_height ( rtp_ext_header_t* _header, uint32_t _position )
|
||||
{
|
||||
if ( _header->_ext_type & RTP_EXT_TYPE_RESOLUTION )
|
||||
return _header->_hd_ext[_position];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t rtp_get_resolution_marking_width ( rtp_ext_header_t* _header, uint32_t _position )
|
||||
{
|
||||
if ( _header->_ext_type & RTP_EXT_TYPE_RESOLUTION )
|
||||
return ( _header->_hd_ext[_position] >> 16 );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtp_free_msg ( rtp_session_t* _session, rtp_msg_t* _message )
|
||||
{
|
||||
free ( _message->_data );
|
||||
|
||||
if ( !_session ){
|
||||
free ( _message->_header->_csrc );
|
||||
if ( _message->_ext_header ){
|
||||
free ( _message->_ext_header->_hd_ext );
|
||||
free ( _message->_ext_header );
|
||||
}
|
||||
} else {
|
||||
if ( _session->_csrc != _message->_header->_csrc )
|
||||
free ( _message->_header->_csrc );
|
||||
if ( _message->_ext_header && _session->_ext_header != _message->_ext_header ) {
|
||||
free ( _message->_ext_header->_hd_ext );
|
||||
free ( _message->_ext_header );
|
||||
}
|
||||
}
|
||||
|
||||
free ( _message->_header );
|
||||
free ( _message );
|
||||
}
|
||||
|
||||
rtp_header_t* rtp_build_header ( rtp_session_t* _session )
|
||||
{
|
||||
rtp_header_t* _retu;
|
||||
_retu = calloc ( sizeof * _retu, 1 );
|
||||
assert(_retu);
|
||||
|
||||
rtp_header_add_flag_version ( _retu, _session->_version );
|
||||
rtp_header_add_flag_padding ( _retu, _session->_padding );
|
||||
rtp_header_add_flag_extension ( _retu, _session->_extension );
|
||||
rtp_header_add_flag_CSRC_count ( _retu, _session->_cc );
|
||||
rtp_header_add_setting_marker ( _retu, _session->_marker );
|
||||
rtp_header_add_setting_payload ( _retu, _session->_payload_type );
|
||||
|
||||
_retu->_sequence_number = _session->_sequence_number;
|
||||
_session->_time_elapsed = t_time() - _session->_initial_time;
|
||||
_retu->_timestamp = t_time();
|
||||
_retu->_ssrc = _session->_ssrc;
|
||||
|
||||
if ( _session->_cc > 0 ) {
|
||||
_retu->_csrc = calloc(sizeof(uint32_t), _session->_cc);
|
||||
assert(_retu->_csrc);
|
||||
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < _session->_cc; i++ ) {
|
||||
_retu->_csrc[i] = _session->_csrc[i];
|
||||
}
|
||||
} else {
|
||||
_retu->_csrc = NULL;
|
||||
}
|
||||
|
||||
_retu->_length = _MIN_HEADER_LENGTH + ( _session->_cc * size_32 );
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
void rtp_set_payload_type ( rtp_session_t* _session, uint8_t _payload_value )
|
||||
{
|
||||
_session->_payload_type = _payload_value;
|
||||
}
|
||||
uint32_t rtp_get_payload_type ( rtp_session_t* _session )
|
||||
{
|
||||
return _payload_table[_session->_payload_type];
|
||||
}
|
||||
|
||||
int rtp_add_receiver ( rtp_session_t* _session, tox_IP_Port* _dest )
|
||||
{
|
||||
if ( !_session )
|
||||
return FAILURE;
|
||||
|
||||
rtp_dest_list_t* _new_user = calloc(sizeof(rtp_dest_list_t), 1);
|
||||
assert(_new_user);
|
||||
|
||||
_new_user->next = NULL;
|
||||
_new_user->_dest = *_dest;
|
||||
|
||||
if ( _session->_last_user == NULL ) { /* New member */
|
||||
_session->_dest_list = _session->_last_user = _new_user;
|
||||
|
||||
} else { /* Append */
|
||||
_session->_last_user->next = _new_user;
|
||||
_session->_last_user = _new_user;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int rtp_send_msg ( rtp_session_t* _session, rtp_msg_t* _msg, void* _core_handler )
|
||||
{
|
||||
if ( !_msg || _msg->_data == NULL || _msg->_length <= 0 ) {
|
||||
t_perror ( RTP_ERROR_EMPTY_MESSAGE );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int _last;
|
||||
unsigned long long _total = 0;
|
||||
|
||||
size_t _length = _msg->_length;
|
||||
uint8_t _send_data [ MAX_UDP_PACKET_SIZE ];
|
||||
|
||||
uint16_t _prefix_length = _session->_prefix_length;
|
||||
|
||||
_send_data[0] = 70;
|
||||
|
||||
if ( _session->_prefix && _length + _prefix_length < MAX_UDP_PACKET_SIZE ) {
|
||||
/*t_memcpy(_send_data, _session->_prefix, _prefix_length);*/
|
||||
t_memcpy ( _send_data + 1, _msg->_data, _length );
|
||||
} else {
|
||||
t_memcpy ( _send_data + 1, _msg->_data, _length );
|
||||
}
|
||||
|
||||
/* Set sequ number */
|
||||
if ( _session->_sequence_number >= _MAX_SEQU_NUM ) {
|
||||
_session->_sequence_number = 0;
|
||||
} else {
|
||||
_session->_sequence_number++;
|
||||
}
|
||||
|
||||
/* Start sending loop */
|
||||
rtp_dest_list_t* _it;
|
||||
for ( _it = _session->_dest_list; _it != NULL; _it = _it->next ) {
|
||||
|
||||
_last = m_sendpacket ( _core_handler, &_it->_dest, _send_data, _length + 1);
|
||||
|
||||
if ( _last < 0 ) {
|
||||
t_perror ( RTP_ERROR_STD_SEND_FAILURE );
|
||||
printf("Stderror: %s", strerror(errno));
|
||||
} else {
|
||||
_session->_packets_sent ++;
|
||||
_total += _last;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rtp_free_msg ( _session, _msg );
|
||||
_session->_bytes_sent += _total;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
rtp_msg_t* rtp_recv_msg ( rtp_session_t* _session )
|
||||
{
|
||||
if ( !_session )
|
||||
return NULL;
|
||||
|
||||
rtp_msg_t* _retu = _session->_oldest_msg;
|
||||
|
||||
pthread_mutex_lock(&_session->_mutex);
|
||||
|
||||
if ( _retu )
|
||||
_session->_oldest_msg = _retu->_next;
|
||||
|
||||
if ( !_session->_oldest_msg )
|
||||
_session->_last_msg = NULL;
|
||||
|
||||
pthread_mutex_unlock(&_session->_mutex);
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
void rtp_store_msg ( rtp_session_t* _session, rtp_msg_t* _msg )
|
||||
{
|
||||
if ( rtp_check_late_message(_session, _msg) < 0 ) {
|
||||
rtp_register_msg(_session, _msg);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_session->_mutex);
|
||||
|
||||
if ( _session->_last_msg ) {
|
||||
_session->_last_msg->_next = _msg;
|
||||
_session->_last_msg = _msg;
|
||||
} else {
|
||||
_session->_last_msg = _session->_oldest_msg = _msg;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_session->_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
int rtp_release_session_recv ( rtp_session_t* _session )
|
||||
{
|
||||
if ( !_session ){
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
rtp_msg_t* _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;
|
||||
|
||||
pthread_mutex_unlock(&_session->_mutex);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
rtp_msg_t* rtp_msg_new ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length )
|
||||
{
|
||||
if ( !_session )
|
||||
return NULL;
|
||||
|
||||
uint8_t* _from_pos;
|
||||
rtp_msg_t* _retu = calloc(sizeof(rtp_msg_t), 1);
|
||||
assert(_retu);
|
||||
|
||||
/* Sets header values and copies the extension header in _retu */
|
||||
_retu->_header = rtp_build_header ( _session ); /* It allocates memory and all */
|
||||
_retu->_ext_header = _session->_ext_header;
|
||||
|
||||
uint32_t _total_lenght = _length + _retu->_header->_length;
|
||||
|
||||
if ( _retu->_ext_header ) {
|
||||
|
||||
_total_lenght += ( _MIN_EXT_HEADER_LENGTH + _retu->_ext_header->_ext_len * size_32 );
|
||||
/* Allocate Memory for _retu->_data */
|
||||
_retu->_data = calloc ( sizeof _retu->_data, _total_lenght );
|
||||
assert(_retu->_data);
|
||||
|
||||
_from_pos = rtp_add_header ( _retu->_header, _retu->_data );
|
||||
_from_pos = rtp_add_extention_header ( _retu->_ext_header, _from_pos + 1 );
|
||||
} else {
|
||||
/* Allocate Memory for _retu->_data */
|
||||
_retu->_data = calloc ( sizeof _retu->_data, _total_lenght );
|
||||
assert(_retu->_data);
|
||||
|
||||
_from_pos = rtp_add_header ( _retu->_header, _retu->_data );
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the extension header into the message
|
||||
* Of course if any
|
||||
*/
|
||||
|
||||
/* Appends _data on to _retu->_data */
|
||||
t_memcpy ( _from_pos + 1, _data, _length );
|
||||
|
||||
_retu->_length = _total_lenght;
|
||||
|
||||
_retu->_next = NULL;
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
rtp_msg_t* rtp_msg_parse ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length )
|
||||
{
|
||||
rtp_msg_t* _retu = calloc(sizeof(rtp_msg_t), 1);
|
||||
assert(_retu);
|
||||
|
||||
_retu->_header = rtp_extract_header ( _data, _length ); /* It allocates memory and all */
|
||||
if ( !_retu->_header ){
|
||||
free(_retu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->_length = _length - _retu->_header->_length;
|
||||
|
||||
uint16_t _from_pos = _retu->_header->_length;
|
||||
|
||||
|
||||
if ( rtp_header_get_flag_extension ( _retu->_header ) ) {
|
||||
_retu->_ext_header = rtp_extract_ext_header ( _data + _from_pos, _length );
|
||||
if ( _retu->_ext_header ){
|
||||
_retu->_length -= ( _MIN_EXT_HEADER_LENGTH + _retu->_ext_header->_ext_len * size_32 );
|
||||
_from_pos += ( _MIN_EXT_HEADER_LENGTH + _retu->_ext_header->_ext_len * size_32 );
|
||||
} else {
|
||||
free (_retu->_ext_header);
|
||||
free (_retu->_header);
|
||||
free (_retu);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
_retu->_ext_header = NULL;
|
||||
}
|
||||
|
||||
/* Get the payload */
|
||||
_retu->_data = calloc ( sizeof ( uint8_t ), _retu->_length );
|
||||
assert(_retu->_data);
|
||||
|
||||
t_memcpy ( _retu->_data, _data + _from_pos, _length - _from_pos );
|
||||
|
||||
_retu->_next = NULL;
|
||||
|
||||
|
||||
if ( _session && !_session->_multi_session && rtp_check_late_message(_session, _retu) < 0 ){
|
||||
rtp_register_msg(_session, _retu);
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
int rtp_check_late_message (rtp_session_t* _session, rtp_msg_t* _msg)
|
||||
{
|
||||
/*
|
||||
* Check Sequence number. If this new msg has lesser number then the _session->_last_sequence_number
|
||||
* it shows that the message came in late
|
||||
*/
|
||||
if ( _msg->_header->_sequence_number < _session->_last_sequence_number &&
|
||||
_msg->_header->_timestamp < _session->_current_timestamp
|
||||
) {
|
||||
return SUCCESS; /* Drop the packet. You can check if the packet dropped by checking _packet_loss increment. */
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
void rtp_register_msg ( rtp_session_t* _session, rtp_msg_t* _msg )
|
||||
{
|
||||
_session->_last_sequence_number = _msg->_header->_sequence_number;
|
||||
_session->_current_timestamp = _msg->_header->_timestamp;
|
||||
}
|
||||
|
||||
|
||||
int rtp_add_resolution_marking ( rtp_session_t* _session, uint16_t _width, uint16_t _height )
|
||||
{
|
||||
if ( !_session )
|
||||
return FAILURE;
|
||||
|
||||
rtp_ext_header_t* _ext_header = _session->_ext_header;
|
||||
_session->_exthdr_resolution = 0;
|
||||
|
||||
if ( ! ( _ext_header ) ) {
|
||||
_session->_ext_header = calloc (sizeof(rtp_ext_header_t), 1);
|
||||
assert(_session->_ext_header);
|
||||
|
||||
_session->_extension = 1;
|
||||
_session->_ext_header->_ext_len = 1;
|
||||
_ext_header = _session->_ext_header;
|
||||
_session->_ext_header->_hd_ext = calloc(sizeof(uint32_t), 1);
|
||||
assert(_session->_ext_header->_hd_ext);
|
||||
|
||||
} else { /* If there is need for more headers this will be needed to change */
|
||||
if ( !(_ext_header->_ext_type & RTP_EXT_TYPE_RESOLUTION) ){
|
||||
uint32_t _exthdr_framerate = _ext_header->_hd_ext[_session->_exthdr_framerate];
|
||||
/* it's position is at 2nd place by default */
|
||||
_session->_exthdr_framerate ++;
|
||||
|
||||
/* Update length */
|
||||
_ext_header->_ext_len++;
|
||||
|
||||
/* Allocate the value */
|
||||
_ext_header->_hd_ext = realloc(_ext_header->_hd_ext, sizeof(rtp_ext_header_t) * _ext_header->_ext_len);
|
||||
assert(_ext_header->_hd_ext);
|
||||
|
||||
/* Reset other values */
|
||||
_ext_header->_hd_ext[_session->_exthdr_framerate] = _exthdr_framerate;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add flag */
|
||||
_ext_header->_ext_type |= RTP_EXT_TYPE_RESOLUTION;
|
||||
|
||||
_ext_header->_hd_ext[_session->_exthdr_resolution] = _width << 16 | ( uint32_t ) _height;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int rtp_remove_resolution_marking ( rtp_session_t* _session )
|
||||
{
|
||||
if ( _session->_extension == 0 || ! ( _session->_ext_header ) ) {
|
||||
t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if ( !( _session->_ext_header->_ext_type & RTP_EXT_TYPE_RESOLUTION ) ) {
|
||||
t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
_session->_ext_header->_ext_type &= ~RTP_EXT_TYPE_RESOLUTION; /* Remove the flag */
|
||||
_session->_exthdr_resolution = -1; /* Remove identifier */
|
||||
|
||||
/* Check if extension is empty */
|
||||
if ( _session->_ext_header->_ext_type == 0 ){
|
||||
|
||||
free ( _session->_ext_header->_hd_ext );
|
||||
free ( _session->_ext_header );
|
||||
|
||||
_session->_ext_header = NULL; /* It's very important */
|
||||
_session->_extension = 0;
|
||||
|
||||
} else {
|
||||
_session->_ext_header->_ext_len --;
|
||||
|
||||
/* this will also be needed to change if there are more than 2 headers */
|
||||
if ( _session->_ext_header->_ext_type & RTP_EXT_TYPE_FRAMERATE ){
|
||||
memcpy(_session->_ext_header->_hd_ext + 1, _session->_ext_header->_hd_ext, _session->_ext_header->_ext_len);
|
||||
_session->_exthdr_framerate = 0;
|
||||
_session->_ext_header->_hd_ext = realloc( _session->_ext_header->_hd_ext, sizeof( rtp_ext_header_t ) * _session->_ext_header->_ext_len );
|
||||
assert(_session->_ext_header->_hd_ext);
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int rtp_add_framerate_marking ( rtp_session_t* _session, uint32_t _value )
|
||||
{
|
||||
if ( !_session )
|
||||
return FAILURE;
|
||||
|
||||
rtp_ext_header_t* _ext_header = _session->_ext_header;
|
||||
_session->_exthdr_framerate = 0;
|
||||
|
||||
if ( ! ( _ext_header ) ) {
|
||||
_session->_ext_header = calloc (sizeof(rtp_ext_header_t), 1);
|
||||
assert(_session->_ext_header);
|
||||
|
||||
_session->_extension = 1;
|
||||
_session->_ext_header->_ext_len = 1;
|
||||
_ext_header = _session->_ext_header;
|
||||
_session->_ext_header->_hd_ext = calloc(sizeof(uint32_t), 1);
|
||||
assert(_session->_ext_header->_hd_ext);
|
||||
} else { /* If there is need for more headers this will be needed to change */
|
||||
if ( !(_ext_header->_ext_type & RTP_EXT_TYPE_FRAMERATE) ){
|
||||
/* it's position is at 2nd place by default */
|
||||
_session->_exthdr_framerate ++;
|
||||
|
||||
/* Update length */
|
||||
_ext_header->_ext_len++;
|
||||
|
||||
/* Allocate the value */
|
||||
_ext_header->_hd_ext = realloc(_ext_header->_hd_ext, sizeof(rtp_ext_header_t) * _ext_header->_ext_len);
|
||||
assert(_ext_header->_hd_ext);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Add flag */
|
||||
_ext_header->_ext_type |= RTP_EXT_TYPE_FRAMERATE;
|
||||
|
||||
_ext_header->_hd_ext[_session->_exthdr_framerate] = _value;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int rtp_remove_framerate_marking ( rtp_session_t* _session )
|
||||
{
|
||||
if ( _session->_extension == 0 || ! ( _session->_ext_header ) ) {
|
||||
t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if ( !( _session->_ext_header->_ext_type & RTP_EXT_TYPE_FRAMERATE ) ) {
|
||||
t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
_session->_ext_header->_ext_type &= ~RTP_EXT_TYPE_FRAMERATE; /* Remove the flag */
|
||||
_session->_exthdr_framerate = -1; /* Remove identifier */
|
||||
_session->_ext_header->_ext_len --;
|
||||
|
||||
/* Check if extension is empty */
|
||||
if ( _session->_ext_header->_ext_type == 0 ){
|
||||
|
||||
free ( _session->_ext_header->_hd_ext );
|
||||
free ( _session->_ext_header );
|
||||
|
||||
_session->_ext_header = NULL; /* It's very important */
|
||||
_session->_extension = 0;
|
||||
|
||||
} else if ( !_session->_ext_header->_ext_len ) {
|
||||
|
||||
/* this will also be needed to change if there are more than 2 headers */
|
||||
_session->_ext_header->_hd_ext = realloc( _session->_ext_header->_hd_ext, sizeof( rtp_ext_header_t ) * _session->_ext_header->_ext_len );
|
||||
assert(_session->_ext_header->_hd_ext);
|
||||
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t rtp_get_framerate_marking ( rtp_ext_header_t* _header )
|
||||
{
|
||||
if ( _header->_ext_len == 1 ){
|
||||
return _header->_hd_ext[0];
|
||||
} else {
|
||||
return _header->_hd_ext[1];
|
||||
}
|
||||
}
|
||||
|
||||
int rtp_set_prefix ( rtp_session_t* _session, uint8_t* _prefix, uint16_t _prefix_length )
|
||||
{
|
||||
if ( !_session )
|
||||
return FAILURE;
|
||||
|
||||
if ( _session->_prefix ) {
|
||||
free ( _session->_prefix );
|
||||
}
|
||||
|
||||
_session->_prefix = calloc ( ( sizeof * _session->_prefix ), _prefix_length );
|
||||
assert(_session->_prefix);
|
||||
|
||||
t_memcpy ( _session->_prefix, _prefix, _prefix_length );
|
||||
_session->_prefix_length = _prefix_length;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
188
toxrtp/toxrtp.h
188
toxrtp/toxrtp.h
|
@ -1,188 +0,0 @@
|
|||
/* rtp_impl.h
|
||||
*
|
||||
* Rtp implementation includes rtp_session_s struct which is a session identifier.
|
||||
* It contains session information and it's a must for every session.
|
||||
* It's best if you don't touch any variable directly but use callbacks to do so. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RTP__IMPL_H_
|
||||
#define _RTP__IMPL_H_
|
||||
|
||||
#define RTP_VERSION 2
|
||||
#include <inttypes.h>
|
||||
#include "tox.h"
|
||||
#include <pthread.h>
|
||||
/* Extension header flags */
|
||||
#define RTP_EXT_TYPE_RESOLUTION 0x01
|
||||
#define RTP_EXT_TYPE_FRAMERATE 0x02
|
||||
|
||||
/* Some defines */
|
||||
|
||||
#define RTP_PACKET 70
|
||||
|
||||
/* Payload identifiers */
|
||||
|
||||
/* Audio */
|
||||
#define _PAYLOAD_OPUS 96
|
||||
|
||||
/* Video */
|
||||
#define _PAYLOAD_VP8 106
|
||||
|
||||
/* End of Payload identifiers */
|
||||
|
||||
/* End of defines */
|
||||
|
||||
|
||||
/* Our main session descriptor.
|
||||
* It measures the session variables and controls
|
||||
* the entire session. There are functions for manipulating
|
||||
* the session so tend to use those instead of directly accessing
|
||||
* session parameters.
|
||||
*/
|
||||
typedef struct rtp_session_s {
|
||||
uint8_t _version;
|
||||
uint8_t _padding;
|
||||
uint8_t _extension;
|
||||
uint8_t _cc;
|
||||
uint8_t _marker;
|
||||
uint8_t _payload_type;
|
||||
uint16_t _sequence_number; /* Set when sending */
|
||||
uint16_t _last_sequence_number; /* Check when recving msg */
|
||||
uint32_t _initial_time;
|
||||
uint32_t _time_elapsed;
|
||||
uint32_t _current_timestamp;
|
||||
uint32_t _ssrc;
|
||||
uint32_t *_csrc;
|
||||
|
||||
|
||||
/* If some additional data must be sent via message
|
||||
* apply it here. Only by allocating this member you will be
|
||||
* automatically placing it within a message.
|
||||
*/
|
||||
|
||||
struct rtp_ext_header_s *_ext_header;
|
||||
/* External header identifiers */
|
||||
int _exthdr_resolution;
|
||||
int _exthdr_framerate;
|
||||
|
||||
int _max_users; /* -1 undefined */
|
||||
|
||||
uint64_t _packets_sent; /* measure packets */
|
||||
uint64_t _packets_recv;
|
||||
|
||||
uint64_t _bytes_sent;
|
||||
uint64_t _bytes_recv;
|
||||
|
||||
uint64_t _packet_loss;
|
||||
|
||||
const char *_last_error;
|
||||
|
||||
struct rtp_dest_list_s *_dest_list;
|
||||
struct rtp_dest_list_s *_last_user; /* a tail for faster appending */
|
||||
|
||||
struct rtp_msg_s *_oldest_msg;
|
||||
struct rtp_msg_s *_last_msg; /* tail */
|
||||
|
||||
uint16_t _prefix_length;
|
||||
uint8_t *_prefix;
|
||||
|
||||
/* Specifies multiple session use.
|
||||
* When using one session it uses default value ( -1 )
|
||||
* Otherwise it's set to 1 and rtp_register_msg () is required
|
||||
*/
|
||||
int _multi_session;
|
||||
|
||||
uint32_t _current_framerate;
|
||||
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
} rtp_session_t;
|
||||
|
||||
|
||||
/*
|
||||
* Now i don't believe we need to store this _from thing every time
|
||||
* since we have csrc table but will leave it like this for a while
|
||||
*/
|
||||
|
||||
|
||||
void rtp_free_msg ( rtp_session_t *_session, struct rtp_msg_s *_msg );
|
||||
int rtp_release_session_recv ( rtp_session_t *_session );
|
||||
|
||||
/* Functions handling receiving */
|
||||
struct rtp_msg_s *rtp_recv_msg ( rtp_session_t *_session );
|
||||
void rtp_store_msg ( rtp_session_t *_session, struct rtp_msg_s *_msg );
|
||||
|
||||
/*
|
||||
* rtp_msg_parse() stores headers separately from the payload data
|
||||
* and so the _length variable is set accordingly
|
||||
*/
|
||||
struct rtp_msg_s *rtp_msg_parse ( rtp_session_t *_session, const uint8_t *_data, uint32_t _length );
|
||||
|
||||
int rtp_check_late_message (rtp_session_t *_session, struct rtp_msg_s *_msg);
|
||||
void rtp_register_msg ( rtp_session_t *_session, struct rtp_msg_s * );
|
||||
|
||||
/* Functions handling sending */
|
||||
int rtp_send_msg ( rtp_session_t *_session, struct rtp_msg_s *_msg, void *_core_handler );
|
||||
|
||||
/*
|
||||
* rtp_msg_new() stores headers and payload data in one container ( _data )
|
||||
* and the _length is set accordingly. Returned message is used for sending only
|
||||
* so there is not much use of the headers there
|
||||
*/
|
||||
struct rtp_msg_s *rtp_msg_new ( rtp_session_t *_session, const uint8_t *_data, uint32_t _length );
|
||||
|
||||
|
||||
/* Convenient functions for creating a header */
|
||||
struct rtp_header_s *rtp_build_header ( rtp_session_t *_session );
|
||||
|
||||
/* Functions handling session control */
|
||||
|
||||
/* Handling an rtp packet */
|
||||
/* int rtp_handlepacket(uint8_t * packet, uint32_t length, IP_Port source); */
|
||||
|
||||
/* Session initiation and termination.
|
||||
* Set _multi_session to -1 if not using multiple sessions
|
||||
*/
|
||||
rtp_session_t *rtp_init_session ( int _max_users, int _multi_session );
|
||||
int rtp_terminate_session ( rtp_session_t *_session );
|
||||
|
||||
/* Adding receiver */
|
||||
int rtp_add_receiver ( rtp_session_t *_session, tox_IP_Port *_dest );
|
||||
|
||||
/* Convenient functions for marking the resolution */
|
||||
int rtp_add_resolution_marking ( rtp_session_t *_session, uint16_t _width, uint16_t _height );
|
||||
int rtp_remove_resolution_marking ( rtp_session_t *_session );
|
||||
uint16_t rtp_get_resolution_marking_height ( struct rtp_ext_header_s *_header, uint32_t _position );
|
||||
uint16_t rtp_get_resolution_marking_width ( struct rtp_ext_header_s *_header, uint32_t _position );
|
||||
|
||||
int rtp_add_framerate_marking ( rtp_session_t *_session, uint32_t _value );
|
||||
int rtp_remove_framerate_marking ( rtp_session_t *_session );
|
||||
uint32_t rtp_get_framerate_marking ( struct rtp_ext_header_s *_header );
|
||||
/* Convenient functions for marking the payload */
|
||||
void rtp_set_payload_type ( rtp_session_t *_session, uint8_t _payload_value );
|
||||
uint32_t rtp_get_payload_type ( rtp_session_t *_session );
|
||||
|
||||
/* When using RTP in core be sure to set prefix when sending via rtp_send_msg */
|
||||
int rtp_set_prefix ( rtp_session_t *_session, uint8_t *_prefix, uint16_t _prefix_length );
|
||||
|
||||
#endif /* _RTP__IMPL_H_ */
|
|
@ -1,68 +0,0 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp_error.h"
|
||||
#include "toxrtp_helper.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct rtp_error_s {
|
||||
char* _message;
|
||||
int _id;
|
||||
|
||||
} rtp_error_t;
|
||||
|
||||
static rtp_error_t* _register = NULL;
|
||||
static size_t _it = 0;
|
||||
|
||||
void t_rtperr_register ( int _id, const char* _info )
|
||||
{
|
||||
size_t _info_size = strlen ( _info );
|
||||
|
||||
if ( !_register ) {
|
||||
_register = calloc ( sizeof ( rtp_error_t ), 1 );
|
||||
} else {
|
||||
_register = realloc ( _register, sizeof ( rtp_error_t ) * ( _it + 1 ) );
|
||||
}
|
||||
assert(_register);
|
||||
|
||||
|
||||
rtp_error_t* _current = & _register[_it];
|
||||
|
||||
_current->_id = _id;
|
||||
_current->_message = calloc ( sizeof(char), _info_size );
|
||||
assert(_current->_message);
|
||||
|
||||
t_memcpy ( (uint8_t*)_current->_message, (const uint8_t*)_info, _info_size );
|
||||
_it ++;
|
||||
}
|
||||
|
||||
const char* t_rtperr ( int _errno )
|
||||
{
|
||||
if ( !_register )
|
||||
return "Unregistered";
|
||||
|
||||
uint32_t _i;
|
||||
|
||||
for ( _i = _it; _i--; ) {
|
||||
if ( _register[_i]._id == _errno ) {
|
||||
return _register[_i]._message;
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid error id!";
|
||||
}
|
||||
|
||||
void t_rtperr_print ( const char* _val, ... )
|
||||
{
|
||||
va_list _args;
|
||||
va_start ( _args, _val );
|
||||
vfprintf ( stderr, _val, _args );
|
||||
va_end ( _args );
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef _RTP_ERROR_
|
||||
#define _RTP_ERROR_
|
||||
|
||||
#define PRINT_FORMAT "Error %d: %s at %s:%d\n"
|
||||
#define PRINT_ARGS( _errno ) _errno, t_rtperr(_errno), __FILE__, __LINE__
|
||||
|
||||
|
||||
const char* t_rtperr ( int _errno );
|
||||
void t_rtperr_register ( int _id, const char* _info );
|
||||
|
||||
void t_invoke_error ( int _id );
|
||||
void t_rtperr_print ( const char* _val, ... );
|
||||
|
||||
|
||||
#ifdef _USE_ERRORS
|
||||
#define t_perror( _errno ) t_rtperr_print ( PRINT_FORMAT, PRINT_ARGS ( _errno ) )
|
||||
#else
|
||||
#define t_perror( _errno )do { } while(0)
|
||||
#endif /* _USE_ERRORS */
|
||||
|
||||
#ifdef _STDIO_H
|
||||
#define t_errexit( _errno ) exit(-_errno)
|
||||
#endif /* _STDIO_H */
|
||||
|
||||
#endif /* _RTP_ERROR_ */
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef _RTP_ERROR_ID_
|
||||
#define _RTP_ERROR_ID_
|
||||
|
||||
#include "toxrtp_error.h"
|
||||
|
||||
typedef enum error_s {
|
||||
RTP_ERROR_PACKET_DROPED = 1,
|
||||
RTP_ERROR_EMPTY_MESSAGE,
|
||||
RTP_ERROR_STD_SEND_FAILURE,
|
||||
RTP_ERROR_NO_EXTERNAL_HEADER,
|
||||
RTP_ERROR_INVALID_EXTERNAL_HEADER,
|
||||
RTP_ERROR_HEADER_PARSING,
|
||||
RTP_ERROR_PAYLOAD_NULL,
|
||||
RTP_ERROR_PAYLOAD_INVALID,
|
||||
|
||||
} error_t;
|
||||
|
||||
|
||||
/* Only needed to be called once */
|
||||
#ifndef REGISTER_RTP_ERRORS
|
||||
#define REGISTER_RTP_ERRORS \
|
||||
t_rtperr_register( RTP_ERROR_PACKET_DROPED, "Ivalid sequence number, packet is late" ); \
|
||||
t_rtperr_register( RTP_ERROR_EMPTY_MESSAGE, "Tried to send an empty message" ); \
|
||||
t_rtperr_register( RTP_ERROR_STD_SEND_FAILURE, "Failed call function: sendto" ); \
|
||||
t_rtperr_register( RTP_ERROR_NO_EXTERNAL_HEADER, "While parsing external header" ); \
|
||||
t_rtperr_register( RTP_ERROR_INVALID_EXTERNAL_HEADER, "While parsing external header" ); \
|
||||
t_rtperr_register( RTP_ERROR_HEADER_PARSING, "While parsing header" ); \
|
||||
t_rtperr_register( RTP_ERROR_PAYLOAD_NULL, "Payload is NULL" ); \
|
||||
t_rtperr_register( RTP_ERROR_PAYLOAD_INVALID, "Invalid payload size" );
|
||||
#endif /* REGISTER_RTP_ERRORS */
|
||||
|
||||
#endif /* _RTP_ERROR_ID_ */
|
|
@ -1,208 +0,0 @@
|
|||
/* rtp_helper.c
|
||||
*
|
||||
* Has some standard functions. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp_helper.h"
|
||||
#include "../toxcore/network.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WIN
|
||||
#include <windows.h>
|
||||
#endif /* WIN */
|
||||
|
||||
|
||||
static int _seed = 0; /* Not initiated */
|
||||
|
||||
int t_setipport ( const char *_ip, unsigned short _port, void *_dest )
|
||||
{
|
||||
assert(_dest);
|
||||
|
||||
IP_Port *_dest_c = ( IP_Port * ) _dest;
|
||||
ip_init(&_dest_c->ip, 0);
|
||||
|
||||
IP_Port _ipv6_garbage;
|
||||
|
||||
if ( !addr_resolve(_ip, &_dest_c->ip, &_ipv6_garbage.ip) )
|
||||
return FAILURE;
|
||||
|
||||
_dest_c->port = htons ( _port );
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t t_random ( uint32_t _max )
|
||||
{
|
||||
if ( !_seed ) {
|
||||
srand ( t_time() );
|
||||
_seed++;
|
||||
}
|
||||
|
||||
if ( _max <= 0 ) {
|
||||
return ( unsigned ) rand();
|
||||
} else {
|
||||
return ( unsigned ) rand() % _max;
|
||||
}
|
||||
}
|
||||
|
||||
void t_memcpy ( uint8_t *_dest, const uint8_t *_source, size_t _size )
|
||||
{
|
||||
/*
|
||||
* Using countdown to zero method
|
||||
* It's faster than for(_it = 0; _it < _size; _it++);
|
||||
*/
|
||||
size_t _it = _size;
|
||||
|
||||
do {
|
||||
_it--;
|
||||
_dest[_it] = _source[_it];
|
||||
} while ( _it );
|
||||
|
||||
}
|
||||
|
||||
uint8_t *t_memset ( uint8_t *_dest, uint8_t _valu, size_t _size )
|
||||
{
|
||||
/*
|
||||
* Again using countdown to zero method
|
||||
*/
|
||||
size_t _it = _size;
|
||||
|
||||
do {
|
||||
_it--;
|
||||
_dest[_it] = _valu;
|
||||
} while ( _it );
|
||||
|
||||
return _dest;
|
||||
}
|
||||
|
||||
size_t t_memlen ( const uint8_t *_valu)
|
||||
{
|
||||
const uint8_t *_it;
|
||||
size_t _retu = 0;
|
||||
|
||||
for ( _it = _valu; *_it; ++_it ) ++_retu;
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
uint8_t *t_strallcpy ( const uint8_t *_source ) /* string alloc and copy */
|
||||
{
|
||||
assert(_source);
|
||||
|
||||
size_t _length = t_memlen(_source) + 1; /* make space for null character */
|
||||
|
||||
uint8_t *_dest = calloc( sizeof ( uint8_t ), _length );
|
||||
assert(_dest);
|
||||
|
||||
t_memcpy(_dest, _source, _length);
|
||||
|
||||
return _dest;
|
||||
}
|
||||
|
||||
size_t t_strfind ( const uint8_t *_str, const uint8_t *_substr )
|
||||
{
|
||||
size_t _pos = 0;
|
||||
size_t _it, _delit = 0;
|
||||
|
||||
for ( _it = 0; _str[_it] != '\0'; _it++ ) {
|
||||
if ( _str[_it] == _substr[_delit] ) {
|
||||
_pos = _it;
|
||||
|
||||
while ( _str[_it] == _substr[_delit] && _str[_it] != '\0' ) {
|
||||
_it ++;
|
||||
_delit++;
|
||||
|
||||
if ( _substr[_delit] == '\0' ) {
|
||||
return _pos;
|
||||
}
|
||||
}
|
||||
|
||||
_delit = 0;
|
||||
_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return _pos;
|
||||
}
|
||||
|
||||
#ifdef WIN
|
||||
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
||||
#else
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
||||
#endif
|
||||
|
||||
struct timezone {
|
||||
int tz_minuteswest; /* minutes W of Greenwich */
|
||||
int tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
FILETIME ft;
|
||||
unsigned __int64 tmpres = 0;
|
||||
static int tzflag;
|
||||
|
||||
if (NULL != tv) {
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
tmpres |= ft.dwHighDateTime;
|
||||
tmpres <<= 32;
|
||||
tmpres |= ft.dwLowDateTime;
|
||||
|
||||
/*converting file time to unix epoch*/
|
||||
tmpres -= DELTA_EPOCH_IN_MICROSECS;
|
||||
tmpres /= 10; /*convert into microseconds*/
|
||||
tv->tv_sec = (long)(tmpres / 1000000UL);
|
||||
tv->tv_usec = (long)(tmpres % 1000000UL);
|
||||
}
|
||||
|
||||
if (NULL != tz) {
|
||||
if (!tzflag) {
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WIN */
|
||||
|
||||
|
||||
uint64_t t_time()
|
||||
{
|
||||
struct timeval _tv;
|
||||
gettimeofday(&_tv, NULL);
|
||||
uint64_t _retu_usec = _tv.tv_sec % 1000000; /* get 6 digits an leave space for 3 more */
|
||||
_retu_usec = _retu_usec * 1000 + (_tv.tv_usec / 1000 );
|
||||
return _retu_usec;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/* rtp_helper.h
|
||||
*
|
||||
* Has some standard functions. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RTP__HELPER_H_
|
||||
#define _RTP__HELPER_H_
|
||||
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Current time, unix format */
|
||||
/*#define _time ((uint32_t)time(NULL))*/
|
||||
|
||||
#define SUCCESS 0
|
||||
#define FAILURE -1
|
||||
|
||||
#define _USE_ERRORS
|
||||
|
||||
#define RUN_IN_THREAD(_func, _thread_id, _arg_ptr) \
|
||||
if ( pthread_create ( &_thread_id, NULL, _func, _arg_ptr ) ) { \
|
||||
pthread_detach ( _thread_id ); \
|
||||
}
|
||||
|
||||
/* Core adaptation helper */
|
||||
int t_setipport ( const char* _ip, unsigned short _port, void* _cont );
|
||||
uint32_t t_random ( uint32_t _max );
|
||||
|
||||
/* It's a bit faster than the memcpy it self and more optimized for using
|
||||
* a uint8_t since memcpy has optimizations when copying "words" i.e. long type.
|
||||
* Otherwise it just copies char's while we need only uint8_t
|
||||
*/
|
||||
void t_memcpy ( uint8_t* _dest, const uint8_t* _source, size_t _size );
|
||||
|
||||
|
||||
/* This is our memset. It's also a bit faster than the memset for it
|
||||
* does not cast _dest to char* and uses faster loop algorithm.
|
||||
*/
|
||||
uint8_t* t_memset ( uint8_t* _dest, uint8_t _valu, size_t _size );
|
||||
|
||||
/* Get null terminated len */
|
||||
size_t t_memlen ( const uint8_t* _valu );
|
||||
|
||||
/* finds location of substring */
|
||||
size_t t_strfind ( const uint8_t* _str, const uint8_t* _substr );
|
||||
|
||||
/* string alloc and copy ( ! must be null terminated ) */
|
||||
uint8_t* t_strallcpy ( const uint8_t* _source );
|
||||
|
||||
/* Get current time in milliseconds */
|
||||
uint64_t t_time();
|
||||
|
||||
|
||||
#endif /* _RTP__HELPER_H_ */
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,351 +0,0 @@
|
|||
/* rtp_message.c
|
||||
*
|
||||
* Rtp Message handler. It handles message/header parsing.
|
||||
* Refer to RTP: A Transport Protocol for Real-Time Applications ( RFC 3550 ) for more info. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp_message.h"
|
||||
#include "toxrtp.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _USE_ERRORS
|
||||
#include "toxrtp_error_id.h"
|
||||
#endif /* _USE_ERRORS */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Some defines */
|
||||
|
||||
/* End of defines */
|
||||
|
||||
void rtp_header_print (const rtp_header_t* _header)
|
||||
{
|
||||
printf("Header: \n"
|
||||
"Version: %d\n"
|
||||
"Padding: %d\n"
|
||||
"Ext: %d\n"
|
||||
"CC: %d\n"
|
||||
"marker: %d\n"
|
||||
"payload typ:%d\n\n"
|
||||
"sequ num: %d\n"
|
||||
"Timestamp: %d\n"
|
||||
"SSrc: %d\n"
|
||||
"CSrc: %d\n"
|
||||
"Lenght: %d\n"
|
||||
,rtp_header_get_flag_version(_header)
|
||||
,rtp_header_get_flag_padding(_header)
|
||||
,rtp_header_get_flag_extension(_header)
|
||||
,rtp_header_get_flag_CSRC_count(_header)
|
||||
,rtp_header_get_setting_marker(_header)
|
||||
,rtp_header_get_setting_payload_type(_header)
|
||||
,_header->_sequence_number
|
||||
,_header->_timestamp
|
||||
,_header->_ssrc
|
||||
,_header->_csrc[0]
|
||||
,_header->_length
|
||||
);
|
||||
}
|
||||
|
||||
rtp_header_t* rtp_extract_header ( const uint8_t* _payload, size_t _bytes )
|
||||
{
|
||||
if ( !_payload ) {
|
||||
t_perror ( RTP_ERROR_PAYLOAD_NULL );
|
||||
return NULL;
|
||||
}
|
||||
const uint8_t* _it = _payload;
|
||||
|
||||
rtp_header_t* _retu = calloc(sizeof(rtp_header_t), 1);
|
||||
assert(_retu);
|
||||
|
||||
_retu->_flags = *_it; ++_it;
|
||||
|
||||
/* This indicates if the first 2 bytes are valid.
|
||||
* Now it my happen that this is out of order but
|
||||
* it cuts down chances of parsing some invalid value
|
||||
*/
|
||||
if ( rtp_header_get_flag_version(_retu) != RTP_VERSION ){
|
||||
printf("Invalid version: %d\n", rtp_header_get_flag_version(_retu));
|
||||
//assert(rtp_header_get_flag_version(_retu) == RTP_VERSION);
|
||||
/* Deallocate */
|
||||
//DEALLOCATOR(_retu);
|
||||
//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 = rtp_header_get_flag_CSRC_count ( _retu );
|
||||
uint32_t _lenght = _MIN_HEADER_LENGTH + ( cc * 4 );
|
||||
|
||||
if ( _bytes < _lenght ) {
|
||||
t_perror ( RTP_ERROR_PAYLOAD_INVALID );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( cc > 0 ) {
|
||||
_retu->_csrc = calloc ( sizeof ( uint32_t ), cc );
|
||||
assert(_retu->_csrc);
|
||||
|
||||
} else { /* But this should not happen ever */
|
||||
t_perror ( RTP_ERROR_HEADER_PARSING );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
_retu->_marker_payload_t = *_it; ++_it;
|
||||
_retu->_length = _lenght;
|
||||
_retu->_sequence_number = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 );
|
||||
|
||||
_it += 2;
|
||||
|
||||
_retu->_timestamp = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( * ( _it + 3 ) ) ;
|
||||
|
||||
_it += 4;
|
||||
|
||||
_retu->_ssrc = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( ( uint32_t ) * ( _it + 3 ) ) ;
|
||||
|
||||
|
||||
size_t x;
|
||||
for ( x = 0; x < cc; x++ ) {
|
||||
_it += 4;
|
||||
_retu->_csrc[x] = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( ( uint32_t ) * ( _it + 3 ) ) ;
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
rtp_ext_header_t* rtp_extract_ext_header ( const uint8_t* _payload, size_t _bytes )
|
||||
{
|
||||
if ( !_payload ) {
|
||||
t_perror ( RTP_ERROR_PAYLOAD_NULL );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const uint8_t* _it = _payload;
|
||||
|
||||
rtp_ext_header_t* _retu = calloc(sizeof(rtp_ext_header_t), 1);
|
||||
assert(_retu);
|
||||
|
||||
uint16_t _ext_len = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it += 2;
|
||||
|
||||
if ( _bytes < ( _ext_len * sizeof(uint32_t) ) ) {
|
||||
t_perror ( RTP_ERROR_PAYLOAD_INVALID );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->_ext_len = _ext_len;
|
||||
_retu->_ext_type = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it -= 2;
|
||||
|
||||
_retu->_hd_ext = calloc(sizeof(uint32_t), _ext_len);
|
||||
assert(_retu->_hd_ext);
|
||||
|
||||
uint32_t* _hd_ext = _retu->_hd_ext;
|
||||
size_t i;
|
||||
for ( i = 0; i < _ext_len; i++ ) {
|
||||
_it += 4;
|
||||
_hd_ext[i] = ( ( uint32_t ) * _it << 24 ) |
|
||||
( ( uint32_t ) * ( _it + 1 ) << 16 ) |
|
||||
( ( uint32_t ) * ( _it + 2 ) << 8 ) |
|
||||
( ( uint32_t ) * ( _it + 3 ) ) ;
|
||||
}
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
uint8_t* rtp_add_header ( rtp_header_t* _header, uint8_t* _payload )
|
||||
{
|
||||
uint8_t cc = rtp_header_get_flag_CSRC_count ( _header );
|
||||
|
||||
uint8_t* _it = _payload;
|
||||
|
||||
*_it = _header->_flags; ++_it;
|
||||
*_it = _header->_marker_payload_t; ++_it;
|
||||
|
||||
*_it = ( _header->_sequence_number >> 8 ); ++_it;
|
||||
*_it = ( _header->_sequence_number ); ++_it;
|
||||
|
||||
uint32_t _timestamp = _header->_timestamp;
|
||||
*_it = ( _timestamp >> 24 ); ++_it;
|
||||
*_it = ( _timestamp >> 16 ); ++_it;
|
||||
*_it = ( _timestamp >> 8 ); ++_it;
|
||||
*_it = ( _timestamp ); ++_it;
|
||||
|
||||
uint32_t _ssrc = _header->_ssrc;
|
||||
*_it = ( _ssrc >> 24 ); ++_it;
|
||||
*_it = ( _ssrc >> 16 ); ++_it;
|
||||
*_it = ( _ssrc >> 8 ); ++_it;
|
||||
*_it = ( _ssrc );
|
||||
|
||||
uint32_t *_csrc = _header->_csrc;
|
||||
size_t x;
|
||||
for ( x = 0; x < cc; x++ ) {
|
||||
++_it;
|
||||
*_it = ( _csrc[x] >> 24 ); ++_it;
|
||||
*_it = ( _csrc[x] >> 16 ); ++_it;
|
||||
*_it = ( _csrc[x] >> 8 ); ++_it;
|
||||
*_it = ( _csrc[x] );
|
||||
}
|
||||
|
||||
return _it;
|
||||
}
|
||||
|
||||
uint8_t* rtp_add_extention_header ( rtp_ext_header_t* _header, uint8_t* _payload )
|
||||
{
|
||||
uint8_t* _it = _payload;
|
||||
|
||||
*_it = ( _header->_ext_len >> 8 ); _it++;
|
||||
*_it = ( _header->_ext_len ); _it++;
|
||||
|
||||
*_it = ( _header->_ext_type >> 8 ); ++_it;
|
||||
*_it = ( _header->_ext_type );
|
||||
|
||||
size_t x;
|
||||
|
||||
uint32_t* _hd_ext = _header->_hd_ext;
|
||||
for ( x = 0; x < _header->_ext_len; x++ ) {
|
||||
++_it;
|
||||
*_it = ( _hd_ext[x] >> 24 ); ++_it;
|
||||
*_it = ( _hd_ext[x] >> 16 ); ++_it;
|
||||
*_it = ( _hd_ext[x] >> 8 ); ++_it;
|
||||
*_it = ( _hd_ext[x] );
|
||||
}
|
||||
|
||||
return _it;
|
||||
}
|
||||
|
||||
size_t rtp_header_get_size ( const rtp_header_t* _header )
|
||||
{
|
||||
return ( 8 + ( rtp_header_get_flag_CSRC_count ( _header ) * 4 ) );
|
||||
}
|
||||
/* Setting flags */
|
||||
|
||||
void rtp_header_add_flag_version ( rtp_header_t* _header, uint32_t value )
|
||||
{
|
||||
( _header->_flags ) &= 0x3F;
|
||||
( _header->_flags ) |= ( ( ( value ) << 6 ) & 0xC0 );
|
||||
}
|
||||
|
||||
void rtp_header_add_flag_padding ( rtp_header_t* _header, uint32_t value )
|
||||
{
|
||||
if ( value > 0 ) {
|
||||
value = 1; /* It can only be 1 */
|
||||
}
|
||||
|
||||
( _header->_flags ) &= 0xDF;
|
||||
( _header->_flags ) |= ( ( ( value ) << 5 ) & 0x20 );
|
||||
}
|
||||
|
||||
void rtp_header_add_flag_extension ( rtp_header_t* _header, uint32_t value )
|
||||
{
|
||||
if ( value > 0 ) {
|
||||
value = 1; /* It can only be 1 */
|
||||
}
|
||||
|
||||
( _header->_flags ) &= 0xEF;
|
||||
( _header->_flags ) |= ( ( ( value ) << 4 ) & 0x10 );
|
||||
}
|
||||
|
||||
void rtp_header_add_flag_CSRC_count ( rtp_header_t* _header, uint32_t value )
|
||||
{
|
||||
( _header->_flags ) &= 0xF0;
|
||||
( _header->_flags ) |= ( ( value ) & 0x0F );
|
||||
}
|
||||
|
||||
void rtp_header_add_setting_marker ( rtp_header_t* _header, uint32_t value )
|
||||
{
|
||||
if ( value > 1 )
|
||||
value = 1;
|
||||
|
||||
( _header->_marker_payload_t ) &= 0x7F;
|
||||
( _header->_marker_payload_t ) |= ( ( ( value ) << 7 ) /*& 0x80 */ );
|
||||
}
|
||||
|
||||
void rtp_header_add_setting_payload ( rtp_header_t* _header, uint32_t value )
|
||||
{
|
||||
if ( value > 127 )
|
||||
value = 127; /* Well set to maximum */
|
||||
|
||||
( _header->_marker_payload_t ) &= 0x80;
|
||||
( _header->_marker_payload_t ) |= ( ( value ) /* & 0x7F */ );
|
||||
}
|
||||
|
||||
/* Getting values from flags */
|
||||
uint8_t rtp_header_get_flag_version ( const rtp_header_t* _header )
|
||||
{
|
||||
return ( _header->_flags & 0xd0 ) >> 6;
|
||||
}
|
||||
|
||||
uint8_t rtp_header_get_flag_padding ( const rtp_header_t* _header )
|
||||
{
|
||||
return ( _header->_flags & 0x20 ) >> 5;
|
||||
}
|
||||
|
||||
uint8_t rtp_header_get_flag_extension ( const rtp_header_t* _header )
|
||||
{
|
||||
return ( _header->_flags & 0x10 ) >> 4;
|
||||
}
|
||||
|
||||
uint8_t rtp_header_get_flag_CSRC_count ( const rtp_header_t* _header )
|
||||
{
|
||||
return ( _header->_flags & 0x0f );
|
||||
}
|
||||
uint8_t rtp_header_get_setting_marker ( const rtp_header_t* _header )
|
||||
{
|
||||
return ( _header->_marker_payload_t ) >> 7;
|
||||
}
|
||||
uint8_t rtp_header_get_setting_payload_type ( const rtp_header_t* _header )
|
||||
{
|
||||
/*
|
||||
uint8_t _retu;
|
||||
|
||||
if ( _header->_marker_payload_t >> 7 == 1 ) {
|
||||
_header->_marker_payload_t ^= 0x80;
|
||||
_retu = _header->_marker_payload_t;
|
||||
_header->_marker_payload_t ^= 0x80;
|
||||
} else {
|
||||
_retu = _header->_marker_payload_t;
|
||||
}
|
||||
*/
|
||||
/* return to start value
|
||||
return _retu; */
|
||||
return _header->_marker_payload_t & 0x7f;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
/* rtp_message.h
|
||||
*
|
||||
* Rtp Message handler. It handles message/header parsing.
|
||||
* Refer to RTP: A Transport Protocol for Real-Time Applications ( RFC 3550 ) for more info. !Red!
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RTP__MESSAGE_H_
|
||||
#define _RTP__MESSAGE_H_
|
||||
|
||||
#include "../toxcore/network.h"
|
||||
#include "toxrtp_helper.h"
|
||||
#include "../toxcore/tox.h"
|
||||
/* Defines */
|
||||
|
||||
#define _MAX_SEQU_NUM 65535
|
||||
|
||||
/* Minimum size */
|
||||
#define _MIN_HEADER_LENGTH 12
|
||||
#define _MIN_EXT_HEADER_LENGTH 4
|
||||
|
||||
/* End of defines */
|
||||
|
||||
|
||||
typedef struct rtp_dest_list_s {
|
||||
tox_IP_Port _dest;
|
||||
struct rtp_dest_list_s* next;
|
||||
|
||||
} rtp_dest_list_t;
|
||||
|
||||
typedef struct rtp_header_s {
|
||||
uint8_t _flags; /* Version(2),Padding(1), Ext(1), Cc(4) */
|
||||
uint8_t _marker_payload_t; /* Marker(1), PlayLoad Type(7) */
|
||||
uint16_t _sequence_number; /* Sequence Number */
|
||||
uint32_t _timestamp; /* Timestamp */
|
||||
uint32_t _ssrc; /* SSRC */
|
||||
uint32_t* _csrc; /* CSRC's table */
|
||||
|
||||
uint32_t _length; /* A little something for allocation */
|
||||
|
||||
} rtp_header_t;
|
||||
|
||||
typedef struct rtp_ext_header_s {
|
||||
uint16_t _ext_type; /* Extension profile */
|
||||
uint16_t _ext_len; /* Number of extensions */
|
||||
uint32_t* _hd_ext; /* Extension's table */
|
||||
|
||||
|
||||
} rtp_ext_header_t;
|
||||
|
||||
typedef struct rtp_msg_s {
|
||||
struct rtp_header_s* _header;
|
||||
struct rtp_ext_header_s* _ext_header;
|
||||
uint32_t _header_lenght;
|
||||
|
||||
uint8_t* _data;
|
||||
uint32_t _length;
|
||||
tox_IP_Port _from;
|
||||
|
||||
struct rtp_msg_s* _next;
|
||||
} rtp_msg_t;
|
||||
|
||||
/* Extracts the header from the payload starting at _from */
|
||||
rtp_header_t* rtp_extract_header ( const uint8_t* _payload, size_t _bytes );
|
||||
rtp_ext_header_t* rtp_extract_ext_header ( const uint8_t* _payload, size_t _bytes );
|
||||
|
||||
|
||||
uint8_t* rtp_add_header ( rtp_header_t* _header, uint8_t* _payload );
|
||||
uint8_t* rtp_add_extention_header ( rtp_ext_header_t* _header, uint8_t* _payload );
|
||||
|
||||
/* Gets the size of the header _header in bytes */
|
||||
size_t rtp_header_get_size ( const rtp_header_t* _header );
|
||||
|
||||
void rtp_header_print (const rtp_header_t* _header);
|
||||
|
||||
/* Adding flags and settings */
|
||||
void rtp_header_add_flag_version ( rtp_header_t* _header, uint32_t value );
|
||||
void rtp_header_add_flag_padding ( rtp_header_t* _header, uint32_t value );
|
||||
void rtp_header_add_flag_extension ( rtp_header_t* _header, uint32_t value );
|
||||
void rtp_header_add_flag_CSRC_count ( rtp_header_t* _header, uint32_t value );
|
||||
void rtp_header_add_setting_marker ( rtp_header_t* _header, uint32_t value );
|
||||
void rtp_header_add_setting_payload ( rtp_header_t* _header, uint32_t value );
|
||||
|
||||
|
||||
/* Getting values from flags and settings */
|
||||
uint8_t rtp_header_get_flag_version ( const rtp_header_t* _header );
|
||||
uint8_t rtp_header_get_flag_padding ( const rtp_header_t* _header );
|
||||
uint8_t rtp_header_get_flag_extension ( const rtp_header_t* _header );
|
||||
uint8_t rtp_header_get_flag_CSRC_count ( const rtp_header_t* _header );
|
||||
uint8_t rtp_header_get_setting_marker ( const rtp_header_t* _header );
|
||||
uint8_t rtp_header_get_setting_payload_type ( const rtp_header_t* _header );
|
||||
|
||||
#endif /* _RTP__MESSAGE_H_ */
|
Loading…
Reference in New Issue
Block a user