From e62ded3a6dfc1203418e3d7a2c936794c4c9ec1c Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 29 Nov 2014 13:42:19 +0100 Subject: [PATCH] More av cleanup --- auto_tests/toxav_basic_test.c | 4 +- auto_tests/toxav_many_test.c | 4 +- toxav/codec.c | 190 ++++++-------------- toxav/codec.h | 43 +++-- toxav/msi.c | 205 +++++++++++----------- toxav/msi.h | 52 +++--- toxav/rtp.c | 320 +++++++++++++++++----------------- toxav/rtp.h | 14 +- toxav/toxav.c | 291 +++++++++++++------------------ toxav/toxav.h | 41 ++--- toxcore/net_crypto.c | 16 +- toxcore/util.c | 19 ++ toxcore/util.h | 3 + 13 files changed, 546 insertions(+), 656 deletions(-) diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c index c5a9a3db..db1db3fb 100644 --- a/auto_tests/toxav_basic_test.c +++ b/auto_tests/toxav_basic_test.c @@ -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); } diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c index 4e3567d7..99012992 100644 --- a/auto_tests/toxav_many_test.c +++ b/auto_tests/toxav_many_test.c @@ -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); } /*************************************************************************************************/ diff --git a/toxav/codec.c b/toxav/codec.c index 2849ed69..020cde81 100644 --- a/toxav/codec.c +++ b/toxav/codec.c @@ -27,6 +27,7 @@ #endif /* HAVE_CONFIG_H */ #include "../toxcore/logger.h" +#include "../toxcore/util.h" #include #include @@ -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 { diff --git a/toxav/codec.h b/toxav/codec.h index dd054338..432bb847 100644 --- a/toxav/codec.h +++ b/toxav/codec.h @@ -42,16 +42,33 @@ /* Audio encoding/decoding */ #include +#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_ */ diff --git a/toxav/msi.c b/toxav/msi.c index a80c4b30..00e18f4f 100644 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -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); } diff --git a/toxav/msi.h b/toxav/msi.h index d63f2441..b222655f 100644 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -25,6 +25,7 @@ #include #include +#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; /** diff --git a/toxav/rtp.c b/toxav/rtp.c index 328eb676..a1969fa6 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -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, ×tamp, sizeof(timestamp)); - _it += 4; + memcpy(it, ×tamp, 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 ) diff --git a/toxav/rtp.h b/toxav/rtp.h index 613fbec8..c98840ac 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h @@ -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; diff --git a/toxav/toxav.c b/toxav/toxav.c index 11f709b9..43b2eca5 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -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. diff --git a/toxav/toxav.h b/toxav/toxav.h index a271e1f3..3696f961 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -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. */ diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 2f125fdc..a7915493 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -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); diff --git a/toxcore/util.c b/toxcore/util.c index 3d444b07..d7ae016f 100644 --- a/toxcore/util.c +++ b/toxcore/util.c @@ -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; +} diff --git a/toxcore/util.h b/toxcore/util.h index 007db079..3734e9da 100644 --- a/toxcore/util.h +++ b/toxcore/util.h @@ -27,6 +27,7 @@ #include #include +#include #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__ */