More av cleanup

This commit is contained in:
mannol 2014-11-29 13:42:19 +01:00
parent 975ce25af0
commit e62ded3a6d
13 changed files with 546 additions and 656 deletions

View File

@ -220,8 +220,8 @@ void register_callbacks(ToxAv *av, void *data)
toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
toxav_register_callstate_callback(av, callback_peer_cs_change, av_OnPeerCSChange, data);
toxav_register_callstate_callback(av, callback_self_cs_change, av_OnSelfCSChange, data);
toxav_register_audio_callback(callback_audio, NULL);
toxav_register_video_callback(callback_video, NULL);
toxav_register_audio_callback(av, callback_audio, NULL);
toxav_register_video_callback(av, callback_video, NULL);
}

View File

@ -126,8 +126,8 @@ void register_callbacks(ToxAv *av, void *data)
toxav_register_callstate_callback(av, callback_requ_timeout, av_OnRequestTimeout, data);
toxav_register_audio_callback(callback_audio, NULL);
toxav_register_video_callback(callback_video, NULL);
toxav_register_audio_callback(av, callback_audio, NULL);
toxav_register_video_callback(av, callback_video, NULL);
}
/*************************************************************************************************/

View File

@ -27,6 +27,7 @@
#endif /* HAVE_CONFIG_H */
#include "../toxcore/logger.h"
#include "../toxcore/util.h"
#include <stdio.h>
#include <stdlib.h>
@ -50,14 +51,10 @@
/* FIXME: Might not be enough */
#define VIDEO_DECODE_BUFFER_SIZE 20
#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; }
#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; }
typedef ARRAY(uint8_t) Payload;
static PAIR(CSVideoCallback, void *) vpcallback;
static PAIR(CSAudioCallback, void *) apcallback;
typedef struct {
uint16_t size; /* Max size */
uint16_t start;
@ -319,24 +316,12 @@ static int init_audio_encoder(CSSession *cs)
return 0;
}
static float calculate_sum_sq (int16_t *n, uint16_t k)
{
float result = 0;
uint16_t i = 0;
for ( ; i < k; i ++) result += (float) (n[i] * n[i]);
return result;
}
/* PUBLIC */
int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length)
{
if (!cs || !length || length > cs->max_video_frame_size) {
LOGGER_ERROR("Invalid CodecState or video frame size: %u", length);
return -1;
return cs_ErrorSplittingVideoPayload;
}
cs->split_video_frame[0] = cs->frameid_out++;
@ -375,43 +360,23 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size)
void cs_do(CSSession *cs)
{
/* Codec session should always be protected by call mutex so no need to check for cs validity
*/
if (!cs) return;
pthread_mutex_lock(cs->queue_mutex);
if (!cs->active) {
pthread_mutex_unlock(cs->queue_mutex);
return;
}
/*
/* Iterate over whole buffers and call playback callback * /
if (cs->abuf_ready) while (!DecodedAudioBuffer_empty(cs->abuf_ready)) {
DecodedAudio* p;
DecodedAudioBuffer_read(cs->abuf_ready, &p);
if (apcallback.first)
apcallback.first(cs->agent, cs->call_idx, p->data, p->size, apcallback.second);
free(p);
}
if (cs->vbuf_ready) while (!DecodedVideoBuffer_empty(cs->vbuf_ready)) {
vpx_image_t* p;
DecodedVideoBuffer_read(cs->vbuf_ready, &p);
if (vpcallback.first)
vpcallback.first(cs->agent, cs->call_idx, p, vpcallback.second);
vpx_img_free(p);
}
*/
Payload *p;
int rc;
pthread_mutex_lock(cs->queue_mutex);
if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) {
/* Decode audio */
buffer_read(cs->abuf_raw, &p);
/* Leave space for (possibly) other thread to queue more data after we read it here */
pthread_mutex_unlock(cs->queue_mutex);
uint16_t fsize = (cs->audio_decoder_channels *
(cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000);
int16_t tmp[fsize];
@ -421,15 +386,20 @@ void cs_do(CSSession *cs)
if (rc < 0)
LOGGER_WARNING("Decoding error: %s", opus_strerror(rc));
else
else if (cs->acb.first)
/* Play */
apcallback.first(cs->agent, cs->call_idx, tmp, rc, apcallback.second);
cs->acb.first(cs->agent, cs->call_idx, tmp, rc, cs->acb.second);
pthread_mutex_lock(cs->queue_mutex);
}
if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) {
/* Decode video */
buffer_read(cs->vbuf_raw, &p);
/* Leave space for (possibly) other thread to queue more data after we read it here */
pthread_mutex_unlock(cs->queue_mutex);
rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
free(p);
@ -441,27 +411,17 @@ void cs_do(CSSession *cs)
/* Play decoded images */
for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) {
vpcallback.first(cs->agent, cs->call_idx, dest, vpcallback.second);
if (cs->vcb.first)
cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second);
vpx_img_free(dest);
}
}
return;
}
pthread_mutex_unlock(cs->queue_mutex);
}
void cs_register_audio_callback(CSAudioCallback cb, void *data)
{
apcallback.first = cb;
apcallback.second = data;
}
void cs_register_video_callback(CSVideoCallback cb, void *data)
{
vpcallback.first = cb;
vpcallback.second = data;
}
int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height)
{
vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
@ -470,7 +430,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
return 0;
if (width * height > cs->max_width * cs->max_height)
return -1;
return cs_ErrorSettingVideoResolution;
LOGGER_DEBUG("New video resolution: %u %u", width, height);
cfg.g_w = width;
@ -479,7 +439,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig
if ( rc != VPX_CODEC_OK) {
LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
return -1;
return cs_ErrorSettingVideoResolution;
}
return 0;
@ -498,7 +458,7 @@ int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate)
if ( rc != VPX_CODEC_OK) {
LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
return -1;
return cs_ErrorSettingVideoBitrate;
}
return 0;
@ -513,6 +473,11 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
return NULL;
}
if (create_recursive_mutex(cs->queue_mutex) != 0) {
LOGGER_WARNING("Failed to create recursive mutex!");
return NULL;
}
if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) {
LOGGER_WARNING("Jitter buffer creaton failed!");
goto error;
@ -529,38 +494,22 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;
cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? a_encoding : 0;
cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? a_decoding : 0;
cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0;
cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0;
if ( !(cs->capabilities & a_encoding) || !(cs->capabilities & a_decoding) ) goto error;
if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error;
if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error;
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0) goto error;
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
if (pthread_mutexattr_destroy(&attr) != 0)
LOGGER_WARNING("Failed to destroy mutex attribute!");
goto error;
}
if (pthread_mutex_init(cs->queue_mutex, &attr) != 0) {
pthread_mutexattr_destroy(&attr);
goto error;
}
if ((cs->support_video = has_video)) {
cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width,
cs_self->max_video_height, cs_self->video_bitrate) ) ? v_encoding : 0;
cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? v_decoding : 0;
cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0;
cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0;
if ( !(cs->capabilities & v_encoding) || !(cs->capabilities & v_decoding) ) goto error;
if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error;
if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;
@ -569,17 +518,14 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer,
if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
}
if (pthread_mutexattr_destroy(&attr) != 0)
LOGGER_WARNING("Failed to destroy mutex attribute!");
cs->active = 1;
return cs;
error:
LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
pthread_mutex_destroy(cs->queue_mutex);
buffer_free(cs->abuf_raw);
if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder);
@ -588,9 +534,9 @@ error:
if (has_video) {
if ( cs->capabilities & v_decoding ) vpx_codec_destroy(&cs->v_decoder);
if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder);
if ( cs->capabilities & v_encoding ) vpx_codec_destroy(&cs->v_encoder);
if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder);
buffer_free(cs->vbuf_raw);
@ -608,13 +554,7 @@ void cs_kill(CSSession *cs)
{
if (!cs) return;
/* Lock running mutex and signal that cs is no longer active */
pthread_mutex_lock(cs->queue_mutex);
cs->active = 0;
/* Wait threads to close */
pthread_mutex_unlock(cs->queue_mutex);
/* queue_message will not be called since it's unregistered before cs_kill is called */
pthread_mutex_destroy(cs->queue_mutex);
@ -624,10 +564,10 @@ void cs_kill(CSSession *cs)
if ( cs->audio_decoder )
opus_decoder_destroy(cs->audio_decoder);
if ( cs->capabilities & v_decoding )
if ( cs->capabilities & cs_VideoDecoding )
vpx_codec_destroy(&cs->v_decoder);
if ( cs->capabilities & v_encoding )
if ( cs->capabilities & cs_VideoEncoding )
vpx_codec_destroy(&cs->v_encoder);
jbuf_free(cs->j_buf);
@ -639,43 +579,23 @@ void cs_kill(CSSession *cs)
free(cs);
}
void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration)
{
cs->EVAD_tolerance = treshold > frame_duration ? treshold / frame_duration : frame_duration;
}
int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy)
{
float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size;
if ( frame_energy > energy) {
cs->EVAD_tolerance_cr = cs->EVAD_tolerance; /* Reset counter */
return 1;
}
if ( cs->EVAD_tolerance_cr ) {
cs->EVAD_tolerance_cr --;
return 1;
}
return 0;
}
/* Called from RTP */
void queue_message(RTPSession *session, RTPMessage *msg)
{
/* This function is unregistered during call termination befor destroing
* Codec session so no need to check for validity of cs
*/
CSSession *cs = session->cs;
if (!cs || !cs->active) return;
if (!cs) return;
/* Audio */
if (session->payload_type == type_audio % 128) {
if (session->payload_type == msi_TypeAudio % 128) {
jbuf_write(cs->j_buf, msg);
pthread_mutex_lock(cs->queue_mutex);
int success = 0;
while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
@ -698,13 +618,13 @@ void queue_message(RTPSession *session, RTPMessage *msg)
}
if (p) {
pthread_mutex_lock(cs->queue_mutex);
buffer_write(cs->abuf_raw, p);
pthread_mutex_unlock(cs->queue_mutex);
} else {
LOGGER_WARNING("Allocation failed! Program might misbehave!");
}
}
pthread_mutex_unlock(cs->queue_mutex);
}
/* Video */
else {

View File

@ -42,16 +42,33 @@
/* Audio encoding/decoding */
#include <opus.h>
#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
typedef void (*CSAudioCallback) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data);
typedef void (*CSVideoCallback) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data);
typedef enum _CsCapabilities {
a_encoding = 1 << 0,
a_decoding = 1 << 1,
v_encoding = 1 << 2,
v_decoding = 1 << 3
} CsCapabilities;
/**
* Codec capabilities
*/
typedef enum {
cs_AudioEncoding = 1 << 0,
cs_AudioDecoding = 1 << 1,
cs_VideoEncoding = 1 << 2,
cs_VideoDecoding = 1 << 3
} CSCapabilities;
/**
* Codec errors.
*/
typedef enum {
cs_ErrorSettingVideoResolution = -30,
cs_ErrorSettingVideoBitrate = -31,
cs_ErrorSplittingVideoPayload = -32,
} CSError;
/**
* Codec session - controling codec
*/
typedef struct _CSSession {
/* VIDEO
@ -122,16 +139,21 @@ typedef struct _CSSession {
uint64_t capabilities; /* supports*/
/* Callbacks */
PAIR(CSAudioCallback, void*) acb;
PAIR(CSVideoCallback, void*) vcb;
/* Buffering */
void *abuf_raw, *vbuf_raw; /* Un-decoded data */
_Bool active;
pthread_mutex_t queue_mutex[1];
void *agent; /* Pointer to ToxAv */
int32_t call_idx;
} CSSession;
/* Make sure to be called BEFORE corresponding rtp_new */
CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video);
/* Make sure to be called AFTER corresponding rtp_kill */
void cs_kill(CSSession *cs);
int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length);
@ -142,19 +164,12 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size);
*/
void cs_do(CSSession *cs);
void cs_register_audio_callback(CSAudioCallback cb, void *data);
void cs_register_video_callback(CSVideoCallback cb, void *data);
/* Reconfigure video encoder; return 0 on success or -1 on failure. */
int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height);
int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate);
/* Calculate energy and return 1 if has voice, 0 if not */
int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy);
void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration);
/* Internal. Called from rtp_handle_message */
void queue_message(RTPSession *session, RTPMessage *msg);
#endif /* _CODEC_H_ */

