From 6a78e2e71c1471b89646a71a1adeb0529cfb73d4 Mon Sep 17 00:00:00 2001 From: mannol Date: Fri, 7 Mar 2014 03:13:04 +0100 Subject: [PATCH] Fixed several bugs and added some features --- configure.ac | 3 +- libtoxav.pc | 11 ++++ toxav/media.c | 113 +++++++++++++++----------------- toxav/media.h | 11 +++- toxav/msi.c | 102 +++++++++++++++++------------ toxav/msi.h | 2 +- toxav/phone.c | 174 ++++++++++++++++++++++++++++++++++++++++++-------- toxav/rtp.c | 62 ++++++------------ toxav/rtp.h | 14 ++-- toxav/toxav.c | 139 ++++++++++++++++++++++++++++++++-------- toxav/toxav.h | 86 +++++++++++++++++++++---- 11 files changed, 493 insertions(+), 224 deletions(-) create mode 100644 libtoxav.pc mode change 100644 => 100755 toxav/msi.c mode change 100644 => 100755 toxav/msi.h mode change 100644 => 100755 toxav/phone.c mode change 100644 => 100755 toxav/rtp.c mode change 100644 => 100755 toxav/rtp.h mode change 100644 => 100755 toxav/toxav.c mode change 100644 => 100755 toxav/toxav.h diff --git a/configure.ac b/configure.ac index 6d856828..e916b4a4 100644 --- a/configure.ac +++ b/configure.ac @@ -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" diff --git a/libtoxav.pc b/libtoxav.pc new file mode 100644 index 00000000..48bc1cc4 --- /dev/null +++ b/libtoxav.pc @@ -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} diff --git a/toxav/media.c b/toxav/media.c index 2594f99a..59ca49b7 100644 --- a/toxav/media.c +++ b/toxav/media.c @@ -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); } diff --git a/toxav/media.h b/toxav/media.h index aed57ea2..323d22fd 100644 --- a/toxav/media.h +++ b/toxav/media.h @@ -38,6 +38,14 @@ /* Audio encoding/decoding */ #include +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); diff --git a/toxav/msi.c b/toxav/msi.c old mode 100644 new mode 100755 index e5e1e1c5..a38ab730 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -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 ); diff --git a/toxav/msi.h b/toxav/msi.h old mode 100644 new mode 100755 index a70685f8..83de0117 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -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 ); /** diff --git a/toxav/phone.c b/toxav/phone.c old mode 100644 new mode 100755 index 98e97873..95b49231 --- a/toxav/phone.c +++ b/toxav/phone.c @@ -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); diff --git a/toxav/rtp.c b/toxav/rtp.c old mode 100644 new mode 100755 index 8eca46d4..9b8cd652 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -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 */ diff --git a/toxav/rtp.h b/toxav/rtp.h old mode 100644 new mode 100755 index c2b68b01..58b16ab1 --- a/toxav/rtp.h +++ b/toxav/rtp.h @@ -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; diff --git a/toxav/toxav.c b/toxav/toxav.c old mode 100644 new mode 100755 index 977415dc..698fac3b --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -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; +} \ No newline at end of file diff --git a/toxav/toxav.h b/toxav/toxav.h old mode 100644 new mode 100755 index df5acfc6..3e66c230 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -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 */ \ No newline at end of file