Merge pull request #789 from mannol1/master

Fixed several bugs and added some features
This commit is contained in:
irungentoo 2014-03-07 11:11:17 -05:00
commit b451565f17
11 changed files with 493 additions and 224 deletions

View File

@ -487,7 +487,8 @@ fi
if test "x$BUILD_AV" = "xyes"; then
# toxcore lib needs an global?
# So far this works okay
AV_LIBS="$OPUS_LIBS $VPX_LIBS"
## What about pthread?
AV_LIBS="$OPUS_LIBS $VPX_LIBS -pthread"
AC_SUBST(AV_LIBS)
AV_CFLAGS="$OPUS_CFLAGS $VPX_CFLAGS"

11
libtoxav.pc Normal file
View File

@ -0,0 +1,11 @@
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: libtoxav
Description: Tox A/V library
Requires:
Version: 0.0.0
Libs: -L${libdir} -ltoxav -lopus -lvpx -lm -pthread
Cflags: -I${includedir}

View File

@ -46,18 +46,28 @@ struct jitter_buffer {
uint8_t id_set;
};
int empty_queue(struct jitter_buffer *q)
{
while (q->size > 0) {
rtp_free_msg(NULL, q->queue[q->front]);
q->front++;
if (q->front == q->capacity)
q->front = 0;
q->size--;
}
q->id_set = 0;
q->queue_ready = 0;
return 0;
}
struct jitter_buffer *create_queue(int capacity)
{
struct jitter_buffer *q;
q = (struct jitter_buffer *)calloc(sizeof(struct jitter_buffer), 1);
q->queue = (RTPMessage **)calloc(sizeof(RTPMessage *), capacity);
int i = 0;
for (i = 0; i < capacity; ++i) {
q->queue[i] = NULL;
}
q = calloc(sizeof(struct jitter_buffer), 1);
q->queue = calloc(sizeof(RTPMessage *), capacity);
q->size = 0;
q->capacity = capacity;
q->front = 0;
@ -81,7 +91,7 @@ uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint3
/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
RTPMessage *dequeue(struct jitter_buffer *q, int *success)
{
if (q->size == 0 || q->queue_ready == 0) {
if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */
q->queue_ready = 0;
*success = 0;
return NULL;
@ -103,13 +113,13 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
q->current_ts = next_ts;
} else {
if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) {
printf("nextid: %d current: %d\n", next_id, q->current_id);
/*printf("nextid: %d current: %d\n", next_id, q->current_id);*/
q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
*success = 2; /* tell the decoder the packet is lost */
return NULL;
} else {
/* packet too old */
printf("packet too old\n");
/*printf("packet too old\n");*/
*success = 0;
return NULL;
}
@ -128,27 +138,12 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
return q->queue[front];
}
int empty_queue(struct jitter_buffer *q)
{
while (q->size > 0) {
q->size--;
rtp_free_msg(NULL, q->queue[q->front]);
q->front++;
if (q->front == q->capacity)
q->front = 0;
}
q->id_set = 0;
q->queue_ready = 0;
return 0;
}
int queue(struct jitter_buffer *q, RTPMessage *pk)
{
if (q->size == q->capacity) {
printf("buffer full, emptying buffer...\n");
if (q->size == q->capacity) { /* Full, empty queue */
empty_queue(q);
/*rtp_free_msg(NULL, pk);*/
return 0;
}
@ -180,7 +175,7 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
temp = q->queue[a];
q->queue[a] = q->queue[b];
q->queue[b] = temp;
printf("had to swap\n");
/*printf("had to swap\n");*/
} else {
break;
}
@ -229,7 +224,7 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
if (res) {
printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res));
return -1;
}
@ -266,49 +261,43 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
uint16_t video_height,
uint32_t video_bitrate )
{
CodecState *_retu = calloc(sizeof(CodecState), 1);
assert(_retu);
CodecState *retu = calloc(sizeof(CodecState), 1);
assert(retu);
_retu->audio_bitrate = audio_bitrate;
_retu->audio_sample_rate = audio_sample_rate;
retu->audio_bitrate = audio_bitrate;
retu->audio_sample_rate = audio_sample_rate;
/* Encoders */
if (!video_width || !video_height) {
video_width = 320;
video_height = 240;
if (!video_width || !video_height) { /* Disable video */
/*video_width = 320;
video_height = 240; */
}
else {
retu->supported_actions |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0;
retu->supported_actions |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
}
if ( 0 == init_video_encoder(_retu, video_width, video_height, video_bitrate) )
printf("Video encoder initialized!\n");
retu->supported_actions |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0;
retu->supported_actions |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0;
if ( 0 == init_audio_encoder(_retu, audio_channels) )
printf("Audio encoder initialized!\n");
/* Decoders */
if ( 0 == init_video_decoder(_retu) )
printf("Video decoder initialized!\n");
if ( 0 == init_audio_decoder(_retu, audio_channels) )
printf("Audio decoder initialized!\n");
return _retu;
return retu;
}
void codec_terminate_session ( CodecState *cs )
{
if ( cs->audio_encoder ) {
if ( cs->audio_encoder )
opus_encoder_destroy(cs->audio_encoder);
printf("Terminated encoder!\n");
}
if ( cs->audio_decoder ) {
if ( cs->audio_decoder )
opus_decoder_destroy(cs->audio_decoder);
printf("Terminated decoder!\n");
}
/* TODO: Terminate video */
vpx_codec_destroy(&cs->v_decoder);
vpx_codec_destroy(&cs->v_encoder);
/* TODO: Terminate video
* Do what???
*/
if ( cs->supported_actions & v_decoding )
vpx_codec_destroy(&cs->v_decoder);
if ( cs->supported_actions & v_encoding )
vpx_codec_destroy(&cs->v_encoder);
}

View File

@ -38,6 +38,14 @@
/* Audio encoding/decoding */
#include <opus/opus.h>
enum _actions
{
no_actions,
a_encoding = 1 << 0,
a_decoding = 1 << 1,
v_encoding = 1 << 2,
v_decoding = 1 << 3
};
typedef struct _CodecState {
@ -56,12 +64,13 @@ typedef struct _CodecState {
/* audio decoding */
OpusDecoder *audio_decoder;
uint64_t supported_actions; /* Encoding decoding etc */
} CodecState;
typedef struct _RTPMessage RTPMessage;
struct jitter_buffer *create_queue(int capacity);
int empty_queue(struct jitter_buffer *q);
int queue(struct jitter_buffer *q, RTPMessage *pk);
RTPMessage *dequeue(struct jitter_buffer *q, int *success);

102
toxav/msi.c Normal file → Executable file
View File

@ -616,10 +616,15 @@ int send_message ( MSISession *session, MSIMessage *msg, uint32_t to )
void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id )
{
if ( msg->calltype.header_value ) {
if ( strcmp ( ( const char * ) msg->calltype.header_value, CT_AUDIO_HEADER_VALUE ) == 0 ) {
uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */
memcpy(hdrval, msg->calltype.header_value, msg->calltype.size);
hdrval[msg->calltype.size] = '\0';
if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
session->call->type_peer[peer_id] = type_audio;
} else if ( strcmp ( ( const char * ) msg->calltype.header_value, CT_VIDEO_HEADER_VALUE ) == 0 ) {
} else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) {
session->call->type_peer[peer_id] = type_video;
} else {} /* Error */
} else {} /* Error */
@ -670,7 +675,7 @@ int handle_error ( MSISession *session, MSICallError errid, uint32_t to )
session->last_error_id = errid;
session->last_error_str = stringify_error ( errid );
event.rise ( callbacks[MSI_OnError], session->agent_handler );
if ( callbacks[MSI_OnError] ) event.rise ( callbacks[MSI_OnError], session->agent_handler );
return 0;
}
@ -723,12 +728,12 @@ void *handle_timeout ( void *arg )
uint16_t _it = 0;
for ( ; _it < _peer_count; _it++ )
msi_cancel ( arg, _peers[_it], (const uint8_t *)"Timeout" );
msi_cancel ( arg, _peers[_it], "Timeout" );
}
( *callbacks[MSI_OnRequestTimeout] ) ( _session->agent_handler );
( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler );
if ( callbacks[MSI_OnRequestTimeout] ) callbacks[MSI_OnRequestTimeout] ( _session->agent_handler );
if ( callbacks[MSI_OnEnding] ) callbacks[MSI_OnEnding ] ( _session->agent_handler );
return NULL;
}
@ -864,7 +869,7 @@ int handle_recv_invite ( MSISession *session, MSIMessage *msg )
send_message ( session, _msg_ringing, msg->friend_id );
free_message ( _msg_ringing );
event.rise ( callbacks[MSI_OnInvite], session->agent_handler );
if ( callbacks[MSI_OnInvite] ) event.rise ( callbacks[MSI_OnInvite], session->agent_handler );
return 1;
}
@ -888,7 +893,7 @@ int handle_recv_start ( MSISession *session, MSIMessage *msg )
flush_peer_type ( session, msg, 0 );
event.rise ( callbacks[MSI_OnStart], session->agent_handler );
if ( callbacks[MSI_OnStart] ) event.rise ( callbacks[MSI_OnStart], session->agent_handler );
return 1;
}
@ -905,7 +910,7 @@ int handle_recv_reject ( MSISession *session, MSIMessage *msg )
free_message ( _msg_end );
event.timer_release ( session->call->request_timer_id );
event.rise ( callbacks[MSI_OnReject], session->agent_handler );
if ( callbacks[MSI_OnReject] ) event.rise ( callbacks[MSI_OnReject], session->agent_handler );
session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
return 1;
@ -920,7 +925,7 @@ int handle_recv_cancel ( MSISession *session, MSIMessage *msg )
terminate_call ( session );
event.rise ( callbacks[MSI_OnCancel], session->agent_handler );
if ( callbacks[MSI_OnCancel] ) event.rise ( callbacks[MSI_OnCancel], session->agent_handler );
return 1;
}
@ -938,7 +943,7 @@ int handle_recv_end ( MSISession *session, MSIMessage *msg )
terminate_call ( session );
event.rise ( callbacks[MSI_OnEnd], session->agent_handler );
if ( callbacks[MSI_OnEnd] ) event.rise ( callbacks[MSI_OnEnd], session->agent_handler );
return 1;
}
@ -952,7 +957,7 @@ int handle_recv_ringing ( MSISession *session, MSIMessage *msg )
return 0;
session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms );
event.rise ( callbacks[MSI_OnRinging], session->agent_handler );
if ( callbacks[MSI_OnRinging] ) event.rise ( callbacks[MSI_OnRinging], session->agent_handler );
return 1;
}
@ -991,7 +996,7 @@ int handle_recv_starting ( MSISession *session, MSIMessage *msg )
flush_peer_type ( session, msg, 0 );
event.rise ( callbacks[MSI_OnStarting], session->agent_handler );
if ( callbacks[MSI_OnStarting] ) event.rise ( callbacks[MSI_OnStarting], session->agent_handler );
event.timer_release ( session->call->ringing_timer_id );
return 1;
@ -999,15 +1004,23 @@ int handle_recv_starting ( MSISession *session, MSIMessage *msg )
int handle_recv_ending ( MSISession *session, MSIMessage *msg )
{
assert ( session );
if ( has_call_error ( session, msg ) == 0 )
return 0;
/* Do the callback before ending
if ( callbacks[MSI_OnEnding] ) event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
*/
/* Stop timer */
event.timer_release ( session->call->request_timer_id );
/* Call callback */
if ( callbacks[MSI_OnEnding] ) callbacks[MSI_OnEnding](session->agent_handler);
/* Terminate call */
terminate_call ( session );
event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
return 1;
}
int handle_recv_error ( MSISession *session, MSIMessage *msg )
@ -1023,7 +1036,7 @@ int handle_recv_error ( MSISession *session, MSIMessage *msg )
terminate_call ( session );
event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
if ( callbacks[MSI_OnEnding] ) event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
return 1;
}
@ -1081,8 +1094,13 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
/* Now handle message */
if ( _msg->request.header_value ) { /* Handle request */
const uint8_t *_request_value = _msg->request.header_value;
if ( _msg->response.size > 32 ) goto free_end;
uint8_t _request_value[32];
memcpy(_request_value, _msg->request.header_value, _msg->request.size);
_request_value[_msg->request.size] = '\0';
if ( same ( _request_value, stringify_request ( invite ) ) ) {
handle_recv_invite ( _session, _msg );
@ -1100,15 +1118,17 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
handle_recv_end ( _session, _msg );
}
else {
free_message ( _msg );
return;
}
else goto free_end;
} else if ( _msg->response.header_value ) { /* Handle response */
const uint8_t *_response_value = _msg->response.header_value;
if ( _msg->response.size > 32 ) goto free_end;
uint8_t _response_value[32];
memcpy(_response_value, _msg->response.header_value, _msg->response.size);
_response_value[_msg->response.size] = '\0';
if ( same ( _response_value, stringify_response ( ringing ) ) ) {
handle_recv_ringing ( _session, _msg );
@ -1120,10 +1140,8 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
} else if ( same ( _response_value, stringify_response ( error ) ) ) {
handle_recv_error ( _session, _msg );
} else {
free_message ( _msg );
return;
}
} else goto free_end;
/* Got response so cancel timer */
if ( _session->call )
@ -1131,7 +1149,7 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
}
free_message ( _msg );
free_end:free_message ( _msg );
}
@ -1286,19 +1304,19 @@ int msi_hangup ( MSISession *session )
if ( !session->call || session->call->state != call_active )
return -1;
MSIMessage *_msg_ending = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) );
MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) );
/* hangup for each peer */
int _it = 0;
for ( ; _it < session->call->peer_count; _it ++ )
send_message ( session, _msg_end, session->call->peers[_it] );
for ( ; _it < session->call->peer_count; _it ++ )
send_message ( session, _msg_ending, session->call->peers[_it] );
free_message ( _msg_ending );
free_message ( _msg_end );
session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
return 0;
}
@ -1352,13 +1370,13 @@ int msi_answer ( MSISession *session, MSICallType call_type )
* @param reason Set optional reason header. Pass NULL if none.
* @return int
*/
int msi_cancel ( MSISession *session, uint32_t peer, const uint8_t *reason )
int msi_cancel ( MSISession *session, uint32_t peer, const char *reason )
{
assert ( session );
MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) );
if ( reason ) msi_msg_set_reason(_msg_cancel, reason, strlen((const char *)reason));
if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t*)reason, strlen(reason));
send_message ( session, _msg_cancel, peer );
free_message ( _msg_cancel );

