mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
More av cleanup
This commit is contained in:
parent
975ce25af0
commit
e62ded3a6d
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
|
190
toxav/codec.c
190
toxav/codec.c
|
@ -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 {
|
||||
|
|
|
@ -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_ */
|
||||
|
|
205
toxav/msi.c
205
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);
|
||||
}
|
||||
|
|
52
toxav/msi.h
52
toxav/msi.h
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
320
toxav/rtp.c
320
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 )
|
||||
|
|
14
toxav/rtp.h
14
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;
|
||||
|
|
291
toxav/toxav.c
291
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.
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in New Issue
Block a user