View File

@ -112,10 +112,10 @@ typedef struct _MSIMessage {
static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i)
{
if ( s->callbacks[i].function ) {
if ( s->callbacks[i].first ) {
LOGGER_DEBUG("Invoking callback function: %d", i);
s->callbacks[i].function( s->agent_handler, c, s->callbacks[i].data );
s->callbacks[i].first( s->agent_handler, c, s->callbacks[i].second );
}
}
@ -791,7 +791,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
for ( ; i < session->calls[j]->peer_count; i ++ )
if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) {
invoke_callback(session, j, MSI_OnPeerTimeout);
invoke_callback(session, j, msi_OnPeerTimeout);
terminate_call(session, session->calls[j]);
LOGGER_DEBUG("Remote: %d timed out!", friend_num);
return; /* TODO: On group calls change behaviour */
@ -820,7 +820,7 @@ static void handle_timeout ( Timer *timer )
if (call) {
LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
invoke_callback(timer->session, timer->call_idx, MSI_OnRequestTimeout);
invoke_callback(timer->session, timer->call_idx, msi_OnRequestTimeout);
msi_cancel(timer->session, timer->call_idx, call->peers [0], "Request timed out");
}
}
@ -840,7 +840,7 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
if ( call ) {
if ( call->peers[0] == (uint32_t)msg->friend_id ) {
if (call->state == call_inviting) {
if (call->state == msi_CallInviting) {
/* The glare case. A calls B when at the same time
* B calls A. Who has advantage is set bey calculating
* 'bigger' Call id and then that call id is being used in
@ -864,7 +864,7 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
} else {
return 0; /* Wait for ringing from peer */
}
} else if (call->state == call_active) {
} else if (call->state == msi_CallActive) {
/* Request for media change; call callback and send starting response */
if (flush_peer_csettings(call, msg, 0) != 0) { /**/
LOGGER_WARNING("Peer sent invalid csetting!");
@ -872,9 +872,9 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
return 0;
}
LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == type_audio ? "audio" : "video");
LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == msi_TypeAudio ? "audio" : "video");
send_reponse(session, call, starting, msg->friend_id);
invoke_callback(session, call->call_idx, MSI_OnPeerCSChange);
invoke_callback(session, call->call_idx, msi_OnPeerCSChange);
return 1;
}
} else {
@ -898,12 +898,12 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
}
memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) );
call->state = call_starting;
call->state = msi_CallStarting;
add_peer( call, msg->friend_id);
flush_peer_csettings ( call, msg, 0 );
send_reponse(session, call, ringing, msg->friend_id);
invoke_callback(session, call->call_idx, MSI_OnInvite);
invoke_callback(session, call->call_idx, msi_OnInvite);
return 1;
}
@ -919,8 +919,8 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m
LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
call->state = call_active;
invoke_callback(session, call->call_idx, MSI_OnStart);
call->state = msi_CallActive;
invoke_callback(session, call->call_idx, msi_OnStart);
return 1;
}
@ -933,7 +933,7 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
LOGGER_DEBUG("Session: %p Handling 'reject' on call: %u", session, call->call_idx);
invoke_callback(session, call->call_idx, MSI_OnReject);
invoke_callback(session, call->call_idx, msi_OnReject);
send_reponse(session, call, ending, msg->friend_id);
terminate_call(session, call);
@ -952,7 +952,7 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *
LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx);
invoke_callback(session, call->call_idx, MSI_OnCancel);
invoke_callback(session, call->call_idx, msi_OnCancel);
terminate_call ( session, call );
return 1;
@ -967,7 +967,7 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
invoke_callback(session, call->call_idx, MSI_OnEnd);
invoke_callback(session, call->call_idx, msi_OnEnd);
send_reponse(session, call, ending, msg->friend_id);
terminate_call ( session, call );
@ -993,7 +993,7 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage
call->ringing_timer_id = timer_alloc
( session, handle_timeout, call->call_idx, call->ringing_tout_ms );
invoke_callback(session, call->call_idx, MSI_OnRinging);
invoke_callback(session, call->call_idx, msi_OnRinging);
return 1;
}
static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
@ -1003,16 +1003,16 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
return 0;
}
if ( call->state == call_active ) { /* Change media */
if ( call->state == msi_CallActive ) { /* Change media */
LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
invoke_callback(session, call->call_idx, MSI_OnSelfCSChange);
invoke_callback(session, call->call_idx, msi_OnSelfCSChange);
} else if ( call->state == call_inviting ) {
} else if ( call->state == msi_CallInviting ) {
LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
call->state = call_active;
call->state = msi_CallActive;
MSIMessage *msg_start = msi_new_message ( TypeRequest, start );
send_message ( session, call, msg_start, msg->friend_id );
@ -1023,7 +1023,7 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
/* This is here in case of glare */
timer_release(session->timer_handler, call->ringing_timer_id);
invoke_callback(session, call->call_idx, MSI_OnStart);
invoke_callback(session, call->call_idx, msi_OnStart);
} else {
LOGGER_ERROR("Invalid call state");
terminate_call(session, call );
@ -1043,14 +1043,13 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *
LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx );
invoke_callback(session, call->call_idx, MSI_OnEnd);
invoke_callback(session, call->call_idx, msi_OnEnd);
terminate_call ( session, call );
return 1;
}
static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
{
if ( !call ) {
LOGGER_WARNING("Handling 'error' on non-existing call!");
return -1;
@ -1058,7 +1057,7 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
invoke_callback(session, call->call_idx, MSI_OnEnd);
invoke_callback(session, call->call_idx, msi_OnEnd);
/* Handle error accordingly */
if ( msg->reason.exists ) {
@ -1127,7 +1126,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
msg->friend_id = source;
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
/* Find what call */
MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
@ -1187,7 +1186,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
free ( msg );
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
}
@ -1195,8 +1194,8 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
/********** User functions **********/
void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
{
session->callbacks[id].function = callback;
session->callbacks[id].data = userdata;
session->callbacks[id].first = callback;
session->callbacks[id].second = userdata;
}
@ -1224,17 +1223,6 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
goto error;
}
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0 ||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 ||
pthread_mutex_init(&retu->mutex, &attr) != 0 ) {
LOGGER_ERROR("Failed to init mutex! Program might misbehave!");
goto error;
}
retu->timer_handler = calloc(1, sizeof(TimerHandler));
if (retu->timer_handler == NULL) {
@ -1250,6 +1238,11 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
goto error;
}
if (create_recursive_mutex(retu->mutex) != 0) {
LOGGER_ERROR("Failed to init mutex! Program might misbehave");
goto error;
}
retu->messenger_handle = messenger;
retu->agent_handler = NULL;
retu->max_calls = max_calls;
@ -1265,7 +1258,10 @@ MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
return retu;
error:
free(retu->timer_handler);
if (retu->timer_handler) {
free(((TimerHandler *)retu->timer_handler)->timers);
free(retu->timer_handler);
}
free(retu->calls);
free(retu);
return NULL;
@ -1279,15 +1275,11 @@ int msi_kill ( MSISession *session )
return -1;
}
pthread_mutex_lock(&session->mutex);
m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
pthread_mutex_unlock(&session->mutex);
pthread_mutex_lock(session->mutex);
int _status = 0;
/* If have calls, cancel them */
/* Cancel active calls */
int32_t idx = 0;
for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) {
/* Cancel all? */
uint16_t _it = 0;
@ -1296,13 +1288,14 @@ int msi_kill ( MSISession *session )
*/
msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
}
pthread_mutex_destroy(&session->mutex);
free ( session->calls );
pthread_mutex_unlock(session->mutex);
pthread_mutex_destroy(session->mutex);
LOGGER_DEBUG("Terminated session: %p", session);
free ( session->calls );
free ( session );
return _status;
return 0;
}
int msi_invite ( MSISession *session,
@ -1311,7 +1304,7 @@ int msi_invite ( MSISession *session,
uint32_t rngsec,
uint32_t friend_id )
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
@ -1321,17 +1314,17 @@ int msi_invite ( MSISession *session,
for (; i < session->max_calls; i ++)
if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
LOGGER_ERROR("Already in a call with friend %d", friend_id);
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorAlreadyInCallWithPeer;
}
MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
if ( !call ) {
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
LOGGER_ERROR("Cannot handle more calls");
return -1;
return msi_ErrorReachedCallLimit;
}
*call_index = call->call_idx;
@ -1348,32 +1341,32 @@ int msi_invite ( MSISession *session,
send_message ( session, call, msg_invite, friend_id );
free( msg_invite );
call->state = call_inviting;
call->state = msi_CallInviting;
call->request_timer_id = timer_alloc ( session, handle_timeout, call->call_idx, m_deftout );
LOGGER_DEBUG("Invite sent");
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
int msi_hangup ( MSISession *session, int32_t call_index )
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
LOGGER_ERROR("Invalid call index!");
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorNoCall;
}
if ( session->calls[call_index]->state != call_active ) {
LOGGER_ERROR("No call with such index or call is not active!");
pthread_mutex_unlock(&session->mutex);
return -1;
if ( session->calls[call_index]->state != msi_CallActive ) {
LOGGER_ERROR("Call is not active!");
pthread_mutex_unlock(session->mutex);
return msi_ErrorInvalidState;
}
MSIMessage *msg_end = msi_new_message ( TypeRequest, end );
@ -1384,28 +1377,34 @@ int msi_hangup ( MSISession *session, int32_t call_index )
for ( ; it < session->calls[call_index]->peer_count; it ++ )
send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
session->calls[call_index]->state = call_hanged_up;
session->calls[call_index]->state = msi_CallOver;
free ( msg_end );
session->calls[call_index]->request_timer_id =
timer_alloc ( session, handle_timeout, call_index, m_deftout );
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *csettings )
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
LOGGER_ERROR("Invalid call index!");
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorNoCall;
}
if ( session->calls[call_index]->state != msi_CallStarting ) {
LOGGER_ERROR("Call is in invalid state!");
pthread_mutex_unlock(session->mutex);
return msi_ErrorInvalidState;
}
MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
session->calls[call_index]->csettings_local = *csettings;
@ -1415,23 +1414,29 @@ int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings *cs
send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] );
free ( msg_starting );
session->calls[call_index]->state = call_active;
session->calls[call_index]->state = msi_CallActive;
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
LOGGER_ERROR("Invalid call index!");
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorNoCall;
}
if ( session->calls[call_index]->state != msi_CallInviting ) {
LOGGER_ERROR("Call is in invalid state!");
pthread_mutex_unlock(session->mutex);
return msi_ErrorInvalidState;
}
MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel );
/* FIXME */
@ -1453,22 +1458,28 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
free ( msg_cancel );
terminate_call ( session, session->calls[call_index] );
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
LOGGER_ERROR("Invalid call index!");
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorNoCall;
}
if ( session->calls[call_index]->state != msi_CallStarting ) {
LOGGER_ERROR("Call is in invalid state!");
pthread_mutex_unlock(session->mutex);
return msi_ErrorInvalidState;
}
MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject );
/* FIXME */
@ -1490,50 +1501,50 @@ int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
free ( msg_reject );
session->calls[call_index]->state = call_hanged_up;
session->calls[call_index]->state = msi_CallOver;
session->calls[call_index]->request_timer_id =
timer_alloc ( session, handle_timeout, call_index, m_deftout );
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
int msi_stopcall ( MSISession *session, int32_t call_index )
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index);
if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorNoCall;
}
/* just terminate it */
terminate_call ( session, session->calls[call_index] );
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings *csettings)
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
LOGGER_DEBUG("Changing media on call: %d", call_index);
if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
LOGGER_ERROR("Invalid call index!");
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorNoCall;
}
MSICall *call = session->calls[call_index];
if ( call->state != call_active ) {
if ( call->state != msi_CallActive ) {
LOGGER_ERROR("Call is not active!");
pthread_mutex_unlock(&session->mutex);
return -1;
pthread_mutex_unlock(session->mutex);
return msi_ErrorInvalidState;
}
MSICSettings *local = &call->csettings_local;
@ -1548,7 +1559,7 @@ int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSett
local->audio_sample_rate == csettings->audio_sample_rate &&
local->audio_channels == csettings->audio_channels ) {
LOGGER_ERROR("Call is already set accordingly!");
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return -1;
}
@ -1562,14 +1573,14 @@ int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSett
LOGGER_DEBUG("Request for media change sent");
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
return 0;
}
void msi_do(MSISession *session)
{
pthread_mutex_lock(&session->mutex);
pthread_mutex_lock(session->mutex);
TimerHandler *timer = session->timer_handler;
@ -1586,5 +1597,5 @@ void msi_do(MSISession *session)
timer_release(timer, id);
}
pthread_mutex_unlock(&session->mutex);
pthread_mutex_unlock(session->mutex);
}