2
toxav/msi.h Normal file → Executable file
View File

@ -206,7 +206,7 @@ int msi_answer ( MSISession *session, MSICallType call_type );
* @param reason Set optional reason header. Pass NULL if none.
* @return int
*/
int msi_cancel ( MSISession *session, uint32_t peer, const uint8_t *reason );
int msi_cancel ( MSISession* session, uint32_t peer, const char* reason );
/**

174
toxav/phone.c Normal file → Executable file
View File

@ -428,17 +428,16 @@ void *encode_audio_thread(void *arg)
int frame_size = AUDIO_FRAME_SIZE;
ALint sample = 0;
alcCaptureStart((ALCdevice *)_phone->audio_capture_device);
while (_phone->running_encaud) {
alcGetIntegerv((ALCdevice *)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
if (sample >= frame_size) {
alcCaptureSamples((ALCdevice *)_phone->audio_capture_device, frame, frame_size);
ret = toxav_send_audio(_phone->av, frame, frame_size);
if (ret < 0)
printf("Could not encode or send audio packet\n");
if (ret < 0) printf("Could not encode or send audio packet\n");
} else {
usleep(1000);
@ -734,6 +733,114 @@ ending:
void *one_threaded_audio(void *arg)
{
INFO("Started audio thread!");
av_session_t *_phone = arg;
_phone->running_decaud = 1;
//int recved_size;
//uint8_t dest [RTP_PAYLOAD_SIZE];
int frame_size = AUDIO_FRAME_SIZE;
int16_t frame[4096];
ALint sample = 0;
alcCaptureStart((ALCdevice *)_phone->audio_capture_device);
ALCdevice *dev;
ALCcontext *ctx;
ALuint source, *buffers;
dev = alcOpenDevice(NULL);
ctx = alcCreateContext(dev, NULL);
alcMakeContextCurrent(ctx);
int openal_buffers = 5;
buffers = calloc(sizeof(ALuint) * openal_buffers, 1);
alGenBuffers(openal_buffers, buffers);
alGenSources((ALuint)1, &source);
alSourcei(source, AL_LOOPING, AL_FALSE);
ALuint buffer;
ALint ready;
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size);
int16_t PCM[frame_size];
int i;
for (i = 0; i < openal_buffers; ++i) {
alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
}
alSourceQueueBuffers(source, openal_buffers, buffers);
alSourcePlay(source);
if (alGetError() != AL_NO_ERROR) {
fprintf(stderr, "Error starting audio\n");
goto ending;
}
int dec_frame_len;
while (_phone->running_decaud) {
// combo
alcGetIntegerv((ALCdevice *)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
// record and send
if (sample >= frame_size) {
alcCaptureSamples((ALCdevice *)_phone->audio_capture_device, frame, frame_size);
if (toxav_send_audio(_phone->av, frame, frame_size) < 0)
printf("Could not encode or send audio packet\n");
} else {
usleep(5000);
}
// play received
alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
if (ready <= 0)
continue;
dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM);
/* Play the packet */
if (dec_frame_len > 0) {
alSourceUnqueueBuffers(source, 1, &buffer);
alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000);
int error = alGetError();
if (error != AL_NO_ERROR) {
fprintf(stderr, "Error setting buffer %d\n", error);
break;
}
alSourceQueueBuffers(source, 1, &buffer);
if (alGetError() != AL_NO_ERROR) {
fprintf(stderr, "Error: could not buffer audio\n");
break;
}
alGetSourcei(source, AL_SOURCE_STATE, &ready);
if (ready != AL_PLAYING) alSourcePlay(source);
}
usleep(1000);
}
ending:
_phone->running_decaud = -1;
pthread_exit ( NULL );
}
int phone_startmedia_loop ( ToxAv *arg )
@ -742,7 +849,7 @@ int phone_startmedia_loop ( ToxAv *arg )
return -1;
}
toxav_prepare_transmission(arg);
toxav_prepare_transmission(arg, 1);
/*
* Rise all threads
@ -759,10 +866,10 @@ int phone_startmedia_loop ( ToxAv *arg )
#endif
/* Always send audio */
if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) {
/*if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) {
INFO("Error while starting encode_audio_thread()");
return -1;
}
} */
/* Only checks for last peer */
if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
@ -771,12 +878,19 @@ int phone_startmedia_loop ( ToxAv *arg )
return -1;
}
if ( 0 > event.rise(decode_audio_thread, toxav_get_agent_handler(arg)) ) {
/*if ( 0 > event.rise(decode_audio_thread, toxav_get_agent_handler(arg)) ) {
INFO("Error while starting decode_audio_thread()");
return -1;
} */
/* One threaded audio */
if ( 0 > event.rise(one_threaded_audio, toxav_get_agent_handler(arg)) ) {
INFO ("Shit-head");
return -1;
}
return 0;
}
@ -888,15 +1002,17 @@ void *callback_call_ended ( void *_arg )
_phone->running_encvid = 0;
_phone->running_decvid = 0;
/* Wait until all threads are done */
/* Wait until all threads are done
while ( _phone->running_encaud != -1 ||
_phone->running_decaud != -1 ||
_phone->running_encvid != -1 ||
_phone->running_decvid != -1 )
usleep(10000000);
usleep(1000000);*/
while (_phone->running_decaud != -1) usleep(1000000);
toxav_kill_transmission(_phone->av);
INFO ( "Call ended!" );
pthread_exit(NULL);
@ -977,7 +1093,7 @@ av_session_t *av_init_session()
if (avformat_open_input(&_retu->video_format_ctx, DEFAULT_WEBCAM, _retu->video_input_format, NULL) != 0) {
fprintf(stderr, "Opening video_input_format failed!\n");
//return -1;
return NULL;
goto failed_init_ffmpeg;
}
avformat_find_stream_info(_retu->video_format_ctx, NULL);
@ -996,23 +1112,25 @@ av_session_t *av_init_session()
if (_retu->webcam_decoder == NULL) {
fprintf(stderr, "Unsupported codec!\n");
//return -1;
return NULL;
goto failed_init_ffmpeg;
}
if (_retu->webcam_decoder_ctx == NULL) {
fprintf(stderr, "Init webcam_decoder_ctx failed!\n");
//return -1;
return NULL;
goto failed_init_ffmpeg;
}
if (avcodec_open2(_retu->webcam_decoder_ctx, _retu->webcam_decoder, NULL) < 0) {
fprintf(stderr, "Opening webcam decoder failed!\n");
//return -1;
return NULL;
goto failed_init_ffmpeg;
}
width = _retu->webcam_decoder_ctx->width;
height = _retu->webcam_decoder_ctx->height;
failed_init_ffmpeg: ;
#endif
uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(_retu->_messenger, _byte_address );
@ -1023,18 +1141,18 @@ av_session_t *av_init_session()
/* ------------------ */
toxav_register_callstate_callback(callback_call_started, OnStart);
toxav_register_callstate_callback(callback_call_canceled, OnCancel);
toxav_register_callstate_callback(callback_call_rejected, OnReject);
toxav_register_callstate_callback(callback_call_ended, OnEnd);
toxav_register_callstate_callback(callback_recv_invite, OnInvite);
toxav_register_callstate_callback(callback_call_started, av_OnStart);
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel);
toxav_register_callstate_callback(callback_call_rejected, av_OnReject);
toxav_register_callstate_callback(callback_call_ended, av_OnEnd);
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite);
toxav_register_callstate_callback(callback_recv_ringing, OnRinging);
toxav_register_callstate_callback(callback_recv_starting, OnStarting);
toxav_register_callstate_callback(callback_recv_ending, OnEnding);
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging);
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting);
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding);
toxav_register_callstate_callback(callback_recv_error, OnError);
toxav_register_callstate_callback(callback_requ_timeout, OnRequestTimeout);
toxav_register_callstate_callback(callback_recv_error, av_OnError);
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout);
/* ------------------ */
@ -1310,6 +1428,8 @@ int main ( int argc, char *argv [] )
av_session_t *_phone = av_init_session();
assert ( _phone );
tox_callback_friend_request(_phone->_messenger, av_friend_requ, _phone);
tox_callback_status_message(_phone->_messenger, av_friend_active, _phone);
@ -1341,7 +1461,7 @@ int main ( int argc, char *argv [] )
"================================================================================\n"
"%s\n"
"================================================================================"
, _phone->_my_public_id );
, trim_spaces(_phone->_my_public_id) );
do_phone (_phone);

