From 172f18b5e82cb33fcd6d3f56e9052232019fd8c1 Mon Sep 17 00:00:00 2001 From: Martijnvdc Date: Sat, 1 Feb 2014 06:52:48 -0500 Subject: Added fixes to rtp and updated phone --- toxav/phone.c | 704 +++++++++++++++++++++++++++++++++++++++++++++++-------- toxav/toxmedia.c | 473 ++----------------------------------- toxav/toxmedia.h | 99 +++----- toxav/toxmsi.c | 237 ++++++++++--------- toxav/toxmsi.h | 4 +- toxav/toxrtp.c | 275 ++++++++++++---------- toxav/toxrtp.h | 7 +- toxcore/event.c | 230 ++++++++++-------- 8 files changed, 1078 insertions(+), 951 deletions(-) diff --git a/toxav/phone.c b/toxav/phone.c index 6d4b5e6b..8a0a3162 100755 --- a/toxav/phone.c +++ b/toxav/phone.c @@ -35,18 +35,25 @@ #endif /* HAVE_CONFIG_H */ #define _BSD_SOURCE +#define _GNU_SOURCE #include #include #include - -#include "toxmsi.h" -#include "toxrtp.h" #include #include #include +#include +#include +#include +#include +#include +#include +#include -#include "../toxcore/network.h" +#include "toxmsi.h" +#include "toxrtp.h" +#include "toxmedia.h" #include "../toxcore/event.h" #include "../toxcore/tox.h" @@ -54,6 +61,14 @@ #define _USERAGENT "v.0.3.0" +struct SDL_Surface *screen; + +typedef struct { + struct SDL_Overlay *bmp; + int width, height; +} VideoPicture; + + typedef struct av_friend_s { int _id; int _active; /* 0=false; 1=true; */ @@ -61,16 +76,30 @@ typedef struct av_friend_s { typedef struct av_session_s { MSISession* _msi; - RTPSession* _rtp_audio; RTPSession* _rtp_video; + /* Encoding/decoding/capturing/playing */ + + codec_state* cs; + VideoPicture video_picture; + struct ALCdevice *audio_capture_device; + + /* context for converting image format to something SDL can use*/ + struct SwsContext *sws_SDL_r_ctx; + + /* context for converting webcam image format to something the video encoder can use */ + struct SwsContext *sws_ctx; + + /**/ + + pthread_mutex_t _mutex; Tox* _messenger; av_friend_t* _friends; int _friend_cout; - uint8_t _my_public_id[200]; + char _my_public_id[200]; } av_session_t; @@ -86,7 +115,7 @@ void av_allocate_friend(av_session_t* _phone, int _id, int _active) _phone->_friends = realloc(_phone->_friends, sizeof(av_friend_t) * _phone->_friend_cout); } - if ( _id = -1 ) { + if ( _id == -1 ) { _phone->_friends->_id = _new_id; _new_id ++; } else _phone->_friends->_id = _id; @@ -174,7 +203,7 @@ char* trim_spaces ( char* buff ) static void fraddr_to_str(uint8_t *id_bin, char *id_str) { - uint i, delta = 0, pos_extra, sum_extra = 0; + uint i, delta = 0, pos_extra = 0, sum_extra = 0; for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) { sprintf(&id_str[2 * i + delta], "%02hhX", id_bin[i]); @@ -197,127 +226,526 @@ static void fraddr_to_str(uint8_t *id_bin, char *id_str) id_str[pos_extra] = 0; } -void* phone_handle_media_transport_poll ( void* _hmtc_args_p ) -{ - RTPMessage* _audio_msg, * _video_msg; - av_session_t* _phone = _hmtc_args_p; - MSISession* _session = _phone->_msi; +/********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + */ - RTPSession* _rtp_audio = _phone->_rtp_audio; - RTPSession* _rtp_video = _phone->_rtp_video; - - Tox* _messenger = _phone->_messenger; +/* + * How av stuff _should_ look like + */ + +int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) +{ + codec_state* cs = _phone->cs; + AVPicture pict; + SDL_LockYUVOverlay(_phone->video_picture.bmp); + + pict.data[0] = _phone->video_picture.bmp->pixels[0]; + pict.data[1] = _phone->video_picture.bmp->pixels[2]; + pict.data[2] = _phone->video_picture.bmp->pixels[1]; + pict.linesize[0] = _phone->video_picture.bmp->pitches[0]; + pict.linesize[1] = _phone->video_picture.bmp->pitches[2]; + pict.linesize[2] = _phone->video_picture.bmp->pitches[1]; + /* Convert the image into YUV format that SDL uses */ + sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, + cs->video_decoder_ctx->height, pict.data, pict.linesize ); - while ( _session->call ) { + SDL_UnlockYUVOverlay(_phone->video_picture.bmp); + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = cs->video_decoder_ctx->width; + rect.h = cs->video_decoder_ctx->height; + SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); + return 1; +} - _audio_msg = rtp_recv_msg ( _rtp_audio ); - _video_msg = rtp_recv_msg ( _rtp_video ); +int video_encoder_refresh(codec_state *cs, int bps) +{ + if (cs->video_encoder_ctx) + avcodec_close(cs->video_encoder_ctx); + + cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); + + if (!cs->video_encoder) { + printf("init video_encoder failed\n"); + return -1; + } + + cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); + + if (!cs->video_encoder_ctx) { + printf("init video_encoder_ctx failed\n"); + return -1; + } + + cs->video_encoder_ctx->bit_rate = bps; + cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; + av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); + av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); + + cs->video_encoder_ctx->thread_count = 4; + cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; + cs->video_encoder_ctx->rc_buffer_size = bps * 6; + cs->video_encoder_ctx->profile = 0; + cs->video_encoder_ctx->qmax = 54; + cs->video_encoder_ctx->qmin = 4; + AVRational myrational = {1, 25}; + cs->video_encoder_ctx->time_base = myrational; + cs->video_encoder_ctx->gop_size = 99999; + cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; + cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; + cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; + + if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { + printf("opening video encoder failed\n"); + return -1; + } + return 0; +} - if ( _audio_msg ) { - /* Do whatever with msg - printf("%d - %s\n", _audio_msg->header->sequnum, _audio_msg->data);*/ - rtp_free_msg ( _rtp_audio, _audio_msg ); - } +int video_decoder_refresh(av_session_t* _phone, int width, int height) +{ + printf("need to refresh\n"); + screen = SDL_SetVideoMode(width, height, 0, 0); + + if (_phone->video_picture.bmp) + SDL_FreeYUVOverlay(_phone->video_picture.bmp); + + _phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); + _phone->sws_SDL_r_ctx = sws_getContext(width, height, _phone->cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, + SWS_BILINEAR, NULL, NULL, NULL); + return 1; +} - if ( _video_msg ) { - /* Do whatever with msg - p rintf("%d - %s\n", _video_msg->header->sequnum, _video_msg->data);*/ - rtp_free_msg ( _rtp_video, _video_msg ); +void *encode_video_thread(void *arg) +{ + av_session_t* _phone = arg; + + codec_state *cs = _phone->cs; + AVPacket pkt1, *packet = &pkt1; + int p = 0; + int got_packet; + int video_frame_finished; + AVFrame *s_video_frame; + AVFrame *webcam_frame; + s_video_frame = avcodec_alloc_frame(); + webcam_frame = avcodec_alloc_frame(); + AVPacket enc_video_packet; + + uint8_t *buffer; + int numBytes; + /* Determine required buffer size and allocate buffer */ + numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height); + buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); + avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, + cs->webcam_decoder_ctx->height); + _phone->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, + cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, + SWS_BILINEAR, NULL, NULL, NULL); + + while (!cs->quit && cs->send_video) { + + if (av_read_frame(cs->video_format_ctx, packet) < 0) { + printf("error reading frame\n"); + + if (cs->video_format_ctx->pb->error != 0) + break; + + continue; } + + if (packet->stream_index == cs->video_stream) { + if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { + printf("couldn't decode\n"); + continue; + } + + av_free_packet(packet); + sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, + cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); + /* create a new I-frame every 60 frames */ + ++p; + + if (p == 60) { + + s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; + } else if (p == 61) { + s_video_frame->pict_type = AV_PICTURE_TYPE_I ; + p = 0; + } else { + s_video_frame->pict_type = AV_PICTURE_TYPE_P ; + } + + if (video_frame_finished) { + + if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { + printf("could not encode video frame\n"); + continue; + } + + if (!got_packet) { + continue; + } + + if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); + + if ( 0 > rtp_send_msg ( _phone->_rtp_video, _phone->_messenger, enc_video_packet.data, enc_video_packet.size) ) { + printf("Failed sending message\n"); + } + + av_free_packet(&enc_video_packet); + } + } else { + av_free_packet(packet); + } + } + + /* clean up codecs */ + pthread_mutex_lock(&cs->avcodec_mutex_lock); + av_free(buffer); + av_free(webcam_frame); + av_free(s_video_frame); + sws_freeContext(_phone->sws_ctx); + avcodec_close(cs->webcam_decoder_ctx); + avcodec_close(cs->video_encoder_ctx); + pthread_mutex_unlock(&cs->avcodec_mutex_lock); + pthread_exit ( NULL ); +} - /* - * Send test message to the 'remote' - */ - rtp_send_msg ( _rtp_audio, _messenger, (const uint8_t*)"audio\0", 6 ); - - if ( _session->call->type_local == type_video ){ /* if local call send video */ - rtp_send_msg ( _rtp_video, _messenger, (const uint8_t*)"video\0", 6 ); +void *encode_audio_thread(void *arg) +{ + av_session_t* _phone = arg; + + codec_state *cs = _phone->cs; + unsigned char encoded_data[4096]; + int encoded_size = 0; + int16_t frame[4096]; + int frame_size = AUDIO_FRAME_SIZE; + ALint sample = 0; + alcCaptureStart((ALCdevice*)_phone->audio_capture_device); + + while (!cs->quit && cs->send_audio) { + 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); + encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, 480); + + if (encoded_size <= 0) { + printf("Could not encode audio packet\n"); + } else { + rtp_send_msg ( _phone->_rtp_audio, _phone->_messenger, encoded_data, encoded_size ); + } + } else { + usleep(1000); } + } + + /* clean up codecs */ + pthread_mutex_lock(&cs->avcodec_mutex_lock); + alcCaptureStop((ALCdevice*)_phone->audio_capture_device); + alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); + + pthread_mutex_unlock(&cs->avcodec_mutex_lock); + pthread_exit ( NULL ); +} - _audio_msg = _video_msg = NULL; +void *decode_video_thread(void *arg) +{ + av_session_t* _phone = arg; + + codec_state *cs = _phone->cs; + cs->video_stream = 0; + RTPMessage *r_msg; + int dec_frame_finished; + AVFrame *r_video_frame; + r_video_frame = avcodec_alloc_frame(); + AVPacket dec_video_packet; + av_new_packet (&dec_video_packet, 65536); + int width = 0; + int height = 0; + + while (!cs->quit && cs->receive_video) { + r_msg = rtp_recv_msg ( _phone->_rtp_video ); + if (r_msg) { + memcpy(dec_video_packet.data, r_msg->data, r_msg->length); + dec_video_packet.size = r_msg->length; + avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); + + if (dec_frame_finished) { + if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { + width = cs->video_decoder_ctx->width; + height = cs->video_decoder_ctx->height; + printf("w: %d h%d \n", width, height); + video_decoder_refresh(_phone, width, height); + } + + display_received_frame(_phone, r_video_frame); + } else { + /* TODO: request the sender to create a new i-frame immediatly */ + printf("Bad video packet\n"); + } + + rtp_free_msg(NULL, r_msg); + } - /* Send ~1k messages per second - * That _should_ be enough for both Audio and Video - */ - usleep ( 1000 ); - /* -------------------- */ + usleep(1000); } - if ( _audio_msg ) rtp_free_msg(_rtp_audio, _audio_msg); - rtp_release_session_recv(_rtp_audio); - rtp_terminate_session(_rtp_audio, _messenger); + printf("vend\n"); + /* clean up codecs */ + pthread_mutex_lock(&cs->avcodec_mutex_lock); + av_free(r_video_frame); + avcodec_close(cs->video_decoder_ctx); + pthread_mutex_unlock(&cs->avcodec_mutex_lock); + pthread_exit ( NULL ); +} + +void *decode_audio_thread(void *arg) +{ + av_session_t* _phone = arg; - if ( _video_msg ) rtp_free_msg(_rtp_video, _video_msg); - rtp_release_session_recv(_rtp_video); - rtp_terminate_session(_rtp_video, _messenger); + codec_state *cs = _phone->cs; + RTPMessage *r_msg; - INFO("Media thread finished!"); - + int frame_size = AUDIO_FRAME_SIZE; + int data_size; + + 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 val; + + uint16_t zeros[frame_size]; + memset(zeros, 0, 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"); + cs->quit = 1; + } + + struct jitter_buffer *j_buf = NULL; + + j_buf = create_queue(20); + + int success = 0; + + int dec_frame_len = 0; + + opus_int16 PCM[frame_size]; + + while (!cs->quit && cs->receive_audio) { + + r_msg = rtp_recv_msg ( _phone->_rtp_audio ); + + if (r_msg) { + /* push the packet into the queue */ + queue(j_buf, r_msg); + } + + /* grab a packet from the queue */ + success = 0; + alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); + + if (val > 0) + r_msg = dequeue(j_buf, &success); + + if (success > 0) { + /* good packet */ + if (success == 1) { + dec_frame_len = opus_decode(cs->audio_decoder, r_msg->data, r_msg->length, PCM, frame_size, 0); + //rtp_free_msg(NULL, r_msg); + } + + /* lost packet */ + if (success == 2) { + printf("lost packet\n"); + dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1); + } + + if (dec_frame_len > 0) { + alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); + + if (val <= 0) + continue; + + alSourceUnqueueBuffers(source, 1, &buffer); + data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1); + alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 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, &val); + + if (val != AL_PLAYING) + alSourcePlay(source); + + + } + } + + usleep(1000); + } + + /* clean up codecs */ + pthread_mutex_lock(&cs->avcodec_mutex_lock); + + /* clean up openal */ + alDeleteSources(1, &source); + alDeleteBuffers(openal_buffers, buffers); + alcMakeContextCurrent(NULL); + alcDestroyContext(ctx); + alcCloseDevice(dev); + pthread_mutex_unlock(&cs->avcodec_mutex_lock); pthread_exit ( NULL ); } + + + + int phone_startmedia_loop ( av_session_t* _phone ) { if ( !_phone ){ return -1; } - + _phone->_rtp_audio = rtp_init_session ( - type_audio, - _phone->_messenger, - _phone->_msi->call->peers[0], - _phone->_msi->call->key_peer, - _phone->_msi->call->key_local, - _phone->_msi->call->nonce_peer, - _phone->_msi->call->nonce_local - ); + type_audio, + _phone->_messenger, + _phone->_msi->call->peers[0], + _phone->_msi->call->key_peer, + _phone->_msi->call->key_local, + _phone->_msi->call->nonce_peer, + _phone->_msi->call->nonce_local + ); _phone->_rtp_audio = rtp_init_session ( - type_video, - _phone->_messenger, - _phone->_msi->call->peers[0], - _phone->_msi->call->key_peer, - _phone->_msi->call->key_local, - _phone->_msi->call->nonce_peer, - _phone->_msi->call->nonce_local - ); - - - if ( 0 > event.rise(phone_handle_media_transport_poll, _phone) ) + type_video, + _phone->_messenger, + _phone->_msi->call->peers[0], + _phone->_msi->call->key_peer, + _phone->_msi->call->key_local, + _phone->_msi->call->nonce_peer, + _phone->_msi->call->nonce_local + ); + + _phone->cs->quit = 0; + + init_encoder(_phone->cs); + init_decoder(_phone->cs); + + /* + * Rise all threads + */ + + /* Only checks for last peer */ + if ( _phone->_msi->call->type_peer[0] == type_video && 0 > event.rise(encode_video_thread, _phone) ) + { + INFO("Error while starting encode_video_thread()"); + return -1; + } + + /* Always send audio */ + if ( 0 > event.rise(encode_audio_thread, _phone) ) + { + INFO("Error while starting encode_audio_thread()"); + return -1; + } + + if ( _phone->_msi->call->type_peer[0] == type_video && 0 > event.rise(decode_video_thread, _phone) ) + { + INFO("Error while starting decode_video_thread()"); + return -1; + } + + if ( 0 > event.rise(decode_audio_thread, _phone) ) { - printf("Error while starting phone_handle_media_transport_poll()\n"); + INFO("Error while starting decode_audio_thread()"); return -1; } - else return 0; + + + return 0; } + + + + +/********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + ********************************************* + */ + + /* Some example callbacks */ void* callback_recv_invite ( void* _arg ) { - const char* _call_type; - MSISession* _msi = _arg; switch ( _msi->call->type_peer[_msi->call->peer_count - 1] ){ case type_audio: - _call_type = "audio"; + INFO( "Incoming audio call!"); break; case type_video: - _call_type = "video"; + INFO( "Incoming video call!"); break; } - INFO( "Incoming %s call!", _call_type ); - + pthread_exit(NULL); } void* callback_recv_ringing ( void* _arg ) { INFO ( "Ringing!" ); + pthread_exit(NULL); } void* callback_recv_starting ( void* _arg ) { @@ -327,10 +755,22 @@ void* callback_recv_starting ( void* _arg ) } else { INFO ("Call started! ( press h to hangup )"); } + pthread_exit(NULL); } void* callback_recv_ending ( void* _arg ) { + av_session_t* _phone = ((MSISession*)_arg)->agent_handler; + + _phone->cs->send_audio = 0; + _phone->cs->send_video = 0; + _phone->cs->receive_audio = 0; + _phone->cs->receive_video = 0; + + /* Wait until all threads are done */ + usleep(10000000); + INFO ( "Call ended!" ); + pthread_exit(NULL); } void* callback_recv_error ( void* _arg ) @@ -338,6 +778,7 @@ void* callback_recv_error ( void* _arg ) MSISession* _session = _arg; INFO( "Error: %s", _session->last_error_str ); + pthread_exit(NULL); } void* callback_call_started ( void* _arg ) @@ -348,43 +789,45 @@ void* callback_call_started ( void* _arg ) } else { INFO ("Call started! ( press h to hangup )"); } - + + pthread_exit(NULL); } void* callback_call_canceled ( void* _arg ) { INFO ( "Call canceled!" ); + pthread_exit(NULL); } void* callback_call_rejected ( void* _arg ) { INFO ( "Call rejected!" ); + pthread_exit(NULL); } void* callback_call_ended ( void* _arg ) { + av_session_t* _phone = ((MSISession*)_arg)->agent_handler; + + _phone->cs->send_audio = 0; + _phone->cs->send_video = 0; + _phone->cs->receive_audio = 0; + _phone->cs->receive_video = 0; + + /* Wait until all threads are done */ + usleep(10000000); + INFO ( "Call ended!" ); + pthread_exit(NULL); } void* callback_requ_timeout ( void* _arg ) { INFO( "No answer! " ); -} - -int av_connect_to_dht(av_session_t* _phone, char* _dht_key, const char* _dht_addr, unsigned short _dht_port) -{ - unsigned char *_binary_string = hex_string_to_bin(_dht_key); - - uint16_t _port = htons(_dht_port); - - int _if = tox_bootstrap_from_address(_phone->_messenger, _dht_addr, 1, _port, _binary_string ); - - free(_binary_string); - - return _if ? 0 : -1; + pthread_exit(NULL); } av_session_t* av_init_session() { av_session_t* _retu = malloc(sizeof(av_session_t)); - + /* Initialize our mutex */ pthread_mutex_init ( &_retu->_mutex, NULL ); @@ -400,13 +843,61 @@ av_session_t* av_init_session() _retu->_rtp_audio = NULL; _retu->_rtp_video = NULL; + + const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + int i = 0; + const ALchar *device_names[20]; + + if ( _device_list ) { + INFO("\nAvailable Capture Devices are:"); + + while (*_device_list ) { + device_names[i] = _device_list; + INFO("%d) %s", i, device_names[i]); + _device_list += strlen( _device_list ) + 1; + ++i; + } + } + + INFO("Enter capture device number"); + + char dev[2]; char* left; + fgets(dev, 2, stdin); + long selection = strtol(dev, &left, 10); + + if ( *left ) { + printf("'%s' is not a number!", dev); + fflush(stdout); + exit(EXIT_FAILURE); + } + else { + INFO("Selected: %d ( %s )", selection, device_names[selection]); + } + + _retu->cs = av_calloc(sizeof(codec_state), 1); + + _retu->audio_capture_device = + (struct ALCdevice*)alcCaptureOpenDevice( + device_names[selection], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4); + + + if (alcGetError((ALCdevice*)_retu->audio_capture_device) != AL_NO_ERROR) { + printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); + return 0; + } + + + init_encoder(_retu->cs); + init_decoder(_retu->cs); + + uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; tox_get_address(_retu->_messenger, _byte_address ); fraddr_to_str( _byte_address, _retu->_my_public_id ); /* Initialize msi */ - _retu->_msi = msi_init_session ( _retu->_messenger, _USERAGENT ); + _retu->_msi = msi_init_session ( _retu->_messenger, (const uint8_t*)_USERAGENT ); if ( !_retu->_msi ) { fprintf ( stderr, "msi_init_session() failed\n" ); @@ -498,6 +989,20 @@ int av_add_friend(av_session_t* _phone, char* _friend_hash) return _number; } + +int av_connect_to_dht(av_session_t* _phone, char* _dht_key, const char* _dht_addr, unsigned short _dht_port) +{ + unsigned char *_binary_string = hex_string_to_bin(_dht_key); + + uint16_t _port = htons(_dht_port); + + int _if = tox_bootstrap_from_address(_phone->_messenger, _dht_addr, 1, _port, _binary_string ); + + free(_binary_string); + + return _if ? 0 : -1; +} + /*********************************/ void do_phone ( av_session_t* _phone ) @@ -512,7 +1017,7 @@ void do_phone ( av_session_t* _phone ) "q (quit)\n" "================================================================================" ); - + while ( 1 ) { char _line [ 1500 ]; @@ -613,6 +1118,9 @@ void do_phone ( av_session_t* _phone ) INFO("Quitting!"); return; } + case '\n': + { + } default: { INFO("Invalid command!"); @@ -670,6 +1178,7 @@ int print_help ( const char* _name ) "\t[IP] (DHT ip)\n" "\t[PORT] (DHT port)\n" "\t[KEY] (DHT public key)\n" + "P.S. Friends and key are stored in ./tox_phone.conf\n" ,_name ); return 1; } @@ -681,13 +1190,12 @@ int main ( int argc, char* argv [] ) char* _convertable; - int _wait_seconds = 5; const char* _ip = argv[1]; char* _key = argv[3]; unsigned short _port = strtol(argv[2], &_convertable, 10); - if ( *_convertable ){ + if ( *_convertable ) { printf("Invalid port: cannot convert string to long: %s", _convertable); return 1; } @@ -697,7 +1205,6 @@ int main ( int argc, char* argv [] ) tox_callback_friend_request(_phone->_messenger, av_friend_requ, _phone); tox_callback_status_message(_phone->_messenger, av_friend_active, _phone); - system("clear"); INFO("\r================================================================================\n" "[!] Trying dht@%s:%d" @@ -711,6 +1218,7 @@ int main ( int argc, char* argv [] ) fflush(stdout); int _r; + int _wait_seconds = 5; for ( _r = 0; _r == 0; _r = av_wait_dht(_phone, _wait_seconds, _ip, _key, _port) ) _wait_seconds --; diff --git a/toxav/toxmedia.c b/toxav/toxmedia.c index aff3cf8c..359832d3 100644 --- a/toxav/toxmedia.c +++ b/toxav/toxmedia.c @@ -34,45 +34,13 @@ #include #include #include -#include -#include -#include -#include -#include #include +#include #include "toxmsi.h" #include "toxrtp.h" #include "toxmedia.h" -SDL_Surface *screen; - -int display_received_frame(codec_state *cs, AVFrame *r_video_frame) -{ - AVPicture pict; - SDL_LockYUVOverlay(cs->video_picture.bmp); - - pict.data[0] = cs->video_picture.bmp->pixels[0]; - pict.data[1] = cs->video_picture.bmp->pixels[2]; - pict.data[2] = cs->video_picture.bmp->pixels[1]; - pict.linesize[0] = cs->video_picture.bmp->pitches[0]; - pict.linesize[1] = cs->video_picture.bmp->pitches[2]; - pict.linesize[2] = cs->video_picture.bmp->pitches[1]; - - /* Convert the image into YUV format that SDL uses */ - sws_scale(cs->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, - cs->video_decoder_ctx->height, pict.data, pict.linesize ); - - SDL_UnlockYUVOverlay(cs->video_picture.bmp); - SDL_Rect rect; - rect.x = 0; - rect.y = 0; - rect.w = cs->video_decoder_ctx->width; - rect.h = cs->video_decoder_ctx->height; - SDL_DisplayYUVOverlay(cs->video_picture.bmp, &rect); - return 1; -} - struct jitter_buffer { RTPMessage **queue; uint16_t capacity; @@ -85,6 +53,7 @@ struct jitter_buffer { uint8_t id_set; }; + struct jitter_buffer *create_queue(int capacity) { struct jitter_buffer *q; @@ -240,10 +209,23 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) int init_receive_audio(codec_state *cs) { - int err = OPUS_OK; - cs->audio_decoder = opus_decoder_create(48000, 1, &err); - opus_decoder_init(cs->audio_decoder, 48000, 1); - printf("init audio decoder successful\n"); + int rc; + cs->audio_decoder = opus_decoder_create(48000, 1, &rc ); + + if ( rc != OPUS_OK ){ + printf("Error while starting audio decoder!\n"); + return 0; + } + + rc = opus_decoder_init(cs->audio_decoder, 48000, 1); + + if ( rc != OPUS_OK ){ + printf("Error while starting audio decoder!\n"); + return 0; + } + + + printf("Init audio decoder successful\n"); return 1; } @@ -252,23 +234,23 @@ int init_receive_video(codec_state *cs) cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); if (!cs->video_decoder) { - printf("init video_decoder failed\n"); + printf("Init video_decoder failed\n"); return 0; } cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); if (!cs->video_decoder_ctx) { - printf("init video_decoder_ctx failed\n"); + printf("Init video_decoder_ctx failed\n"); return 0; } if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { - printf("opening video decoder failed\n"); + printf("Opening video decoder failed\n"); return 0; } - printf("init video decoder successful\n"); + printf("Init video decoder successful\n"); return 1; } @@ -356,32 +338,6 @@ int init_send_audio(codec_state *cs) { cs->support_send_audio = 0; - const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - int i = 0; - const ALchar *device_names[20]; - - if (pDeviceList) { - printf("\nAvailable Capture Devices are:\n"); - - while (*pDeviceList) { - device_names[i] = pDeviceList; - printf("%d) %s\n", i, device_names[i]); - pDeviceList += strlen(pDeviceList) + 1; - ++i; - } - } - - printf("enter capture device number: \n"); - char dev[2]; - fgets(dev, sizeof(dev), stdin); - cs->audio_capture_device = alcCaptureOpenDevice(device_names[dev[0] - 48], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, - AUDIO_FRAME_SIZE * 4); - - if (alcGetError(cs->audio_capture_device) != AL_NO_ERROR) { - printf("could not start capture device! %d\n", alcGetError(cs->audio_capture_device)); - return 0; - } - int err = OPUS_OK; cs->audio_bitrate = AUDIO_BITRATE; cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err); @@ -435,385 +391,4 @@ int init_decoder(codec_state *cs) cs->receive_video = 1; return 1; -} - -int video_encoder_refresh(codec_state *cs, int bps) -{ - if (cs->video_encoder_ctx) - avcodec_close(cs->video_encoder_ctx); - - cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); - - if (!cs->video_encoder) { - printf("init video_encoder failed\n"); - return -1; - } - - cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); - - if (!cs->video_encoder_ctx) { - printf("init video_encoder_ctx failed\n"); - return -1; - } - - cs->video_encoder_ctx->bit_rate = bps; - cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; - av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); - av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); - - cs->video_encoder_ctx->thread_count = 4; - cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; - cs->video_encoder_ctx->rc_buffer_size = bps * 6; - cs->video_encoder_ctx->profile = 0; - cs->video_encoder_ctx->qmax = 54; - cs->video_encoder_ctx->qmin = 4; - AVRational myrational = {1, 25}; - cs->video_encoder_ctx->time_base = myrational; - cs->video_encoder_ctx->gop_size = 99999; - cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; - cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; - cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; - - if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { - printf("opening video encoder failed\n"); - return -1; - } - return 0; -} - -void *encode_video_thread(void *arg) -{ - codec_state *cs = (codec_state *)arg; - AVPacket pkt1, *packet = &pkt1; - int p = 0; - int err; - int got_packet; - RTPMessage *s_video_msg; - int video_frame_finished; - AVFrame *s_video_frame; - AVFrame *webcam_frame; - s_video_frame = avcodec_alloc_frame(); - webcam_frame = avcodec_alloc_frame(); - AVPacket enc_video_packet; - - uint8_t *buffer; - int numBytes; - /* Determine required buffer size and allocate buffer */ - numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height); - buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); - avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, - cs->webcam_decoder_ctx->height); - cs->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, - cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, - SWS_BILINEAR, NULL, NULL, NULL); - - while (!cs->quit && cs->send_video) { - - if (av_read_frame(cs->video_format_ctx, packet) < 0) { - printf("error reading frame\n"); - - if (cs->video_format_ctx->pb->error != 0) - break; - - continue; - } - - if (packet->stream_index == cs->video_stream) { - if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { - printf("couldn't decode\n"); - continue; - } - - av_free_packet(packet); - sws_scale(cs->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, - cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); - /* create a new I-frame every 60 frames */ - ++p; - - if (p == 60) { - - s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; - } else if (p == 61) { - s_video_frame->pict_type = AV_PICTURE_TYPE_I ; - p = 0; - } else { - s_video_frame->pict_type = AV_PICTURE_TYPE_P ; - } - - if (video_frame_finished) { - err = avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet); - - if (err < 0) { - printf("could not encode video frame\n"); - continue; - } - - if (!got_packet) { - continue; - } - - pthread_mutex_lock(&cs->rtp_msg_mutex_lock); - - if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); - - if ( 0 > rtp_send_msg ( cs->_rtp_video, cs->_messenger, enc_video_packet.data, enc_video_packet.size) ) { - printf("invalid message\n"); - } - - pthread_mutex_unlock(&cs->rtp_msg_mutex_lock); - av_free_packet(&enc_video_packet); - } - } else { - av_free_packet(packet); - } - } - - /* clean up codecs */ - pthread_mutex_lock(&cs->avcodec_mutex_lock); - av_free(buffer); - av_free(webcam_frame); - av_free(s_video_frame); - sws_freeContext(cs->sws_ctx); - avcodec_close(cs->webcam_decoder_ctx); - avcodec_close(cs->video_encoder_ctx); - pthread_mutex_unlock(&cs->avcodec_mutex_lock); - pthread_exit ( NULL ); -} - -void *encode_audio_thread(void *arg) -{ - codec_state *cs = (codec_state *)arg; - RTPMessage *s_audio_msg; - unsigned char encoded_data[4096]; - int encoded_size = 0; - int16_t frame[4096]; - int frame_size = AUDIO_FRAME_SIZE; - ALint sample = 0; - alcCaptureStart(cs->audio_capture_device); - - while (!cs->quit && cs->send_audio) { - alcGetIntegerv(cs->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample); - - if (sample >= frame_size) { - alcCaptureSamples(cs->audio_capture_device, frame, frame_size); - encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, 480); - - if (encoded_size <= 0) { - printf("Could not encode audio packet\n"); - } else { - pthread_mutex_lock(&cs->rtp_msg_mutex_lock); - - rtp_send_msg ( cs->_rtp_audio, cs->_messenger, encoded_data, encoded_size ); - - pthread_mutex_unlock(&cs->rtp_msg_mutex_lock); - - } - } else { - usleep(1000); - } - } - - /* clean up codecs */ - pthread_mutex_lock(&cs->avcodec_mutex_lock); - alcCaptureStop(cs->audio_capture_device); - alcCaptureCloseDevice(cs->audio_capture_device); - - pthread_mutex_unlock(&cs->avcodec_mutex_lock); - pthread_exit ( NULL ); -} - - -int video_decoder_refresh(codec_state *cs, int width, int height) -{ - printf("need to refresh\n"); - screen = SDL_SetVideoMode(width, height, 0, 0); - - if (cs->video_picture.bmp) - SDL_FreeYUVOverlay(cs->video_picture.bmp); - - cs->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); - cs->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, - SWS_BILINEAR, NULL, NULL, NULL); - return 1; -} - -void *decode_video_thread(void *arg) -{ - codec_state *cs = (codec_state *)arg; - cs->video_stream = 0; - RTPMessage *r_msg; - int dec_frame_finished; - AVFrame *r_video_frame; - r_video_frame = avcodec_alloc_frame(); - AVPacket dec_video_packet; - av_new_packet (&dec_video_packet, 65536); - int width = 0; - int height = 0; - - while (!cs->quit && cs->receive_video) { - r_msg = rtp_recv_msg ( cs->_rtp_video ); - - if (r_msg) { - memcpy(dec_video_packet.data, r_msg->data, r_msg->length); - dec_video_packet.size = r_msg->length; - avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); - - if (dec_frame_finished) { - if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { - width = cs->video_decoder_ctx->width; - height = cs->video_decoder_ctx->height; - printf("w: %d h%d \n", width, height); - video_decoder_refresh(cs, width, height); - } - - display_received_frame(cs, r_video_frame); - } else { - /* TODO: request the sender to create a new i-frame immediatly */ - printf("bad video packet\n"); - } - - rtp_free_msg(cs->_rtp_video, r_msg); - } - - usleep(1000); - } - - printf("vend\n"); - /* clean up codecs */ - pthread_mutex_lock(&cs->avcodec_mutex_lock); - av_free(r_video_frame); - avcodec_close(cs->video_decoder_ctx); - pthread_mutex_unlock(&cs->avcodec_mutex_lock); - pthread_exit ( NULL ); -} - -void *decode_audio_thread(void *arg) -{ - codec_state *cs = (codec_state *)arg; - RTPMessage *r_msg; - - int frame_size = AUDIO_FRAME_SIZE; - int data_size; - - 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 val; - - ALenum error; - uint16_t zeros[frame_size]; - int i; - - for (i = 0; i < frame_size; i++) { - zeros[i] = 0; - } - - 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"); - cs->quit = 1; - } - - struct jitter_buffer *j_buf = NULL; - - j_buf = create_queue(20); - - int success = 0; - - int dec_frame_len; - - opus_int16 PCM[frame_size]; - - while (!cs->quit && cs->receive_audio) { - - r_msg = rtp_recv_msg ( cs->_rtp_audio ); - - if (r_msg) { - /* push the packet into the queue */ - queue(j_buf, r_msg); - } - - /* grab a packet from the queue */ - success = 0; - alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); - - if (val > 0) - r_msg = dequeue(j_buf, &success); - - if (success > 0) { - /* good packet */ - if (success == 1) { - dec_frame_len = opus_decode(cs->audio_decoder, r_msg->data, r_msg->length, PCM, frame_size, 0); - rtp_free_msg(cs->_rtp_audio, r_msg); - } - - /* lost packet */ - if (success == 2) { - printf("lost packet\n"); - dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1); - } - - if (dec_frame_len > 0) { - alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); - - if (val <= 0) - continue; - - alSourceUnqueueBuffers(source, 1, &buffer); - data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1); - alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 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, &val); - - if (val != AL_PLAYING) - alSourcePlay(source); - - - } - } - - usleep(1000); - } - - /* clean up codecs */ - pthread_mutex_lock(&cs->avcodec_mutex_lock); - - /* clean up openal */ - alDeleteSources(1, &source); - alDeleteBuffers(openal_buffers, buffers); - alcMakeContextCurrent(NULL); - alcDestroyContext(ctx); - alcCloseDevice(dev); - pthread_mutex_unlock(&cs->avcodec_mutex_lock); - pthread_exit ( NULL ); -} +} \ No newline at end of file diff --git a/toxav/toxmedia.h b/toxav/toxmedia.h index aad299bb..927c5ef8 100644 --- a/toxav/toxmedia.h +++ b/toxav/toxmedia.h @@ -27,25 +27,25 @@ #include #include +#include "toxrtp.h" +#include "toxmsi.h" +#include "../toxcore/tox.h" + +/* Video encoding/decoding */ #include #include #include #include #include -#include -#include -#include -#include "toxrtp.h" -#include "tox.h" -#include +/* Audio encoding/decoding */ #include /* ffmpeg VP8 codec ID */ -#define VIDEO_CODEC AV_CODEC_ID_VP8 +#define VIDEO_CODEC AV_CODEC_ID_VP8 /* ffmpeg Opus codec ID */ -#define AUDIO_CODEC AV_CODEC_ID_OPUS +#define AUDIO_CODEC AV_CODEC_ID_OPUS /* default video bitrate in bytes/s */ #define VIDEO_BITRATE 10*1000 @@ -75,14 +75,6 @@ #define DEFAULT_WEBCAM "0" #endif -extern SDL_Surface *screen; - -typedef struct { - SDL_Overlay *bmp; - int width, height; -} VideoPicture; - - typedef struct { uint8_t send_audio; uint8_t receive_audio; @@ -95,71 +87,46 @@ typedef struct { uint8_t support_receive_video; /* video encoding */ - AVInputFormat *video_input_format; - AVFormatContext *video_format_ctx; - uint8_t video_stream; - AVCodecContext *webcam_decoder_ctx; - AVCodec *webcam_decoder; - AVCodecContext *video_encoder_ctx; - AVCodec *video_encoder; + AVInputFormat *video_input_format; + AVFormatContext *video_format_ctx; + uint8_t video_stream; + AVCodecContext *webcam_decoder_ctx; + AVCodec *webcam_decoder; + AVCodecContext *video_encoder_ctx; + AVCodec *video_encoder; /* video decoding */ - AVCodecContext *video_decoder_ctx; - AVCodec *video_decoder; + AVCodecContext *video_decoder_ctx; + AVCodec *video_decoder; /* audio encoding */ - ALCdevice *audio_capture_device; - OpusEncoder *audio_encoder; - int audio_bitrate; + OpusEncoder *audio_encoder; + int audio_bitrate; /* audio decoding */ - OpusDecoder *audio_decoder; + OpusDecoder *audio_decoder; uint8_t req_video_refresh; - - /* context for converting image format to something SDL can use*/ - struct SwsContext *sws_SDL_r_ctx; - - /* context for converting webcam image format to something the video encoder can use */ - struct SwsContext *sws_ctx; - - /* rendered video picture, ready for display */ - VideoPicture video_picture; - - RTPSession *_rtp_video; - RTPSession *_rtp_audio; - - Tox* _messenger; - pthread_t encode_audio_thread; - pthread_t encode_video_thread; - - pthread_t decode_audio_thread; - pthread_t decode_video_thread; - pthread_mutex_t rtp_msg_mutex_lock; pthread_mutex_t avcodec_mutex_lock; + + uint8_t quit; + + uint32_t frame_rate; - uint8_t quit; - SDL_Event SDL_event; +} codec_state; - MSISession *_msi; - uint32_t _frame_rate; -} codec_state; +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); + -int display_received_frame(codec_state *cs, AVFrame *r_video_frame); -int init_receive_audio(codec_state *cs); -int init_decoder(codec_state *cs); -int init_send_video(codec_state *cs); -int init_send_audio(codec_state *cs); int init_encoder(codec_state *cs); -int video_encoder_refresh(codec_state *cs, int bps); -void *encode_video_thread(void *arg); -void *encode_audio_thread(void *arg); -int video_decoder_refresh(codec_state *cs, int width, int height); -int handle_rtp_video_packet(codec_state *cs, RTPMessage *r_msg); -void *decode_video_thread(void *arg); -void *decode_audio_thread(void *arg); +int init_decoder(codec_state *cs); + #endif diff --git a/toxav/toxmsi.c b/toxav/toxmsi.c index cf0914ab..d504838a 100755 --- a/toxav/toxmsi.c +++ b/toxav/toxmsi.c @@ -119,7 +119,7 @@ typedef struct _MSIMessage { -static MSICallback callbacks[9] = {0}; +static MSICallback callbacks[10] = {0}; /* define strings for the identifiers */ @@ -330,10 +330,10 @@ MSIMessage* msi_new_message ( uint8_t type, const uint8_t* type_id ) { memset ( _retu, 0, sizeof ( MSIMessage ) ); if ( type == TYPE_REQUEST ) { - ALLOCATE_HEADER ( _retu->request, type_id, strlen ( type_id ) ) + ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char*)type_id ) ) } else if ( type == TYPE_RESPONSE ) { - ALLOCATE_HEADER ( _retu->response, type_id, strlen ( type_id ) ) + ALLOCATE_HEADER ( _retu->response, type_id, strlen ( (const char*)type_id ) ) } else { free_message ( _retu ); @@ -507,7 +507,7 @@ void t_randomstr ( uint8_t* str, size_t size ) { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; - int _it = 0; + size_t _it = 0; for ( ; _it < size; _it++ ) { str[_it] = _bytes[ randombytes_random() % 61 ]; @@ -523,7 +523,7 @@ typedef enum { error_no_call, /* no call in session */ error_no_crypto_key, /* no crypto key */ - error_busy, + error_busy } MSICallError; /* Error codes */ @@ -675,15 +675,18 @@ void* handle_timeout ( void* arg ) /* Send hangup either way */ MSISession* _session = arg; - uint32_t* _peers = _session->call->peers; - uint16_t _peer_count = _session->call->peer_count; - - - /* Cancel all? */ - uint16_t _it = 0; - for ( ; _it < _peer_count; _it++ ) - msi_cancel ( arg, _peers[_it] ); - + if ( _session && _session->call ) { + + uint32_t* _peers = _session->call->peers; + uint16_t _peer_count = _session->call->peer_count; + + + /* Cancel all? */ + uint16_t _it = 0; + for ( ; _it < _peer_count; _it++ ) + msi_cancel ( arg, _peers[_it] ); + + } ( *callbacks[cb_timeout] ) ( arg ); ( *callbacks[cb_ending ] ) ( arg ); @@ -713,107 +716,6 @@ void add_peer( MSICall* call, int peer_id ) } -/** - * @brief BASIC call flow: - * - * ALICE BOB - * | invite --> | - * | | - * | <-- ringing | - * | | - * | <-- starting | - * | | - * | start --> | - * | | - * | <-- MEDIA TRANS --> | - * | | - * | end --> | - * | | - * | <-- ending | - * - * Alice calls Bob by sending invite packet. - * Bob recvs the packet and sends an ringing packet; - * which notifies Alice that her invite is acknowledged. - * Ringing screen shown on both sides. - * Bob accepts the invite for a call by sending starting packet. - * Alice recvs the starting packet and sends the started packet to - * inform Bob that she recved the starting packet. - * Now the media transmission is established ( i.e. RTP transmission ). - * Alice hangs up and sends end packet. - * Bob recves the end packet and sends ending packet - * as the acknowledgement that the call is ending. - * - * - */ -void msi_handle_packet ( Messenger* messenger, int source, uint8_t* data, uint16_t length, void* object ) -{ - MSISession* _session = object; - MSIMessage* _msg; - - _msg = parse_message ( data ); - - if ( !_msg ) return; - - _msg->friend_id = source; - - - /* Now handle message */ - - if ( _msg->request.header_value ) { /* Handle request */ - - const uint8_t* _request_value = _msg->request.header_value; - - if ( same ( _request_value, stringify_request ( invite ) ) ) { - handle_recv_invite ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( start ) ) ) { - handle_recv_start ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { - handle_recv_cancel ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( reject ) ) ) { - handle_recv_reject ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( end ) ) ) { - handle_recv_end ( _session, _msg ); - } - - else { - free_message ( _msg ); - return; - } - - } else if ( _msg->response.header_value ) { /* Handle response */ - - const uint8_t* _response_value = _msg->response.header_value; - - if ( same ( _response_value, stringify_response ( ringing ) ) ) { - handle_recv_ringing ( _session, _msg ); - - } else if ( same ( _response_value, stringify_response ( starting ) ) ) { - handle_recv_starting ( _session, _msg ); - - } else if ( same ( _response_value, stringify_response ( ending ) ) ) { - handle_recv_ending ( _session, _msg ); - - } else if ( same ( _response_value, stringify_response ( error ) ) ) { - handle_recv_error ( _session, _msg ); - } else { - free_message ( _msg ); - return; - } - - /* Got response so cancel timer */ - if ( _session->call ) - event.timer_release ( _session->call->request_timer_id ); - - } - - free_message ( _msg ); -} - - /** * @brief Speaks for it self. * @@ -1076,6 +978,111 @@ int handle_recv_error ( MSISession* session, MSIMessage* msg ) { } +/** + * @brief BASIC call flow: + * + * ALICE BOB + * | invite --> | + * | | + * | <-- ringing | + * | | + * | <-- starting | + * | | + * | start --> | + * | | + * | <-- MEDIA TRANS --> | + * | | + * | end --> | + * | | + * | <-- ending | + * + * Alice calls Bob by sending invite packet. + * Bob recvs the packet and sends an ringing packet; + * which notifies Alice that her invite is acknowledged. + * Ringing screen shown on both sides. + * Bob accepts the invite for a call by sending starting packet. + * Alice recvs the starting packet and sends the started packet to + * inform Bob that she recved the starting packet. + * Now the media transmission is established ( i.e. RTP transmission ). + * Alice hangs up and sends end packet. + * Bob recves the end packet and sends ending packet + * as the acknowledgement that the call is ending. + * + * + */ +void msi_handle_packet ( Messenger* messenger, int source, uint8_t* data, uint16_t length, void* object ) +{ + /* Unused */ + (void)messenger; + (void)&length; + + MSISession* _session = object; + MSIMessage* _msg; + + _msg = parse_message ( data ); + + if ( !_msg ) return; + + _msg->friend_id = source; + + + /* Now handle message */ + + if ( _msg->request.header_value ) { /* Handle request */ + + const uint8_t* _request_value = _msg->request.header_value; + + if ( same ( _request_value, stringify_request ( invite ) ) ) { + handle_recv_invite ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( start ) ) ) { + handle_recv_start ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { + handle_recv_cancel ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( reject ) ) ) { + handle_recv_reject ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( end ) ) ) { + handle_recv_end ( _session, _msg ); + } + + else { + free_message ( _msg ); + return; + } + + } else if ( _msg->response.header_value ) { /* Handle response */ + + const uint8_t* _response_value = _msg->response.header_value; + + if ( same ( _response_value, stringify_response ( ringing ) ) ) { + handle_recv_ringing ( _session, _msg ); + + } else if ( same ( _response_value, stringify_response ( starting ) ) ) { + handle_recv_starting ( _session, _msg ); + + } else if ( same ( _response_value, stringify_response ( ending ) ) ) { + handle_recv_ending ( _session, _msg ); + + } else if ( same ( _response_value, stringify_response ( error ) ) ) { + handle_recv_error ( _session, _msg ); + } else { + free_message ( _msg ); + return; + } + + /* Got response so cancel timer */ + if ( _session->call ) + event.timer_release ( _session->call->request_timer_id ); + + } + + free_message ( _msg ); +} + + /******************************************************************************************************************** * ******************************************************************************************************************* ******************************************************************************************************************** diff --git a/toxav/toxmsi.h b/toxav/toxmsi.h index c45662a6..63cff9e5 100755 --- a/toxav/toxmsi.h +++ b/toxav/toxmsi.h @@ -41,7 +41,7 @@ typedef void* ( *MSICallback ) ( void* arg ); */ typedef enum { type_audio = 70, - type_video, + type_video } MSICallType; @@ -133,7 +133,7 @@ typedef enum { /* Protocol */ cb_error, - cb_timeout, + cb_timeout } MSICallbackID; diff --git a/toxav/toxrtp.c b/toxav/toxrtp.c index 03d20363..6b5ded45 100755 --- a/toxav/toxrtp.c +++ b/toxav/toxrtp.c @@ -28,8 +28,7 @@ #include "toxrtp.h" #include -#include -#include +#include #include "../toxcore/util.h" #include "../toxcore/network.h" @@ -59,6 +58,88 @@ #define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) +/** + * @brief Converts 4 bytes to uint32_t + * + * @param dest Where to convert + * @param bytes What bytes + * @return void + */ +inline__ void bytes_to_U32(uint32_t* dest, const uint8_t* bytes) +{ + *dest = +#ifdef WORDS_BIGENDIAN + ( ( uint32_t ) * bytes ) | + ( ( uint32_t ) * ( bytes + 1 ) << 8 ) | + ( ( uint32_t ) * ( bytes + 2 ) << 16 ) | + ( ( uint32_t ) * ( bytes + 3 ) << 24 ) ; +#else + ( ( uint32_t ) * bytes << 24 ) | + ( ( uint32_t ) * ( bytes + 1 ) << 16 ) | + ( ( uint32_t ) * ( bytes + 2 ) << 8 ) | + ( ( uint32_t ) * ( bytes + 3 ) ) ; +#endif +} + +/** + * @brief Converts 2 bytes to uint16_t + * + * @param dest Where to convert + * @param bytes What bytes + * @return void + */ +inline__ void bytes_to_U16(uint16_t* dest, const uint8_t* bytes) +{ + *dest = +#ifdef WORDS_BIGENDIAN + ( ( uint16_t ) * bytes ) | + ( ( uint16_t ) * ( bytes + 1 ) << 8 ); +#else + ( ( uint16_t ) * bytes << 8 ) | + ( ( uint16_t ) * ( bytes + 1 ) ); +#endif +} + +/** + * @brief Convert uint32_t to byte string of size 4 + * + * @param dest Where to convert + * @param value The value + * @return void + */ +inline__ void U32_to_bytes(uint8_t* dest, uint32_t value) +{ +#ifdef WORDS_BIGENDIAN + *(dest) = ( value ); + *(dest + 1) = ( value >> 8 ); + *(dest + 2) = ( value >> 16 ); + *(dest + 3) = ( value >> 24 ); +#else + *(dest) = ( value >> 24 ); + *(dest + 1) = ( value >> 16 ); + *(dest + 2) = ( value >> 8 ); + *(dest + 3) = ( value ); +#endif +} + +/** + * @brief Convert uint16_t to byte string of size 2 + * + * @param dest Where to convert + * @param value The value + * @return void + */ +inline__ void U16_to_bytes(uint8_t* dest, uint16_t value) +{ +#ifdef WORDS_BIGENDIAN + *(dest) = ( value ); + *(dest + 1) = ( value >> 8 ); +#else + *(dest) = ( value >> 8 ); + *(dest + 1) = ( value ); +#endif +} + /** * @brief Checks if message came in late. @@ -89,25 +170,31 @@ inline__ int check_late_message (RTPSession* session, RTPMessage* msg) */ inline__ void increase_nonce(uint8_t* nonce, uint16_t target) { - uint16_t _nonce_counter = ((uint16_t)( - (((uint16_t) nonce [crypto_box_NONCEBYTES - 1]) << 8 ) | - (((uint16_t) nonce [crypto_box_NONCEBYTES - 2]) ))); - + uint16_t _nonce_counter; + + uint8_t _reverse_bytes[2]; + _reverse_bytes[0] = nonce[crypto_box_NONCEBYTES - 1]; + _reverse_bytes[1] = nonce[crypto_box_NONCEBYTES - 2]; + + bytes_to_U16(&_nonce_counter, _reverse_bytes ); + /* Check overflow */ - if (_nonce_counter > USHRT_MAX - target ) { /* 2 bytes are not long enough */ - int _it = 3; + if (_nonce_counter > UINT16_MAX - target ) { /* 2 bytes are not long enough */ + uint8_t _it = 3; while ( _it <= crypto_box_NONCEBYTES ) _it += ++nonce[crypto_box_NONCEBYTES - _it] ? crypto_box_NONCEBYTES : 1; - _nonce_counter = _nonce_counter - (USHRT_MAX - target ); /* Assign the rest of it */ + _nonce_counter = _nonce_counter - (UINT16_MAX - target ); /* Assign the rest of it */ } else { /* Increase nonce */ _nonce_counter+= target; } - /* Assign the 8 last bytes */ + /* Assign the last bytes */ + + U16_to_bytes( _reverse_bytes, _nonce_counter); + nonce [crypto_box_NONCEBYTES - 1] = _reverse_bytes[0]; + nonce [crypto_box_NONCEBYTES - 2] = _reverse_bytes[1]; - nonce [crypto_box_NONCEBYTES - 1] = (uint8_t) (_nonce_counter >> 8); - nonce [crypto_box_NONCEBYTES - 2] = (uint8_t) (_nonce_counter); } @@ -141,15 +228,15 @@ static const uint32_t payload_table[] = * @return RTPHeader* Extracted header. * @retval NULL Error occurred while extracting header. */ -RTPHeader* extract_header ( const uint8_t* payload, size_t length ) +RTPHeader* extract_header ( const uint8_t* payload, int length ) { - if ( !payload ) { + if ( !payload || !length ) { return NULL; } const uint8_t* _it = payload; - RTPHeader* _retu = calloc(sizeof(RTPHeader), 1); + RTPHeader* _retu = calloc(1, sizeof (RTPHeader)); assert(_retu); _retu->flags = *_it; ++_it; @@ -168,7 +255,7 @@ RTPHeader* extract_header ( const uint8_t* payload, size_t 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 ); + uint8_t _cc = GET_FLAG_CSRCC ( _retu ); uint32_t _length = 12 /* Minimum header len */ + ( _cc * 4 ); if ( length < _length ) { @@ -178,7 +265,7 @@ RTPHeader* extract_header ( const uint8_t* payload, size_t length ) } if ( _cc > 0 ) { - _retu->csrc = calloc ( sizeof ( uint32_t ), _cc ); + _retu->csrc = calloc (_cc, sizeof (uint32_t)); assert(_retu->csrc); } else { /* But this should not happen ever */ @@ -191,26 +278,13 @@ RTPHeader* extract_header ( const uint8_t* payload, size_t length ) _retu->marker_payloadt = *_it; ++_it; _retu->length = _length; - _retu->timestamp = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( * ( _it + 3 ) ) ; - _it += 4; + bytes_to_U32(&_retu->timestamp, _it); _it += 4; + bytes_to_U32(&_retu->ssrc, _it); - _retu->ssrc = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( ( uint32_t ) * ( _it + 3 ) ) ; - - - size_t _x; + uint8_t _x; for ( _x = 0; _x < _cc; _x++ ) { - _it += 4; - _retu->csrc[_x] = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( ( uint32_t ) * ( _it + 3 ) ) ; + _it += 4; bytes_to_U32(&(_retu->csrc[_x]), _it); } return _retu; @@ -228,29 +302,26 @@ RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length ) { const uint8_t* _it = payload; - RTPExtHeader* _retu = calloc(sizeof(RTPExtHeader), 1); + RTPExtHeader* _retu = calloc(1, sizeof (RTPExtHeader)); assert(_retu); - uint16_t _ext_length = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it += 2; + uint16_t _ext_length; + bytes_to_U16(&_ext_length, _it); _it += 2; + if ( length < ( _ext_length * sizeof(uint32_t) ) ) { return NULL; } _retu->length = _ext_length; - _retu->type = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it -= 2; + bytes_to_U16(&_retu->type, _it); _it += 2; - _retu->table = calloc(sizeof(uint32_t), _ext_length ); + _retu->table = calloc(_ext_length, sizeof (uint32_t)); assert(_retu->table); - uint32_t* _table = _retu->table; - size_t _i; - for ( _i = 0; _i < _ext_length; _i++ ) { - _it += 4; - _table[_i] = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( ( uint32_t ) * ( _it + 3 ) ) ; + uint16_t _x; + for ( _x = 0; _x < _ext_length; _x++ ) { + _it += 4; bytes_to_U32(&(_retu->table[_x]), _it); } return _retu; @@ -271,33 +342,18 @@ uint8_t* add_header ( RTPHeader* header, uint8_t* payload ) /* Add sequence number first */ - *_it = ( header->sequnum >> 8 ); ++_it; - *_it = ( header->sequnum ); ++_it; + U16_to_bytes(_it, header->sequnum); _it += 2; *_it = header->flags; ++_it; *_it = header->marker_payloadt; ++_it; - uint32_t _timestamp = header->timestamp; - *_it = ( _timestamp >> 24 ); ++_it; - *_it = ( _timestamp >> 16 ); ++_it; - *_it = ( _timestamp >> 8 ); ++_it; - *_it = ( _timestamp ); ++_it; - - uint32_t _ssrc = header->ssrc; - *_it = ( _ssrc >> 24 ); ++_it; - *_it = ( _ssrc >> 16 ); ++_it; - *_it = ( _ssrc >> 8 ); ++_it; - *_it = ( _ssrc ); - - uint32_t *_csrc = header->csrc; - size_t _x; + U32_to_bytes( _it, header->timestamp); _it+=4; + U32_to_bytes( _it, header->ssrc); + + uint8_t _x; for ( _x = 0; _x < _cc; _x++ ) { - ++_it; - *_it = ( _csrc[_x] >> 24 ); ++_it; - *_it = ( _csrc[_x] >> 16 ); ++_it; - *_it = ( _csrc[_x] >> 8 ); ++_it; - *_it = ( _csrc[_x] ); + _it+=4; U32_to_bytes( _it, header->csrc[_x]); } return _it; @@ -314,21 +370,12 @@ uint8_t* add_ext_header ( RTPExtHeader* header, uint8_t* payload ) { uint8_t* _it = payload; - *_it = ( header->length >> 8 ); _it++; - *_it = ( header->length ); _it++; + U16_to_bytes(_it, header->length); _it+=2; + U16_to_bytes(_it, header->type); _it-=2; /* Return to 0 position */ - *_it = ( header->type >> 8 ); ++_it; - *_it = ( header->type ); - - size_t x; - - uint32_t* _hd_ext = header->table; - for ( x = 0; x < header->length; x++ ) { - ++_it; - *_it = ( _hd_ext[x] >> 24 ); ++_it; - *_it = ( _hd_ext[x] >> 16 ); ++_it; - *_it = ( _hd_ext[x] >> 8 ); ++_it; - *_it = ( _hd_ext[x] ); + uint16_t _x; + for ( _x = 0; _x < header->length; _x++ ) { + _it+=4; U32_to_bytes(_it, header->table[_x]); } return _it; @@ -342,8 +389,7 @@ uint8_t* add_ext_header ( RTPExtHeader* header, uint8_t* payload ) */ RTPHeader* build_header ( RTPSession* session ) { - RTPHeader* _retu; - _retu = calloc ( sizeof * _retu, 1 ); + RTPHeader* _retu = calloc ( 1, sizeof (RTPHeader) ); assert(_retu); ADD_FLAG_VERSION ( _retu, session->version ); @@ -358,7 +404,7 @@ RTPHeader* build_header ( RTPSession* session ) _retu->ssrc = session->ssrc; if ( session->cc > 0 ) { - _retu->csrc = calloc(sizeof(uint32_t), session->cc); + _retu->csrc = calloc(session->cc, sizeof (uint32_t)); assert(_retu->csrc); int i; @@ -388,12 +434,9 @@ RTPHeader* build_header ( RTPSession* session ) * @return RTPMessage* * @retval NULL Error occurred. */ -RTPMessage* msg_parse ( RTPSession* session, uint16_t sequnum, const uint8_t* data, uint32_t length ) -{ - assert( length != -1); - - RTPMessage* _retu = calloc(sizeof(RTPMessage), 1); - assert(_retu); +RTPMessage* msg_parse ( uint16_t sequnum, const uint8_t* data, int length ) +{ + RTPMessage* _retu = calloc(1, sizeof (RTPMessage)); _retu->header = extract_header ( data, length ); /* It allocates memory and all */ @@ -413,7 +456,7 @@ RTPMessage* msg_parse ( RTPSession* session, uint16_t sequnum, const uint8_t* da 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 { + } else { /* Error */ free (_retu->ext_header); free (_retu->header); free (_retu); @@ -423,20 +466,9 @@ RTPMessage* msg_parse ( RTPSession* session, uint16_t sequnum, const uint8_t* da _retu->ext_header = NULL; } - /* Get the payload */ - _retu->data = calloc ( sizeof ( uint8_t ), _retu->length ); - assert(_retu->data); - memcpy ( _retu->data, data + _from_pos, length - _from_pos ); - _retu->next = NULL; - - if ( session && check_late_message ( session, _retu) < 0 ){ - session->rsequnum = _retu->header->sequnum; - session->timestamp = _retu->header->timestamp; - } - return _retu; } @@ -460,8 +492,9 @@ int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t l return -1; uint8_t _plain[MAX_UDP_PACKET_SIZE]; - - uint16_t _sequnum = ( ( uint16_t ) data[1] << 8 ) | data[2]; + + uint16_t _sequnum; + bytes_to_U16(&_sequnum, data + 1); /* Clculate the right nonce */ uint8_t _calculated[crypto_box_NONCEBYTES]; @@ -500,10 +533,9 @@ int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t l } } - _msg = msg_parse ( NULL, _sequnum, _plain, _decrypted_length ); + _msg = msg_parse ( _sequnum, _plain, _decrypted_length ); - if ( !_msg ) - return -1; + if ( !_msg ) return -1; /* Hopefully this goes well * NOTE: Is this even used? @@ -548,7 +580,7 @@ RTPMessage* rtp_new_message ( RTPSession* session, const uint8_t* data, uint32_t return NULL; uint8_t* _from_pos; - RTPMessage* _retu = calloc(sizeof(RTPMessage), 1); + RTPMessage* _retu = calloc(1, sizeof (RTPMessage)); assert(_retu); /* Sets header values and copies the extension header in _retu */ @@ -560,17 +592,10 @@ RTPMessage* rtp_new_message ( RTPSession* session, const uint8_t* data, uint32_t if ( _retu->ext_header ) { _total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); - /* Allocate Memory for _retu->_data */ - _retu->data = calloc ( sizeof _retu->data, _total_length ); - assert(_retu->data); _from_pos = add_header ( _retu->header, _retu->data ); _from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 ); } else { - /* Allocate Memory for _retu->_data */ - _retu->data = calloc ( sizeof _retu->data, _total_length ); - assert(_retu->data); - _from_pos = add_header ( _retu->header, _retu->data ); } @@ -590,6 +615,11 @@ RTPMessage* rtp_new_message ( RTPSession* session, const uint8_t* data, uint32_t } + + + + + /******************************************************************************************************************** ******************************************************************************************************************** ******************************************************************************************************************** @@ -733,14 +763,13 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin /** * @brief Speaks for it self. * - * @param session The control session msg belongs to. It can be NULL. + * @param session The control session msg belongs to. You set it as NULL when freeing recved messages. + * Otherwise set it to session the message was created from. * @param msg The message. * @return void */ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ) { - free ( msg->data ); - if ( !session ){ free ( msg->header->csrc ); if ( msg->ext_header ){ @@ -793,7 +822,7 @@ RTPSession* rtp_init_session ( int payload_type, return NULL; } - RTPSession* _retu = calloc(sizeof(RTPSession), 1); + RTPSession* _retu = calloc(1, sizeof(RTPSession)); assert(_retu); networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu); @@ -819,15 +848,15 @@ RTPSession* rtp_init_session ( int payload_type, _retu->decrypt_key = decrypt_key; /* Need to allocate new memory */ - _retu->encrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->encrypt_nonce); - _retu->decrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->decrypt_nonce); - _retu->nonce_cycle = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->nonce_cycle); + _retu->encrypt_nonce = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) ); assert(_retu->encrypt_nonce); + _retu->decrypt_nonce = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) ); assert(_retu->decrypt_nonce); + _retu->nonce_cycle = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) ); assert(_retu->nonce_cycle); memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_box_NONCEBYTES); memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_box_NONCEBYTES); memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_box_NONCEBYTES); - _retu->csrc = calloc(sizeof(uint32_t), 1); + _retu->csrc = calloc(1, sizeof (uint32_t)); assert(_retu->csrc); _retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */ diff --git a/toxav/toxrtp.h b/toxav/toxrtp.h index 32234ebe..9f8ae5ee 100755 --- a/toxav/toxrtp.h +++ b/toxav/toxrtp.h @@ -27,13 +27,14 @@ #define RTP_VERSION 2 #include +#include #include "../toxcore/tox.h" #define MAX_SEQU_NUM 65535 - +#define MAX_RTP_SIZE 1400 /** - * @brief Standard rtp header. + * @brief Standard rtp header * */ @@ -69,7 +70,7 @@ typedef struct _RTPMessage { RTPHeader* header; RTPExtHeader* ext_header; - uint8_t* data; + uint8_t data[MAX_RTP_SIZE]; uint32_t length; tox_IP_Port from; diff --git a/toxcore/event.c b/toxcore/event.c index 17e68c87..81f8172f 100755 --- a/toxcore/event.c +++ b/toxcore/event.c @@ -39,11 +39,12 @@ #include #include #include +#include -#define RUN_IN_THREAD(func, args) { pthread_t _tid; \ - pthread_create(&_tid, NULL, func, args); assert( pthread_detach(_tid) == 0 ); } +#define RUN_IN_THREAD(func, args) { pthread_t _tid; \ +pthread_create(&_tid, NULL, func, args); assert( pthread_detach(_tid) == 0 ); } -#define LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex) +#define LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex) #define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex) #define FREQUENCY 10000 @@ -52,21 +53,21 @@ typedef struct _EventContainer { - void* (*func)(void*); - void* func_args; - unsigned timeout; - long long id; - + void* (*func)(void*); + void* func_args; + unsigned timeout; + long long id; + } EventContainer; typedef struct _EventHandler { EventContainer* timed_events; - size_t timed_events_count; - - int running; - + size_t timed_events_count; + + int running; + pthread_mutex_t mutex; - + } EventHandler; int throw_event( void* (func)(void*), void* arg ); @@ -90,7 +91,7 @@ struct _Event event = void clear_events (EventContainer** event_container, size_t* counter) { free(*event_container ); - + *event_container = NULL; *counter = 0; } @@ -99,62 +100,86 @@ int pop_id ( EventContainer** event_container, size_t* counter, int id ) { if ( !*event_container || !*counter || !id ) return -1; - + EventContainer* _it = *event_container; int i; - + for ( i = *counter; i; -- i ){ if ( _it->id == id ) { /* Hit! */ break; } ++_it; } - + if ( i ) { for ( ; i; -- i ){ *_it = *(_it + 1); ++_it; } -- (*counter ); - *event_container = realloc(*event_container, sizeof(EventContainer) * (*counter )); /* resize */ - - return 0; - + + if ( !(*counter)) { /* Free and set to NULL */ + free(*event_container); + *event_container = NULL; + } + else { + void* _result = realloc(*event_container, sizeof(EventContainer) * (*counter )); /* resize */ + + + if ( _result != NULL ) { *event_container = _result; return 0; } + else { + /* Not sure what would happen next so abort execution. + */ + fprintf(stderr, "CRITICAL! Failed to reallocate memory in %s():%d, aborting...", __func__, __LINE__); + abort(); + return -1; + } + } } - + /* not found here */ - + return -1; } void push_event ( EventContainer** container, size_t* counter, void* (func)(void*), void* arg ) { - (*container ) = realloc((*container ), sizeof(EventContainer) * ((*counter ) + 1)); - assert((*container ) != NULL); - - (*container )[*counter].func = func; - (*container )[*counter].func_args = arg; - (*container )[*counter].timeout = 0; - (*container )[*counter].id = 0; - + EventContainer* _new = realloc((*container ), sizeof(EventContainer) * ((*counter ) + 1)); + + if ( _new == NULL ) { + /* Not sure what would happen next so abort execution. + * TODO: This could notice the calling function + * about realloc failing. + */ + fprintf(stderr, "CRITICAL! Failed to reallocate memory in %s():%d, aborting...", __func__, __LINE__); + abort(); + } + + _new[*counter].func = func; + _new[*counter].func_args = arg; + _new[*counter].timeout = 0; + _new[*counter].id = 0; + + (*container) = _new; + (*counter )++; } void reorder_events ( size_t counter, EventContainer* container, unsigned timeout ) { if ( counter > 1 ) { - + int i = counter - 1; - + /* start from behind excluding last added member */ EventContainer* _it = &container[i - 1]; - + EventContainer _last_added = container[i]; - + for ( ; i; --i ) { if ( _it->timeout > timeout ){ *(_it + 1) = *_it; *_it = _last_added; -- _it; } } - + } } @@ -164,40 +189,40 @@ void reorder_events ( size_t counter, EventContainer* container, unsigned timeou void* event_poll( void* arg ) { EventHandler* _event_handler = arg; - + while ( _event_handler->running ) { - - LOCK( _event_handler ); - + + LOCK( _event_handler ); + if ( _event_handler->timed_events ){ - + uint32_t _time = ((uint32_t)(current_time() / 1000)); - + if ( _event_handler->timed_events[0].timeout < _time ) { - + RUN_IN_THREAD ( _event_handler->timed_events[0].func, _event_handler->timed_events[0].func_args ); - + pop_id(&_event_handler->timed_events, &_event_handler->timed_events_count, - _event_handler->timed_events[0].id); - + _event_handler->timed_events[0].id); + } - + } - - UNLOCK( _event_handler ); - + + UNLOCK( _event_handler ); + usleep(FREQUENCY); } - -LOCK( _event_handler ); - + + LOCK( _event_handler ); + clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count); - -UNLOCK( _event_handler ); - + + UNLOCK( _event_handler ); + _event_handler->running = -1; pthread_exit(NULL); } @@ -207,7 +232,7 @@ int throw_event( void* (func)(void*), void* arg ) pthread_t _tid; int _rc = pthread_create(&_tid, NULL, func, arg ); - + return (0 != _rc ) ? _rc : pthread_detach(_tid); } @@ -217,31 +242,31 @@ EventHandler event_handler; int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout) { static int _unique_id = 1; - + push_event(&event_handler.timed_events, &(event_handler.timed_events_count), func, arg ); - + size_t _counter = event_handler.timed_events_count; - + event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)(current_time() / 1000)); event_handler.timed_events[_counter - 1].id = _unique_id; ++_unique_id; - - + + /* reorder */ - + reorder_events(_counter, event_handler.timed_events, timeout ); - + return _unique_id - 1; } int execute_timer_event ( int id ) { int _status; - -LOCK((&event_handler)); + + LOCK((&event_handler)); EventContainer* _it = event_handler.timed_events; - + int _i = event_handler.timed_events_count; - + /* Find it and execute */ for ( ; _i; _i-- ) { if ( _it->id == id ) { @@ -250,36 +275,51 @@ LOCK((&event_handler)); } ++_it; } - + /* Now remove it from the queue */ - + if ( _i ) { for ( ; _i; -- _i ){ *_it = *(_it + 1); ++_it; } + -- event_handler.timed_events_count; - - event_handler.timed_events = realloc - (event_handler.timed_events, sizeof(EventContainer) * event_handler.timed_events_count); /* resize */ - + + if ( !event_handler.timed_events_count ) { /* Free and set to null */ + free(event_handler.timed_events); + event_handler.timed_events = NULL; + } + else { + void* _result = realloc(event_handler.timed_events, sizeof(EventContainer) * event_handler.timed_events_count); /* resize */ + + if ( _result != NULL ) { event_handler.timed_events = _result; } + else { + /* Not sure what would happen next so abort execution. + */ + fprintf(stderr, "CRITICAL! Failed to reallocate memory in %s():%d, aborting...", __func__, __LINE__); + abort(); + return -1; + } + } + _status = 0; - + } else _status = -1; - -UNLOCK((&event_handler)); - + + UNLOCK((&event_handler)); + return _status; } int reset_timer_event ( int id, uint32_t timeout ) { int _status; - -LOCK((&event_handler)); - + + LOCK((&event_handler)); + EventContainer* _it = event_handler.timed_events; - + int _i = event_handler.timed_events_count; - + /* Find it and change */ for ( ; _i; _i-- ) { if ( _it->id == id ) { @@ -288,11 +328,11 @@ LOCK((&event_handler)); } ++_it; } - + _status = _i ? -1 : 0; - -UNLOCK((&event_handler)); - + + UNLOCK((&event_handler)); + return _status; } @@ -312,11 +352,11 @@ void __attribute__((constructor)) init_event_poll () { event_handler.timed_events = NULL; event_handler.timed_events_count = 0; - + event_handler.running = 1; - + pthread_mutex_init(&event_handler.mutex, NULL); - + RUN_IN_THREAD(event_poll, &event_handler); } @@ -326,10 +366,10 @@ void __attribute__((destructor)) terminate_event_poll() event_handler.running = 0; /* Keep the global until thread exits */ - while (event_handler.running > -1) { - event_handler.running; - usleep(FREQUENCY*2); + while (event_handler.running > -1) { + (void)event_handler.running; + usleep(FREQUENCY*2); } - + pthread_mutex_destroy( &event_handler.mutex ); -} +} \ No newline at end of file -- cgit v1.2.3