View File

@ -25,6 +25,7 @@
#include <inttypes.h>
#include <pthread.h>
#include "codec.h"
#include "../toxcore/Messenger.h"
typedef uint8_t MSICallIDType[12];
@ -35,8 +36,8 @@ typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg );
* Call type identifier. Also used as rtp callback prefix.
*/
typedef enum {
type_audio = 192,
type_video
msi_TypeAudio = 192,
msi_TypeVideo
} MSICallType;
@ -44,11 +45,11 @@ typedef enum {
* Call state identifiers.
*/
typedef enum {
call_inviting, /* when sending call invite */
call_starting, /* when getting call invite */
call_active,
call_hold,
call_hanged_up
msi_CallInviting, /* when sending call invite */
msi_CallStarting, /* when getting call invite */
msi_CallActive,
msi_CallHold,
msi_CallOver
} MSICallState;
@ -74,26 +75,27 @@ typedef struct _MSICodecSettings {
* Callbacks ids that handle the states
*/
typedef enum {
MSI_OnInvite, /* Incoming call */
MSI_OnRinging, /* When peer is ready to accept/reject the call */
MSI_OnStart, /* Call (RTP transmission) started */
MSI_OnCancel, /* The side that initiated call canceled invite */
MSI_OnReject, /* The side that was invited rejected the call */
MSI_OnEnd, /* Call that was active ended */
MSI_OnRequestTimeout, /* When the requested action didn't get response in specified time */
MSI_OnPeerTimeout, /* Peer timed out; stop the call */
MSI_OnPeerCSChange, /* Peer requested Csettings change */
MSI_OnSelfCSChange /* Csettings change confirmation */
msi_OnInvite, /* Incoming call */
msi_OnRinging, /* When peer is ready to accept/reject the call */
msi_OnStart, /* Call (RTP transmission) started */
msi_OnCancel, /* The side that initiated call canceled invite */
msi_OnReject, /* The side that was invited rejected the call */
msi_OnEnd, /* Call that was active ended */
msi_OnRequestTimeout, /* When the requested action didn't get response in specified time */
msi_OnPeerTimeout, /* Peer timed out; stop the call */
msi_OnPeerCSChange, /* Peer requested Csettings change */
msi_OnSelfCSChange /* Csettings change confirmation */
} MSICallbackID;
/**
* Callbacks container
* Errors
*/
typedef struct _MSICallbackCont {
MSICallbackType function;
void *data;
} MSICallbackCont;
typedef enum {
msi_ErrorNoCall = -20, /* Trying to perform call action while not in a call */
msi_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/
msi_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */
msi_ErrorReachedCallLimit = -23, /* Cannot handle more calls */
} MSIError;
/**
* The call struct.
@ -135,10 +137,10 @@ typedef struct _MSISession {
uint32_t frequ;
uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
pthread_mutex_t mutex;
pthread_mutex_t mutex[1];
void *timer_handler;
MSICallbackCont callbacks[10]; /* Callbacks used by this session */
PAIR(MSICallbackType, void*) callbacks[10];
} MSISession;
/**

View File

@ -70,30 +70,30 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
return NULL;
}
RTPHeader *_retu = calloc(1, sizeof (RTPHeader));
RTPHeader *retu = calloc(1, sizeof (RTPHeader));
if ( !_retu ) {
if ( !retu ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
return NULL;
}
memcpy(&_retu->sequnum, payload, sizeof(_retu->sequnum));
_retu->sequnum = ntohs(_retu->sequnum);
memcpy(&retu->sequnum, payload, sizeof(retu->sequnum));
retu->sequnum = ntohs(retu->sequnum);
const uint8_t *_it = payload + 2;
const uint8_t *it = payload + 2;
_retu->flags = *_it;
++_it;
retu->flags = *it;
++it;
/* This indicates if the first 2 bits are valid.
* Now it may happen that this is out of order but
* it cuts down chances of parsing some invalid value
*/
if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) {
if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) {
/* Deallocate */
LOGGER_WARNING("Invalid version!");
free(_retu);
free(retu);
return NULL;
}
@ -101,38 +101,37 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
* Added a check for the size of the header little sooner so
* I don't need to parse the other stuff if it's bad
*/
uint8_t _cc = GET_FLAG_CSRCC ( _retu );
int _length = 12 /* Minimum header len */ + ( _cc * 4 );
uint8_t cc = GET_FLAG_CSRCC ( retu );
int total = 12 /* Minimum header len */ + ( cc * 4 );
if ( length < _length ) {
if ( length < total ) {
/* Deallocate */
LOGGER_WARNING("Length invalid!");
free(_retu);
free(retu);
return NULL;
}
memset(_retu->csrc, 0, 16 * sizeof (uint32_t));
memset(retu->csrc, 0, 16 * sizeof (uint32_t));
_retu->marker_payloadt = *_it;
++_it;
_retu->length = _length;
retu->marker_payloadt = *it;
++it;
retu->length = total;
memcpy(&_retu->timestamp, _it, sizeof(_retu->timestamp));
_retu->timestamp = ntohl(_retu->timestamp);
_it += 4;
memcpy(&_retu->ssrc, _it, sizeof(_retu->ssrc));
_retu->ssrc = ntohl(_retu->ssrc);
memcpy(&retu->timestamp, it, sizeof(retu->timestamp));
retu->timestamp = ntohl(retu->timestamp);
it += 4;
memcpy(&retu->ssrc, it, sizeof(retu->ssrc));
retu->ssrc = ntohl(retu->ssrc);
uint8_t _x;
for ( _x = 0; _x < _cc; _x++ ) {
_it += 4;
memcpy(&_retu->csrc[_x], _it, sizeof(_retu->csrc[_x]));
_retu->csrc[_x] = ntohl(_retu->csrc[_x]);
uint8_t x;
for ( x = 0; x < cc; x++ ) {
it += 4;
memcpy(&retu->csrc[x], it, sizeof(retu->csrc[x]));
retu->csrc[x] = ntohl(retu->csrc[x]);
}
return _retu;
return retu;
}
/**
@ -140,47 +139,46 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
*/
RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
{
const uint8_t *_it = payload;
const uint8_t *it = payload;
RTPExtHeader *_retu = calloc(1, sizeof (RTPExtHeader));
RTPExtHeader *retu = calloc(1, sizeof (RTPExtHeader));
if ( !_retu ) {
if ( !retu ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
return NULL;
}
uint16_t _ext_length;
memcpy(&_ext_length, _it, sizeof(_ext_length));
_ext_length = ntohs(_ext_length);
_it += 2;
uint16_t ext_length;
memcpy(&ext_length, it, sizeof(ext_length));
ext_length = ntohs(ext_length);
it += 2;
if ( length < ( _ext_length * sizeof(uint32_t) ) ) {
if ( length < ( ext_length * sizeof(uint32_t) ) ) {
LOGGER_WARNING("Length invalid!");
free(_retu);
free(retu);
return NULL;
}
_retu->length = _ext_length;
memcpy(&_retu->type, _it, sizeof(_retu->type));
_retu->type = ntohs(_retu->type);
_it += 2;
retu->length = ext_length;
memcpy(&retu->type, it, sizeof(retu->type));
retu->type = ntohs(retu->type);
it += 2;
if ( !(_retu->table = calloc(_ext_length, sizeof (uint32_t))) ) {
if ( !(retu->table = calloc(ext_length, sizeof (uint32_t))) ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
free(_retu);
free(retu);
return NULL;
}
uint16_t _x;
for ( _x = 0; _x < _ext_length; _x++ ) {
_it += 4;
memcpy(&(_retu->table[_x]), _it, sizeof(_retu->table[_x]));
_retu->table[_x] = ntohl(_retu->table[_x]);
uint16_t x;
for ( x = 0; x < ext_length; x++ ) {
it += 4;
memcpy(&(retu->table[x]), it, sizeof(retu->table[x]));
retu->table[x] = ntohl(retu->table[x]);
}
return _retu;
return retu;
}
/**
@ -188,8 +186,8 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
*/
uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
{
uint8_t _cc = GET_FLAG_CSRCC ( header );
uint8_t *_it = payload;
uint8_t cc = GET_FLAG_CSRCC ( header );
uint8_t *it = payload;
uint16_t sequnum;
uint32_t timestamp;
uint32_t ssrc;
@ -198,30 +196,29 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
/* Add sequence number first */
sequnum = htons(header->sequnum);
memcpy(_it, &sequnum, sizeof(sequnum));
_it += 2;
memcpy(it, &sequnum, sizeof(sequnum));
it += 2;
*_it = header->flags;
++_it;
*_it = header->marker_payloadt;
++_it;
*it = header->flags;
++it;
*it = header->marker_payloadt;
++it;
timestamp = htonl(header->timestamp);
memcpy(_it, &timestamp, sizeof(timestamp));
_it += 4;
memcpy(it, &timestamp, sizeof(timestamp));
it += 4;
ssrc = htonl(header->ssrc);
memcpy(_it, &ssrc, sizeof(ssrc));
memcpy(it, &ssrc, sizeof(ssrc));
uint8_t _x;
for ( _x = 0; _x < _cc; _x++ ) {
_it += 4;
csrc = htonl(header->csrc[_x]);
memcpy(_it, &csrc, sizeof(csrc));
uint8_t x;
for ( x = 0; x < cc; x++ ) {
it += 4;
csrc = htonl(header->csrc[x]);
memcpy(it, &csrc, sizeof(csrc));
}
return _it + 4;
return it + 4;
}
/**
@ -229,29 +226,29 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
*/
uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload )
{
uint8_t *_it = payload;
uint8_t *it = payload;
uint16_t length;
uint16_t type;
uint32_t entry;
length = htons(header->length);
memcpy(_it, &length, sizeof(length));
_it += 2;
memcpy(it, &length, sizeof(length));
it += 2;
type = htons(header->type);
memcpy(_it, &type, sizeof(type));
_it -= 2; /* Return to 0 position */
memcpy(it, &type, sizeof(type));
it -= 2; /* Return to 0 position */
if ( header->table ) {
uint16_t _x;
for ( _x = 0; _x < header->length; _x++ ) {
_it += 4;
entry = htonl(header->table[_x]);
memcpy(_it, &entry, sizeof(entry));
uint16_t x;
for ( x = 0; x < header->length; x++ ) {
it += 4;
entry = htonl(header->table[x]);
memcpy(it, &entry, sizeof(entry));
}
}
return _it + 4;
return it + 4;
}
/**
@ -259,32 +256,31 @@ uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload )
*/
RTPHeader *build_header ( RTPSession *session )
{
RTPHeader *_retu = calloc ( 1, sizeof (RTPHeader) );
RTPHeader *retu = calloc ( 1, sizeof (RTPHeader) );
if ( !_retu ) {
if ( !retu ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
return NULL;
}
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 );
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 = current_time_monotonic(); /* milliseconds */
_retu->ssrc = session->ssrc;
retu->sequnum = session->sequnum;
retu->timestamp = current_time_monotonic(); /* milliseconds */
retu->ssrc = session->ssrc;
int i;
for ( i = 0; i < session->cc; i++ )
_retu->csrc[i] = session->csrc[i];
retu->csrc[i] = session->csrc[i];
_retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
return _retu;
return retu;
}
@ -294,47 +290,47 @@ RTPHeader *build_header ( RTPSession *session )
*/
RTPMessage *msg_parse ( const uint8_t *data, int length )
{
RTPMessage *_retu = calloc(1, sizeof (RTPMessage));
RTPMessage *retu = calloc(1, sizeof (RTPMessage));
_retu->header = extract_header ( data, length ); /* It allocates memory and all */
retu->header = extract_header ( data, length ); /* It allocates memory and all */
if ( !_retu->header ) {
if ( !retu->header ) {
LOGGER_WARNING("Header failed to extract!");
free(_retu);
free(retu);
return NULL;
}
uint16_t _from_pos = _retu->header->length;
_retu->length = length - _from_pos;
uint16_t from_pos = retu->header->length;
retu->length = length - from_pos;
if ( GET_FLAG_EXTENSION ( _retu->header ) ) {
_retu->ext_header = extract_ext_header ( data + _from_pos, length );
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 );
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 { /* Error */
LOGGER_WARNING("Ext Header failed to extract!");
rtp_free_msg(NULL, _retu);
rtp_free_msg(NULL, retu);
return NULL;
}
} else {
_retu->ext_header = NULL;
retu->ext_header = NULL;
}
if ( length - _from_pos <= MAX_RTP_SIZE )
memcpy ( _retu->data, data + _from_pos, length - _from_pos );
if ( length - from_pos <= MAX_RTP_SIZE )
memcpy ( retu->data, data + from_pos, length - from_pos );
else {
LOGGER_WARNING("Invalid length!");
rtp_free_msg(NULL, _retu);
rtp_free_msg(NULL, retu);
return NULL;
}
_retu->next = NULL;
retu->next = NULL;
return _retu;
return retu;
}
/**
@ -342,28 +338,28 @@ RTPMessage *msg_parse ( const uint8_t *data, int length )
*/
int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
{
RTPSession *_session = object;
RTPMessage *_msg;
RTPSession *session = object;
RTPMessage *msg;
if ( !_session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */
if ( !session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */
LOGGER_WARNING("No session or invalid length of received buffer!");
return -1;
}
_msg = msg_parse ( data + 1, length - 1 );
msg = msg_parse ( data + 1, length - 1 );
if ( !_msg ) {
if ( !msg ) {
LOGGER_WARNING("Could not parse message!");
return -1;
}
/* 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;
if ( check_late_message(session, msg) < 0 ) { /* Not late */
session->rsequnum = msg->header->sequnum;
session->timestamp = msg->header->timestamp;
}
queue_message(_session, _msg);
queue_message(session, msg);
return 0;
}
@ -378,30 +374,30 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
return NULL;
}
uint8_t *_from_pos;
RTPMessage *_retu = calloc(1, sizeof (RTPMessage));
uint8_t *from_pos;
RTPMessage *retu = calloc(1, sizeof (RTPMessage));
if ( !_retu ) {
if ( !retu ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
return NULL;
}
/* 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;
/* 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 + 1;
uint32_t total_length = length + retu->header->length + 1;
_retu->data[0] = session->prefix;
retu->data[0] = session->prefix;
if ( _retu->ext_header ) {
_total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
if ( retu->ext_header ) {
total_length += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
_from_pos = add_header ( _retu->header, _retu->data + 1 );
_from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 );
from_pos = add_header ( retu->header, retu->data + 1 );
from_pos = add_ext_header ( retu->ext_header, from_pos + 1 );
} else {
_from_pos = add_header ( _retu->header, _retu->data + 1 );
from_pos = add_header ( retu->header, retu->data + 1 );
}
/*
@ -409,14 +405,14 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
* Of course if any
*/
/* Appends _data on to _retu->_data */
memcpy ( _from_pos, data, length );
/* Appends data on to retu->data */
memcpy ( from_pos, data, length );
_retu->length = _total_length;
retu->length = total_length;
_retu->next = NULL;
retu->next = NULL;
return _retu;
return retu;
}
@ -430,7 +426,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) {
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
rtp_free_msg ( session, msg );
return -1;
return rtp_ErrorSending;
}
@ -461,52 +457,52 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
{
RTPSession *_retu = calloc(1, sizeof(RTPSession));
RTPSession *retu = calloc(1, sizeof(RTPSession));
if ( !_retu ) {
if ( !retu ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
return NULL;
}
if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu)) {
if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, retu)) {
LOGGER_ERROR("Error setting custom register handler for rtp session");
free(_retu);
free(retu);
return NULL;
}
LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num);
_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 = random_int();
_retu->marker = 0;
_retu->payload_type = payload_type % 128;
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 = random_int();
retu->marker = 0;
retu->payload_type = payload_type % 128;
_retu->dest = friend_num;
retu->dest = friend_num;
_retu->rsequnum = _retu->sequnum = 0;
retu->rsequnum = retu->sequnum = 0;
_retu->ext_header = NULL; /* When needed allocate */
retu->ext_header = NULL; /* When needed allocate */
if ( !(_retu->csrc = calloc(1, sizeof (uint32_t))) ) {
if ( !(retu->csrc = calloc(1, sizeof (uint32_t))) ) {
LOGGER_WARNING("Alloc failed! Program might misbehave!");
free(_retu);
free(retu);
return NULL;
}
_retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */
retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */
/* Also set payload type as prefix */
_retu->prefix = payload_type;
retu->prefix = payload_type;
/*
*
*/
return _retu;
return retu;
}
void rtp_kill ( RTPSession *session, Messenger *messenger )

View File

@ -31,10 +31,12 @@
#define MAX_SEQU_NUM 65535
#define MAX_RTP_SIZE 65535
typedef enum {
rtp_ErrorSending = -40
} RTPError;
/**
* 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) */
@ -46,7 +48,6 @@ typedef struct _RTPHeader {
} RTPHeader;
/**
* Standard rtp extension header.
*/
@ -57,7 +58,6 @@ typedef struct _RTPExtHeader {
} RTPExtHeader;
/**
* Standard rtp message.
*/
@ -71,14 +71,8 @@ typedef struct _RTPMessage {
struct _RTPMessage *next;
} RTPMessage;
/**
* 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.
*
* RTP control session.
*/
typedef struct _RTPSession {
uint8_t version;

View File

@ -42,9 +42,8 @@ typedef struct Messenger Tox;
/* Assume 24 fps*/
#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
/* call index invalid: true if invalid */
#define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls)
/* true if invalid call index */
#define CALL_INVALID_INDEX(idx, max) (idx < 0 || idx >= max)
const ToxAvCSettings av_DefaultSettings = {
av_TypeAudio,
@ -62,32 +61,28 @@ const ToxAvCSettings av_DefaultSettings = {
static const uint32_t jbuf_capacity = 6;
static const uint8_t audio_index = 0, video_index = 1;
typedef struct _CallSpecific {
typedef struct _ToxAvCall {
pthread_mutex_t mutex[1];
RTPSession *crtps[2]; /** Audio is first and video is second */
CSSession *cs;/** Each call have its own encoders and decoders.
* You can, but don't have to, reuse encoders for
* multiple calls. If you choose to reuse encoders,
* make sure to also reuse encoded payload for every call.
* Decoders have to be unique for each call.
*/
_Bool call_active;
pthread_mutex_t mutex;
} CallSpecific;
CSSession *cs;
_Bool active;
} ToxAvCall;
struct _ToxAv {
Messenger *messenger;
MSISession *msi_session; /** Main msi session */
CallSpecific *calls; /** Per-call params */
ToxAvCall *calls; /** Per-call params */
uint32_t max_calls;
PAIR(ToxAvAudioCallback, void*) acb;
PAIR(ToxAvVideoCallback, void*) vcb;
/* Decode time measure */
int32_t dectmsscount; /** Measure count */
int32_t dectmsstotal; /** Last cycle total */
int32_t avgdectms; /** Average decoding time in ms */
};
static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from)
{
assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
@ -101,7 +96,6 @@ static const ToxAvCSettings *toxavcsettings_cast (const MSICSettings *from)
}
ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
{
ToxAv *av = calloc ( sizeof(ToxAv), 1);
@ -114,14 +108,14 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
av->messenger = (Messenger *)messenger;
av->msi_session = msi_new(av->messenger, max_calls);
av->msi_session->agent_handler = av;
av->calls = calloc(sizeof(CallSpecific), max_calls);
av->calls = calloc(sizeof(ToxAvCall), max_calls);
av->max_calls = max_calls;
unsigned int i;
for (i = 0; i < max_calls; ++i) {
if (pthread_mutex_init(&av->calls[i].mutex, NULL) != 0 ) {
LOGGER_WARNING("Failed to init call mutex!");
if (create_recursive_mutex(av->calls[i].mutex) != 0 ) {
LOGGER_WARNING("Failed to init call(%u) mutex!", i);
msi_kill(av->msi_session);
free(av->calls);
@ -145,9 +139,10 @@ void toxav_kill ( ToxAv *av )
if ( av->calls[i].crtps[video_index] )
rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
if ( av->calls[i].cs ) cs_kill(av->calls[i].cs);
if ( av->calls[i].cs )
cs_kill(av->calls[i].cs);
pthread_mutex_destroy(&av->calls[i].mutex);
pthread_mutex_destroy(av->calls[i].mutex);
}
msi_kill(av->msi_session);
@ -161,16 +156,12 @@ uint32_t toxav_do_interval(ToxAv *av)
int i = 0;
uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */
for (; i < av->max_calls; i ++) if (av->calls[i].call_active) {
for (; i < av->max_calls; i ++) if (av->calls[i].active) {
/* This should work. Video payload will always come in greater intervals */
rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc);
}
if (rc < av->avgdectms) {
return 0;
} else {
return rc - av->avgdectms;
}
return rc < av->avgdectms ? 0 : rc - av->avgdectms;
}
void toxav_do(ToxAv *av)
@ -182,11 +173,12 @@ void toxav_do(ToxAv *av)
uint32_t i = 0;
for (; i < av->max_calls; i ++) {
pthread_mutex_lock(&av->calls[i].mutex);
pthread_mutex_lock(av->calls[i].mutex);
if (av->calls[i].call_active) cs_do(av->calls[i].cs);
if (av->calls[i].active)
cs_do(av->calls[i].cs);
pthread_mutex_unlock(&av->calls[i].mutex);
pthread_mutex_unlock(av->calls[i].mutex);
}
uint64_t end = current_time_monotonic();
@ -206,14 +198,16 @@ void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback cb, ToxAvCallb
msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata);
}
void toxav_register_audio_callback(ToxAvAudioCallback cb, void *userdata)
void toxav_register_audio_callback(ToxAv* av, ToxAvAudioCallback cb, void* userdata)
{
cs_register_audio_callback(cb, userdata);
av->acb.first = cb;
av->acb.second = userdata;
}
void toxav_register_video_callback(ToxAvVideoCallback cb, void *userdata)
void toxav_register_video_callback(ToxAv* av, ToxAvVideoCallback cb, void* userdata)
{
cs_register_video_callback(cb, userdata);
av->vcb.first = cb;
av->vcb.second = userdata;
}
int toxav_call (ToxAv *av,
@ -227,86 +221,46 @@ int toxav_call (ToxAv *av,
int toxav_hangup ( ToxAv *av, int32_t call_index )
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
return av_ErrorNoCall;
}
if ( av->msi_session->calls[call_index]->state != call_active ) {
return av_ErrorInvalidState;
}
return msi_hangup(av->msi_session, call_index);
}
int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings )
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
return av_ErrorNoCall;
}
if ( av->msi_session->calls[call_index]->state != call_starting ) {
return av_ErrorInvalidState;
}
return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings));
}
int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
return av_ErrorNoCall;
}
if ( av->msi_session->calls[call_index]->state != call_starting ) {
return av_ErrorInvalidState;
}
return msi_reject(av->msi_session, call_index, reason);
}
int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
return av_ErrorNoCall;
}
if ( av->msi_session->calls[call_index]->state != call_inviting ) {
return av_ErrorInvalidState;
}
return msi_cancel(av->msi_session, call_index, peer_id, reason);
}
int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings)
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
return av_ErrorNoCall;
}
return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings));
}
int toxav_stop_call ( ToxAv *av, int32_t call_index )
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
return av_ErrorNoCall;
}
return msi_stopcall(av->msi_session, call_index);
}
int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video )
{
if ( !av->msi_session || cii(call_index, av->msi_session) ||
!av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer ||
av->calls[call_index].call_active) {
if ( !av->msi_session || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) ||
!av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer ||
av->calls[call_index].active) {
LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
return av_ErrorInternal;
return av_ErrorNoCall;
}
CallSpecific *call = &av->calls[call_index];
ToxAvCall *call = &av->calls[call_index];
pthread_mutex_lock(&call->mutex);
pthread_mutex_lock(call->mutex);
const ToxAvCSettings *c_peer = toxavcsettings_cast
(&av->msi_session->calls[call_index]->csettings_peer[0]);
const ToxAvCSettings *c_self = toxavcsettings_cast
@ -332,27 +286,33 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_vide
if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ) {
LOGGER_ERROR("Error while starting Codec State!\n");
pthread_mutex_unlock(&call->mutex);
return av_ErrorInternal;
pthread_mutex_unlock(call->mutex);
return av_ErrorInitializingCodecs;
}
call->cs->agent = av;
call->cs->call_idx = call_index;
call->cs->acb.first = av->acb.first;
call->cs->acb.second = av->acb.second;
call->cs->vcb.first = av->vcb.first;
call->cs->vcb.second = av->vcb.second;
call->crtps[audio_index] =
rtp_new(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]);
rtp_new(msi_TypeAudio, av->messenger, av->msi_session->calls[call_index]->peers[0]);
if ( !call->crtps[audio_index] ) {
LOGGER_ERROR("Error while starting audio RTP session!\n");
pthread_mutex_unlock(&call->mutex);
return av_ErrorInternal;
goto error;
}
call->crtps[audio_index]->cs = call->cs;
if ( support_video ) {
call->crtps[video_index] =
rtp_new(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
rtp_new(msi_TypeVideo, av->messenger, av->msi_session->calls[call_index]->peers[0]);
if ( !call->crtps[video_index] ) {
LOGGER_ERROR("Error while starting video RTP session!\n");
@ -362,35 +322,37 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_vide
call->crtps[video_index]->cs = call->cs;
}
call->call_active = 1;
pthread_mutex_unlock(&call->mutex);
call->active = 1;
pthread_mutex_unlock(call->mutex);
return av_ErrorNone;
error:
rtp_kill(call->crtps[audio_index], av->messenger);
rtp_kill(call->crtps[video_index], av->messenger);
cs_kill(call->cs);
memset(call, 0, sizeof(CallSpecific));
memset(call, 0, sizeof(ToxAvCall));
pthread_mutex_unlock(&call->mutex);
return av_ErrorInternal;
pthread_mutex_unlock(call->mutex);
return av_ErrorCreatingRtpSessions;
}
int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
{
if (cii(call_index, av->msi_session)) {
if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) {
LOGGER_WARNING("Invalid call index: %d", call_index);
return av_ErrorNoCall;
}
CallSpecific *call = &av->calls[call_index];
ToxAvCall *call = &av->calls[call_index];
pthread_mutex_lock(&call->mutex);
pthread_mutex_lock(call->mutex);
if (!call->call_active) {
pthread_mutex_unlock(&call->mutex);
if (!call->active) {
pthread_mutex_unlock(call->mutex);
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
return av_ErrorInvalidState;
}
call->active = 0;
rtp_kill(call->crtps[audio_index], av->messenger);
call->crtps[audio_index] = NULL;
@ -398,20 +360,23 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
call->crtps[video_index] = NULL;
cs_kill(call->cs);
call->cs = NULL;
call->call_active = 0;
pthread_mutex_unlock(&call->mutex);
pthread_mutex_unlock(call->mutex);
return av_ErrorNone;
}
static int toxav_send_rtp_payload(ToxAv *av,
CallSpecific *call,
ToxAvCall *call,
ToxAvCallType type,
const uint8_t *payload,
unsigned int length)
{
if (length > MAX_CRYPTO_DATA_SIZE) {
LOGGER_WARNING("Size exceeds limit: %d", length);
return av_ErrorUnknown;
}
if (call->crtps[type - av_TypeAudio]) {
/* Audio */
@ -420,8 +385,7 @@ static int toxav_send_rtp_payload(ToxAv *av,
/* Video */
int parts = cs_split_video_payload(call->cs, payload, length);
if (parts == -1) return av_ErrorInternal;
if (parts < 0) return parts;
uint16_t part_size;
const uint8_t *iter;
@ -431,8 +395,8 @@ static int toxav_send_rtp_payload(ToxAv *av,
for (i = 0; i < parts; i++) {
iter = cs_get_split_video_frame(call->cs, &part_size);
if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) != 0)
return av_ErrorInternal;
if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0)
return av_ErrorSendingPayload;
}
return av_ErrorNone;
@ -442,32 +406,32 @@ static int toxav_send_rtp_payload(ToxAv *av,
int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
{
if (cii(call_index, av->msi_session)) {
if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) {
LOGGER_WARNING("Invalid call index: %d", call_index);
return av_ErrorNoCall;
}
CallSpecific *call = &av->calls[call_index];
pthread_mutex_lock(&call->mutex);
ToxAvCall *call = &av->calls[call_index];
pthread_mutex_lock(call->mutex);
if (!call->call_active) {
pthread_mutex_unlock(&call->mutex);
if (!call->active) {
pthread_mutex_unlock(call->mutex);
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
return av_ErrorInvalidState;
}
if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) {
pthread_mutex_unlock(&call->mutex);
return av_ErrorInternal;
if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) < 0) {
pthread_mutex_unlock(call->mutex);
return av_ErrorSettingVideoResolution;
}
int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
if ( rc != VPX_CODEC_OK) {
LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
pthread_mutex_unlock(&call->mutex);
return av_ErrorInternal;
pthread_mutex_unlock(call->mutex);
return av_ErrorEncodingVideo;
}
++call->cs->frame_counter;
@ -479,7 +443,7 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
if ( copied + pkt->data.frame.sz > dest_max ) {
pthread_mutex_unlock(&call->mutex);
pthread_mutex_unlock(call->mutex);
return av_ErrorPacketTooLarge;
}
@ -488,30 +452,30 @@ int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, in
}
}
pthread_mutex_unlock(&call->mutex);
pthread_mutex_unlock(call->mutex);
return copied;
}
int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size)
{
if (cii(call_index, av->msi_session)) {
if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) {
LOGGER_WARNING("Invalid call index: %d", call_index);
return av_ErrorNoCall;
}
CallSpecific *call = &av->calls[call_index];
pthread_mutex_lock(&call->mutex);
ToxAvCall *call = &av->calls[call_index];
pthread_mutex_lock(call->mutex);
if (!call->call_active) {
pthread_mutex_unlock(&call->mutex);
if (!call->active) {
pthread_mutex_unlock(call->mutex);
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
return av_ErrorInvalidState;
}
int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size);
pthread_mutex_unlock(&call->mutex);
pthread_mutex_unlock(call->mutex);
return rc;
}
@ -523,27 +487,27 @@ int toxav_prepare_audio_frame ( ToxAv *av,
const int16_t *frame,
int frame_size)
{
if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->calls[call_index].active) {
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
}
CallSpecific *call = &av->calls[call_index];
pthread_mutex_lock(&call->mutex);
ToxAvCall *call = &av->calls[call_index];
pthread_mutex_lock(call->mutex);
if (!call->call_active) {
pthread_mutex_unlock(&call->mutex);
if (!call->active) {
pthread_mutex_unlock(call->mutex);
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
return av_ErrorInvalidState;
}
int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
pthread_mutex_unlock(&call->mutex);
pthread_mutex_unlock(call->mutex);
if (rc < 0) {
LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
return av_ErrorInternal;
return av_ErrorEncodingAudio;
}
return rc;
@ -551,35 +515,32 @@ int toxav_prepare_audio_frame ( ToxAv *av,
int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size)
{
if (size > MAX_CRYPTO_DATA_SIZE)
return av_ErrorInternal;
if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->calls[call_index].active) {
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
}
CallSpecific *call = &av->calls[call_index];
pthread_mutex_lock(&call->mutex);
ToxAvCall *call = &av->calls[call_index];
pthread_mutex_lock(call->mutex);
if (!call->call_active) {
pthread_mutex_unlock(&call->mutex);
if (!call->active) {
pthread_mutex_unlock(call->mutex);
LOGGER_WARNING("Action on inactive call: %d", call_index);
return av_ErrorNoCall;
return av_ErrorInvalidState;
}
int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size);
pthread_mutex_unlock(&call->mutex);
pthread_mutex_unlock(call->mutex);
return rc;
}
int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest )
{
if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
|| av->msi_session->calls[call_index]->peer_count <= peer )
return av_ErrorInternal;
if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) ||
!av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
return av_ErrorNoCall;
*dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]);
return av_ErrorNone;
@ -587,16 +548,16 @@ int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSe
int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
{
if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index]
|| av->msi_session->calls[call_index]->peer_count <= peer )
return av_ErrorInternal;
return av_ErrorNoCall;
return av->msi_session->calls[call_index]->peers[peer];
}
ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
{
if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] )
if ( CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] )
return av_CallNonExistent;
return av->msi_session->calls[call_index]->state;
@ -605,7 +566,7 @@ ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
{
return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CsCapabilities) capability : 0;
return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CSCapabilities) capability : 0;
/* 0 is error here */
}
@ -614,35 +575,17 @@ Tox *toxav_get_tox(ToxAv *av)
return (Tox *)av->messenger;
}
int toxav_set_vad_treshold(ToxAv *av, int32_t call_index, uint32_t treshold)
{
if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
/* TODO on't use default framedur... */
cs_set_vad_treshold(av->calls[call_index].cs, treshold, av_DefaultSettings.audio_frame_duration);
return av_ErrorNone;
}
int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref)
{
if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
return cs_calculate_vad(av->calls[call_index].cs, PCM, frame_size, ref);
}
int toxav_get_active_count(ToxAv *av)
{
if (!av) return av_ErrorInternal;
if (!av) return -1;
int rc = 0, i = 0;
for (; i < av->max_calls; i ++) if (av->calls[i].call_active) rc++;
for (; i < av->max_calls; i ++) if (av->calls[i].active) rc++;
return rc;
}
/* Create a new toxav group.
*
* return group number on success.

View File

@ -81,17 +81,26 @@ typedef enum {
} ToxAvCallState;
/**
* Error indicators.
* Error indicators. Values under -20 are reserved for toxcore.
*/
typedef enum {
av_ErrorNone = 0,
av_ErrorInternal = -1, /* Internal error */
av_ErrorAlreadyInCall = -2, /* Already has an active call */
av_ErrorNoCall = -3, /* Trying to perform call action while not in a call */
av_ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/
av_ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */
av_ErrorInvalidCodecState = -6, /* Codec state not initialized */
av_ErrorPacketTooLarge = -7, /* Split packet exceeds it's limit */
av_ErrorUnknown = -1, /* Unknown error */
av_ErrorNoCall = -20, /* Trying to perform call action while not in a call */
av_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/
av_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */
av_ErrorReachedCallLimit = -23, /* Cannot handle more calls */
av_ErrorInitializingCodecs = -30, /* Failed creating CSSession */
av_ErrorSettingVideoResolution = -31, /* Error setting resolution */
av_ErrorSettingVideoBitrate = -32, /* Error setting bitrate */
av_ErrorSplittingVideoPayload = -33, /* Error splitting video payload */
av_ErrorEncodingVideo = -34, /* vpx_codec_encode failed */
av_ErrorEncodingAudio = -35, /* opus_encode failed */
av_ErrorSendingPayload = -40, /* Sending lossy packet failed */
av_ErrorCreatingRtpSessions = -41, /* One of the rtp sessions failed to initialize */
av_ErrorNoRtpSession = -50, /* Trying to perform rtp action on invalid session */
av_ErrorInvalidCodecState = -51, /* Codec state not initialized */
av_ErrorPacketTooLarge = -52, /* Split packet exceeds it's limit */
} ToxAvError;
@ -153,12 +162,12 @@ void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback cb, ToxAvCallba
/**
* Register callback for audio data.
*/
void toxav_register_audio_callback (ToxAvAudioCallback cb, void *userdata);
void toxav_register_audio_callback (ToxAv *av, ToxAvAudioCallback cb, void *userdata);
/**
* Register callback for video data.
*/
void toxav_register_video_callback (ToxAvVideoCallback cb, void *userdata);
void toxav_register_video_callback (ToxAv *av, ToxAvVideoCallback cb, void *userdata);
/**
* Call user. Use its friend_id.
@ -266,18 +275,6 @@ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilitie
*/
Tox *toxav_get_tox (ToxAv *av);
/**
* Set VAD activity treshold for calculating VAD. 40 is some middle value for treshold
*/
int toxav_set_vad_treshold (ToxAv *av, int32_t call_index, uint32_t treshold);
/**
* Check if there is activity in the PCM data.
* Activity is present if the calculated PCM energy is > ref_energy.
* Returns bool.
*/
int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref);
/**
* Returns number of active calls or -1 on error.
*/

