mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
836 lines
23 KiB
C
836 lines
23 KiB
C
|
|
#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;
|
|
}
|