62
toxav/rtp.c Normal file → Executable file
View File

@ -262,17 +262,8 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
return NULL;
}
if ( _cc > 0 ) {
_retu->csrc = calloc (_cc, sizeof (uint32_t));
assert(_retu->csrc);
} else { /* But this should not happen ever */
/* Deallocate */
free(_retu);
return NULL;
}
memset(_retu->csrc, 0, 16);
_retu->marker_payloadt = *_it;
++_it;
_retu->length = _length;
@ -362,13 +353,11 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
_it += 4;
U32_to_bytes( _it, header->ssrc);
if ( header->csrc ) {
uint8_t _x;
uint8_t _x;
for ( _x = 0; _x < _cc; _x++ ) {
_it += 4;
U32_to_bytes( _it, header->csrc[_x]);
}
for ( _x = 0; _x < _cc; _x++ ) {
_it += 4;
U32_to_bytes( _it, header->csrc[_x]);
}
return _it + 4;
@ -424,19 +413,11 @@ RTPHeader *build_header ( RTPSession *session )
_retu->timestamp = ((uint32_t)(current_time() / 1000)); /* micro to milli */
_retu->ssrc = session->ssrc;
if ( session->cc > 0 ) {
_retu->csrc = calloc(session->cc, sizeof (uint32_t));
assert(_retu->csrc);
int i;
for ( i = 0; i < session->cc; i++ ) {
_retu->csrc[i] = session->csrc[i];
}
} else {
_retu->csrc = NULL;
}
int i;
for ( i = 0; i < session->cc; i++ )
_retu->csrc[i] = session->csrc[i];
_retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
return _retu;
@ -480,9 +461,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
_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 */
free (_retu->ext_header);
free (_retu->header);
free (_retu);
rtp_free_msg(NULL, _retu);
return NULL;
}
} else {
@ -545,7 +524,7 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l
_decrypted_length = decrypt_data_symmetric(
(uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain );
if ( !_decrypted_length ) return -1; /* This packet is not encrypted properly */
if ( _decrypted_length == -1 ) return -1; /* This packet is not encrypted properly */
/* Otherwise, if decryption is ok with new cycle, set new cycle
*/
@ -554,7 +533,7 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l
_decrypted_length = decrypt_data_symmetric(
(uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
if ( !_decrypted_length ) return -1; /* This is just an error */
if ( _decrypted_length == -1 ) return -1; /* This is just an error */
/* A new cycle setting. */
memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_secretbox_NONCEBYTES);
@ -801,16 +780,11 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
{
if ( !session ) {
free ( msg->header->csrc );
if ( msg->ext_header ) {
free ( msg->ext_header->table );
free ( msg->ext_header );
}
} else {
if ( session->csrc != msg->header->csrc )
free ( msg->header->csrc );
if ( msg->ext_header && session->ext_header != msg->ext_header ) {
free ( msg->ext_header->table );
free ( msg->ext_header );
@ -917,15 +891,21 @@ int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
{
if ( !session )
return -1;
custom_user_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
rtp_release_session_recv(session);
pthread_mutex_lock(&session->mutex);
free ( session->ext_header );
free ( session->csrc );
free ( session->decrypt_nonce );
free ( session->encrypt_nonce );
free ( session->nonce_cycle );
pthread_mutex_unlock(&session->mutex);
pthread_mutex_destroy(&session->mutex);
/* And finally free session */

14
toxav/rtp.h Normal file → Executable file
View File

@ -42,13 +42,13 @@
*/
typedef struct _RTPHeader {
uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */
uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */
uint16_t sequnum; /* Sequence Number */
uint32_t timestamp; /* Timestamp */
uint32_t ssrc; /* SSRC */
uint32_t *csrc; /* CSRC's table */
uint32_t length; /* Length of the header in payload string. */
uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */
uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */
uint16_t sequnum; /* Sequence Number */
uint32_t timestamp; /* Timestamp */
uint32_t ssrc; /* SSRC */
uint32_t csrc[16]; /* CSRC's table */
uint32_t length; /* Length of the header in payload string. */
} RTPHeader;

139
toxav/toxav.c Normal file → Executable file
View File

@ -241,7 +241,7 @@ int toxav_cancel ( ToxAv *av, const char *reason )
return ErrorNoCall;
}
return msi_cancel(av->msi_session, 0, (const uint8_t *)reason);
return msi_cancel(av->msi_session, 0, reason);
}
/**
@ -269,7 +269,7 @@ int toxav_stop_call ( ToxAv *av )
* @retval 0 Success.
* @retval ToxAvError On error.
*/
int toxav_prepare_transmission ( ToxAv *av )
int toxav_prepare_transmission ( ToxAv* av, int support_video )
{
assert(av->msi_session);
@ -293,22 +293,23 @@ int toxav_prepare_transmission ( ToxAv *av )
return ErrorStartingAudioRtp;
}
av->rtp_sessions[video_index] = rtp_init_session (
type_video,
av->messenger,
av->msi_session->call->peers[0],
av->msi_session->call->key_peer,
av->msi_session->call->key_local,
av->msi_session->call->nonce_peer,
av->msi_session->call->nonce_local
);
if ( support_video ) {
av->rtp_sessions[video_index] = rtp_init_session (
type_video,
av->messenger,
av->msi_session->call->peers[0],
av->msi_session->call->key_peer,
av->msi_session->call->key_local,
av->msi_session->call->nonce_peer,
av->msi_session->call->nonce_local
);
if ( !av->rtp_sessions[video_index] ) {
fprintf(stderr, "Error while starting video RTP session!\n");
return ErrorStartingVideoRtp;
if ( !av->rtp_sessions[video_index] ) {
fprintf(stderr, "Error while starting video RTP session!\n");
return ErrorStartingVideoRtp;
}
}
return ErrorNone;
}
@ -322,21 +323,20 @@ int toxav_prepare_transmission ( ToxAv *av )
*/
int toxav_kill_transmission ( ToxAv *av )
{
/* Both sessions should be active at any time */
if ( !av->rtp_sessions[0] || !av->rtp_sessions[0] )
return ErrorNoTransmission;
if ( -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) {
if ( av->rtp_sessions[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) {
fprintf(stderr, "Error while terminating audio RTP session!\n");
return ErrorTerminatingAudioRtp;
}
if ( -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) {
if ( av->rtp_sessions[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) {
fprintf(stderr, "Error while terminating video RTP session!\n");
return ErrorTerminatingVideoRtp;
}
av->rtp_sessions[audio_index] = NULL;
av->rtp_sessions[video_index] = NULL;
return ErrorNone;
}
@ -424,13 +424,14 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
uint8_t packet [RTP_PAYLOAD_SIZE];
int recved_size = 0;
int error;
do {
recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet);
if (recved_size > 0) {
printf("decode: %s\n", vpx_codec_err_to_string(vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0)));
}
if (recved_size > 0)
fprintf(stderr, "Error decoding: %s\n", vpx_codec_err_to_string(vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0)));
} while (recved_size > 0);
vpx_codec_iter_t iter = NULL;
@ -456,7 +457,7 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
{
if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) {
printf("could not encode video frame\n");
fprintf(stderr, "Could not encode video frame\n");
return ErrorInternal;
}
@ -500,7 +501,6 @@ inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest )
int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet);
if ( recved_size == ErrorAudioPacketLost ) {
printf("Lost packet\n");
return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
} else if ( recved_size ) {
return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
@ -550,6 +550,24 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int peer )
return av->msi_session->call->type_peer[peer];
}
/**
* @brief Get id of peer participating in conversation
*
* @param av Handler
* @param peer peer index
* @return int
* @retval ToxAvError No peer id
*/
int toxav_get_peer_id ( ToxAv* av, int peer )
{
assert(av->msi_session);
if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer )
return ErrorInternal;
return av->msi_session->call->peers[peer];
}
/**
* @brief Get reference to an object that is handling av session.
*
@ -560,3 +578,68 @@ void *toxav_get_agent_handler ( ToxAv *av )
{
return av->agent_handler;
}
/**
* @brief Is video encoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
inline__ int toxav_video_encoding ( ToxAv* av )
{
return av->cs->supported_actions & v_encoding;
}
/**
* @brief Is video decoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
inline__ int toxav_video_decoding ( ToxAv* av )
{
return av->cs->supported_actions & v_decoding;
}
/**
* @brief Is audio encoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
inline__ int toxav_audio_encoding ( ToxAv* av )
{
return av->cs->supported_actions & a_encoding;
}
/**
* @brief Is audio decoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
inline__ int toxav_audio_decoding ( ToxAv* av )
{
return av->cs->supported_actions & a_decoding;
}
/**
* @brief Get messenger handle
*
* @param av Handler.
* @return Tox*
*/
inline__ Tox* toxav_get_tox ( ToxAv* av )
{
return (Tox*)av->messenger;
}

86
toxav/toxav.h Normal file → Executable file
View File

@ -57,20 +57,20 @@ typedef struct Tox Tox;
*/
typedef enum {
/* Requests */
OnInvite,
OnStart,
OnCancel,
OnReject,
OnEnd,
av_OnInvite,
av_OnStart,
av_OnCancel,
av_OnReject,
av_OnEnd,
/* Responses */
OnRinging,
OnStarting,
OnEnding,
av_OnRinging,
av_OnStarting,
av_OnEnding,
/* Protocol */
OnError,
OnRequestTimeout
av_OnError,
av_OnRequestTimeout
} ToxAvCallbackID;
@ -98,9 +98,8 @@ typedef enum {
ErrorAudioPacketLost = -6, /* Indicating packet loss */
ErrorStartingAudioRtp = -7, /* Error in toxav_prepare_transmission() */
ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
ErrorNoTransmission = -9, /* Returned in toxav_kill_transmission() */
ErrorTerminatingAudioRtp = -10, /* Returned in toxav_kill_transmission() */
ErrorTerminatingVideoRtp = -11, /* Returned in toxav_kill_transmission() */
ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */
ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */
} ToxAvError;
@ -205,11 +204,12 @@ int toxav_stop_call(ToxAv *av);
* @brief Must be call before any RTP transmission occurs.
*
* @param av Handler.
* @param support_video Is video supported ? 1 : 0
* @return int
* @retval 0 Success.
* @retval ToxAvError On error.
*/
int toxav_prepare_transmission(ToxAv *av);
int toxav_prepare_transmission(ToxAv *av, int support_video);
/**
* @brief Call this at the end of the transmission.
@ -281,6 +281,16 @@ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size);
*/
int toxav_get_peer_transmission_type ( ToxAv *av, int peer );
/**
* @brief Get id of peer participating in conversation
*
* @param av Handler
* @param peer peer index
* @return int
* @retval ToxAvError No peer id
*/
int toxav_get_peer_id ( ToxAv* av, int peer );
/**
* @brief Get reference to an object that is handling av session.
*
@ -289,4 +299,52 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int peer );
*/
void *toxav_get_agent_handler ( ToxAv *av );
/**
* @brief Is video encoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
int toxav_video_encoding ( ToxAv* av );
/**
* @brief Is video decoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
int toxav_video_decoding ( ToxAv* av );
/**
* @brief Is audio encoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
int toxav_audio_encoding ( ToxAv* av );
/**
* @brief Is audio decoding supported
*
* @param av Handler
* @return int
* @retval 1 Yes.
* @retval 0 No.
*/
int toxav_audio_decoding ( ToxAv* av );
/**
* @brief Get messenger handle
*
* @param av Handler.
* @return Tox*
*/
Tox* toxav_get_tox ( ToxAv* av );
#endif /* __TOXAV */