View File

@ -2696,22 +2696,12 @@ Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info)
if (temp == NULL)
return NULL;
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) == 0) {
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 || pthread_mutex_init(&temp->tcp_mutex, &attr) != 0
|| pthread_mutex_init(&temp->connections_mutex, NULL) != 0) {
pthread_mutexattr_destroy(&attr);
if (create_recursive_mutex(&temp->tcp_mutex) != 0 ||
pthread_mutex_init(&temp->connections_mutex, NULL) != 0) {
free(temp);
return NULL;
}
} else {
free(temp);
return NULL;
}
pthread_mutexattr_destroy(&attr);
temp->dht = dht;
new_keys(temp);

View File

@ -162,3 +162,22 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
return length == 0 ? 0 : -1;
};
int create_recursive_mutex(pthread_mutex_t* mutex)
{
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0)
return -1;
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
return -1;
/* Create queue mutex */
if (pthread_mutex_init(mutex, &attr) != 0)
return -1;
pthread_mutexattr_destroy(&attr);
return 0;
}

View File

@ -27,6 +27,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
@ -52,4 +53,6 @@ typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32
int load_state(load_state_callback_func load_state_callback, void *outer,
const uint8_t *data, uint32_t length, uint16_t cookie_inner);
int create_recursive_mutex(pthread_mutex_t* mutex);
#endif /* __UTIL_H__ */