From 292708c33634ee0b9a2243a2181018565558bc5c Mon Sep 17 00:00:00 2001 From: mannol Date: Sun, 9 Feb 2014 23:06:44 +0100 Subject: Started adding public API --- toxav/toxav.c | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 toxav/toxav.c (limited to 'toxav/toxav.c') diff --git a/toxav/toxav.c b/toxav/toxav.c new file mode 100644 index 00000000..8757d7fd --- /dev/null +++ b/toxav/toxav.c @@ -0,0 +1,352 @@ +/** toxav.c + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + * + * Report bugs/suggestions at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "toxav.h" +#include "../toxcore/tox.h" +#include "rtp.h" +#include "msi.h" +#include "media.h" + +#include +#include +#include + +#define inline__ inline __attribute__((always_inline)) + +static const uint8_t audio_index = 0, video_index = 1; + + +typedef enum { + ts_closing, + ts_running, + ts_closed + +} ThreadState; + +typedef struct _ToxAv +{ + Tox* messenger; + + MSISession* msi_session; /** Main msi session */ + + RTPSession* rtp_sessions[2]; /* Audio is first and video is second */ + + /* TODO: Add media session */ + struct jitter_buffer* j_buf; + CodecState* cs; + /* TODO: Add media session threads */ + + + void* agent_handler; +} ToxAv; + + + + + +/******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + * + * + * + * PUBLIC API FUNCTIONS IMPLEMENTATIONS + * + * + * + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ********************************************************************************************************************/ + + + +ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name ) +{ + ToxAv* av = calloc ( sizeof(ToxAv), 1); + + av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name ); + av->msi_session->agent_handler = av; + + av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; + + av->messenger = messenger; + + /* NOTE: This should be user defined or? */ + av->j_buf = create_queue(20); + + av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER); + + av->agent_handler = useragent; + + return av; +} + +void toxav_kill ( ToxAv* av ) +{ + msi_terminate_session(av->msi_session); + + if ( av->rtp_sessions[audio_index] ) { + rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle); + } + + if ( av->rtp_sessions[video_index] ) { + rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle); + } + + codec_terminate_session(av->cs); + + free(av); +} + +void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id ) +{ + msi_register_callback((MSICallback)callback, (MSICallbackID) id); +} + + + +int toxav_call (ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds ) +{ + if ( av->msi_session->call ) { + return ErrorAlreadyInCall; + } + + return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user); +} + +int toxav_hangup ( ToxAv* av ) +{ + if ( !av->msi_session->call ) { + return ErrorNoCall; + } + + if ( av->msi_session->call->state != call_active ) { + return ErrorInvalidState; + } + + return msi_hangup(av->msi_session); +} + +int toxav_answer ( ToxAv* av, ToxAvCallType call_type ) +{ + if ( !av->msi_session->call ) { + return ErrorNoCall; + } + + if ( av->msi_session->call->state != call_starting ) { + return ErrorInvalidState; + } + + return msi_answer(av->msi_session, call_type); +} + +int toxav_reject ( ToxAv* av, const char* reason ) +{ + if ( !av->msi_session->call ) { + return ErrorNoCall; + } + + if ( av->msi_session->call->state != call_starting ) { + return ErrorInvalidState; + } + + return msi_reject(av->msi_session, (const uint8_t*) reason); +} + +int toxav_cancel ( ToxAv* av, const char* reason ) +{ + if ( !av->msi_session->call ) { + return ErrorNoCall; + } + + return msi_cancel(av->msi_session, 0, (const uint8_t*)reason); +} + +/* You can stop the call at any state */ +int toxav_stop_call ( ToxAv* av ) +{ + if ( !av->msi_session->call ) { + return ErrorNoCall; + } + + return msi_stopcall(av->msi_session); +} + + +int toxav_prepare_transmission ( ToxAv* av ) +{ + assert(av->msi_session); + if ( !av->msi_session || !av->msi_session->call ) { + return ErrorNoCall; + } + + av->rtp_sessions[audio_index] = rtp_init_session( + type_audio, + 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[audio_index] ) { + fprintf(stderr, "Error while starting audio RTP session!\n"); + 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 ( !av->rtp_sessions[video_index] ) { + fprintf(stderr, "Error while starting video RTP session!\n"); + return ErrorStartingVideoRtp; + } + + return ErrorNone; +} + + +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) ) { + fprintf(stderr, "Error while terminating audio RTP session!\n"); + return ErrorTerminatingAudioRtp; + } + + if ( -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) { + fprintf(stderr, "Error while terminating video RTP session!\n"); + return ErrorTerminatingVideoRtp; + } + + return ErrorNone; +} + + +inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length ) +{ + if ( av->rtp_sessions[type - TypeAudio] ) + return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); + else return -1; +} + +inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest ) +{ + if ( !dest ) return ErrorInternal; + + if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession; + + RTPMessage* message; + + if ( type == TypeAudio ) { + + message = rtp_recv_msg(av->rtp_sessions[audio_index]); + + if (message) { + /* push the packet into the queue */ + queue(av->j_buf, message); + } + + if (ready) { + int success = 0; + message = dequeue(av->j_buf, &success); + + if ( success == 2) return ErrorAudioPacketLost; + } + else return 0; + } + else { + message = rtp_recv_msg(av->rtp_sessions[video_index]); + } + + if ( message ) { + memcpy(dest, message->data, message->length); + + int length = message->length; + + rtp_free_msg(NULL, message); + + return length; + } + + return 0; +} + +inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ) +{ + if ( !dest ) return ErrorInternal; + + return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1); +} + +inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ) +{ + if ( !dest ) + return ErrorInternal; + + return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE); +} + +int toxav_get_peer_transmission_type ( 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->type_peer[peer]; +} + +void* toxav_get_agent_handler ( ToxAv* av ) +{ + return av->agent_handler; +} + + +/* Only temporary */ +void* get_cs_temp(ToxAv* av) +{ + return av->cs; +} -- cgit v1.2.3 From 393433ce9910c3dffed9090c7965654f23a8e7a8 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 15 Feb 2014 20:44:33 +0100 Subject: Public header ready to go --- configure.ac | 92 ++++++----- toxav/Makefile.inc | 134 ++++------------ toxav/media.c | 151 ++++------------- toxav/media.h | 78 ++------- toxav/msi.c | 40 +++-- toxav/msi.h | 9 +- toxav/phone.c | 401 +++++++++++++++++++++++++++++++--------------- toxav/rtp.c | 55 +++---- toxav/rtp.h | 18 ++- toxav/toxav.c | 128 ++++++++++----- toxav/toxav.h | 47 ++++-- toxcore/DHT.c | 10 +- toxcore/Messenger.c | 158 +++++++++++++++++- toxcore/Messenger.h | 34 ++++ toxcore/event.c | 1 + toxcore/friend_requests.c | 3 + toxcore/group_chats.c | 30 +++- toxcore/network.c | 4 +- toxcore/network.h | 9 ++ toxcore/onion.c | 24 +++ toxcore/onion.h | 1 + toxcore/onion_announce.c | 2 +- toxcore/onion_client.c | 29 +++- toxcore/onion_client.h | 2 + toxcore/tox.c | 7 + toxcore/tox.h | 10 ++ 26 files changed, 915 insertions(+), 562 deletions(-) (limited to 'toxav/toxav.c') diff --git a/configure.ac b/configure.ac index afb327cb..28b5e7e1 100644 --- a/configure.ac +++ b/configure.ac @@ -13,8 +13,7 @@ AC_CONFIG_MACRO_DIR([m4]) EXTRA_LT_LDFLAGS= LIBTOXCORE_LT_VERSION=0:0:0 -LIBTOXMSI_LT_VERSION=0:0:0 -LIBTOXRTP_LT_VERSION=0:0:0 +LIBTOXAV_LT_VERSION=0:0:0 dnl dnl current:revision:age dnl @@ -24,12 +23,10 @@ dnl incremented dnl age: increment if interfaces have been added, set to zero if dnl interfaces have been removed or changed TOXCORE_LT_LDFLAGS="-version-info $LIBTOXCORE_LT_VERSION" -TOXMSI_LT_LDFLAGS="-version-info $LIBTOXMSI_LT_VERSION" -TOXRTP_LT_LDFLAGS="-version-info $LIBTOXMSI_LT_VERSION" +TOXAV_LT_LDFLAGS="-version-info $LIBTOXAV_LT_VERSION" AC_SUBST(TOXCORE_LT_LDFLAGS) -AC_SUBST(TOXMSI_LT_LDFLAGS) -AC_SUBST(TOXRTP_LT_LDFLAGS) +AC_SUBST(TOXAV_LT_LDFLAGS) if test "x${prefix}" = "xNONE"; then prefix="${ac_default_prefix}" @@ -39,6 +36,7 @@ BUILD_DHT_BOOTSTRAP_DAEMON="yes" BUILD_NTOX="yes" BUILD_TESTS="yes" BUILD_AV="yes" +BUILD_PHONE="yes" BUILD_TESTING="yes" NCURSES_FOUND="no" @@ -64,12 +62,24 @@ AC_ARG_ENABLE([av], [ if test "x$enableval" = "xno"; then BUILD_AV="no" + BUILD_PHONE="no" elif test "x$enableval" = "xyes"; then BUILD_AV="yes" fi ] ) +AC_ARG_ENABLE([phone], + [AC_HELP_STRING([--disable-phone], [build test phone (default: auto)]) ], + [ + if test "x$enableval" = "xno"; then + BUILD_PHONE="no" + elif test "x$enableval" = "xyes"; then + BUILD_PHONE="yes" + fi + ] +) + AC_ARG_ENABLE([tests], [AC_HELP_STRING([--disable-tests], [build unit tests (default: auto)]) ], [ @@ -339,82 +349,79 @@ AC_C_BIGENDIAN AC_FUNC_FORK AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc]) -if test "x$BUILD_AV" = "xyes"; then - AX_PTHREAD( - [], - [ - AC_MSG_WARN([disabling AV support: required pthread library not found]) - BUILD_AV="no" - ] - ) -fi +AX_PTHREAD( + [], + [ + AC_MSG_ERROR([Error: required pthread library not found]) + ] +) -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([AVFORMAT], [libavformat], [], [ - AC_MSG_WARN([disabling AV support $AVFORMAT_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $AVFORMAT_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([AVCODEC], [libavcodec], [], [ - AC_MSG_WARN([disabling AV support $AVCODEC_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $AVCODEC_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([AVUTIL], [libavutil], [], [ - AC_MSG_WARN([disabling AV support $AVUTIL_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $AVUTIL_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([AVDEVICE], [libavdevice], [], [ - AC_MSG_WARN([disabling AV support $AVDEVICE_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $AVDEVICE_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([SWSCALE], [libswscale], [], [ - AC_MSG_WARN([disabling AV support $SWSCALE_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $SWSCALE_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([SDL], [sdl], [], [ - AC_MSG_WARN([disabling AV support $SDL_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $SDL_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi -if test "x$BUILD_AV" = "xyes"; then +if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([OPENAL], [openal], [], [ - AC_MSG_WARN([disabling AV support $OPENAL_PKG_ERRORS]) - BUILD_AV="no" + AC_MSG_WARN([disabling phone $OPENAL_PKG_ERRORS]) + BUILD_PHONE="no" ] ) fi @@ -425,6 +432,18 @@ if test "x$BUILD_AV" = "xyes"; then [ AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS]) BUILD_AV="no" + BUILD_PHONE="no" + ] + ) +fi + +if test "x$BUILD_AV" = "xyes"; then + PKG_CHECK_MODULES([VPX], [vpx], + [], + [ + AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS]) + BUILD_AV="no" + BUILD_PHONE="no" ] ) fi @@ -587,6 +606,7 @@ AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes") AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") +AM_CONDITIONAL(BUILD_PHONE, test "x$BUILD_PHONE" = "xyes") AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index 203d8a07..0472d361 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc @@ -1,105 +1,43 @@ if BUILD_AV -lib_LTLIBRARIES += libtoxrtp.la \ - libtoxmsi.la \ - libtoxmedia.la +lib_LTLIBRARIES += libtoxav.la +libtoxav_la_include_HEADERS = ../toxav/toxav.h +libtoxav_la_includedir = $(includedir)/tox + +libtoxav_la_SOURCES = ../toxav/rtp.h \ + ../toxav/rtp.c \ + ../toxav/msi.h \ + ../toxav/msi.c \ + ../toxav/media.h \ + ../toxav/media.c \ + ../toxav/toxav.h \ + ../toxav/toxav.c + + +libtoxav_la_CFLAGS = -I../toxcore \ + -I../toxav \ + $(NACL_CFLAGS) \ + $(OPUS_CFLAGS) \ + $(VPX_CFLAGS) + +libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \ + $(NACL_LDFLAGS) \ + $(EXTRA_LT_LDFLAGS) + +libtoxav_la_LIBS = $(NACL_LIBS) \ + $(OPUS_LIBS) \ + $(VPX_LIBS) - -# ****** RTP ****** # - -libtoxrtp_la_include_HEADERS = \ - ../toxav/toxrtp.h - -libtoxrtp_la_includedir = $(includedir)/tox - -libtoxrtp_la_SOURCES = ../toxav/toxrtp.h \ - ../toxav/toxrtp.c - -libtoxrtp_la_CFLAGS = -I../toxcore \ - -I../toxav \ - $(NACL_CFLAGS) - -libtoxrtp_la_LDFLAGS = $(TOXRTP_LT_LDFLAGS) \ - $(NACL_LDFLAGS) \ - $(EXTRA_LT_LDFLAGS) - -libtoxrtp_la_LIBS = libtoxcore.la \ - $(NACL_LIBS) - - +endif -# ****** MSI ****** # - -libtoxmsi_la_include_HEADERS = \ - ../toxav/toxmsi.h - -libtoxmsi_la_includedir = $(includedir)/tox - -libtoxmsi_la_SOURCES = ../toxav/toxmsi.h \ - ../toxav/toxmsi.c - -libtoxmsi_la_CFLAGS = -I../toxcore \ - -I../toxav \ - $(NACL_CFLAGS) - -libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ - $(EXTRA_LT_LDFLAGS) \ - $(NACL_LDFLAGS) - -libtoxmsi_la_LIBS = libtoxcore.la \ - $(NACL_LIBS) - -# ****** MEDIA ****** # - -libtoxmedia_la_include_HEADERS = \ - ../toxav/toxmedia.h - -libtoxmedia_la_includedir = $(includedir)/tox - -libtoxmedia_la_SOURCES = ../toxav/toxmedia.h \ - ../toxav/toxmedia.c +if BUILD_PHONE -libtoxmedia_la_CFLAGS = -I../toxcore \ - -I../toxav \ - $(AVFORMAT_CFLAGS) \ - $(AVCODEC_CFLAGS) \ - $(AVUTIL_CFLAGS) \ - $(AVDEVICE_CFLAGS) \ - $(SWSCALE_CFLAGS) \ - $(SDL_CFLAGS) \ - $(OPENAL_CFLAGS) \ - $(NACL_CFLAGS) \ - $(OPUS_CFLAGS) - - -libtoxmedia_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ - $(TOXRTP_LT_LDFLAGS) \ - $(EXTRA_LT_LDFLAGS) \ - $(NACL_LDFLAGS) - - -libtoxmedia_la_LIBS = libtoxcore.la \ - $(NACL_LDFLAGS) \ - $(AVFORMAT_LIBS) \ - $(AVCODEC_LIBS) \ - $(AVUTIL_LIBS) \ - $(AVDEVICE_LIBS) \ - $(SWSCALE_LIBS) \ - $(SDL_LIBS) \ - $(OPENAL_LIBS) \ - $(NACL_LIBS) \ - $(OPUS_LIBS) - - - - -# ***** PHONE ***** # noinst_PROGRAMS += phone @@ -113,25 +51,17 @@ phone_CFLAGS = -I../toxcore \ $(AVDEVICE_CFLAGS) \ $(SWSCALE_CFLAGS) \ $(SDL_CFLAGS) \ - $(OPENAL_CFLAGS) \ - $(NACL_CFLAGS) \ - $(OPUS_CFLAGS) - + $(OPENAL_CFLAGS) -phone_LDADD = libtoxrtp.la \ - libtoxmsi.la \ - libtoxmedia.la \ +phone_LDADD = libtoxav.la \ libtoxcore.la \ - $(NACL_LDFLAGS) \ $(AVFORMAT_LIBS) \ $(AVCODEC_LIBS) \ $(AVUTIL_LIBS) \ $(AVDEVICE_LIBS) \ $(SWSCALE_LIBS) \ $(SDL_LIBS) \ - $(OPENAL_LIBS) \ - $(NACL_LIBS) \ - $(OPUS_LIBS) + $(OPENAL_LIBS) endif \ No newline at end of file diff --git a/toxav/media.c b/toxav/media.c index e18c1803..a327c751 100644 --- a/toxav/media.c +++ b/toxav/media.c @@ -28,13 +28,8 @@ #endif /* HAVE_CONFIG_H */ #include +#include #include -#include -#include -#include -#include -#include -#include #include #include "rtp.h" @@ -206,25 +201,11 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) int init_video_decoder(CodecState *cs) { - cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); - - if (!cs->video_decoder) { + if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { fprintf(stderr, "Init video_decoder failed!\n"); return -1; } - - cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); - - if (!cs->video_decoder_ctx) { - fprintf(stderr, "Init video_decoder_ctx failed!\n"); - return -1; - } - - if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { - fprintf(stderr, "Opening video decoder failed!\n"); - return -1; - } - + return 0; } @@ -242,97 +223,32 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels) } -int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate) +int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) { - cs->video_input_format = av_find_input_format(video_driver); - - if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) { - fprintf(stderr, "Opening video_input_format failed!\n"); - return -1; - } - - avformat_find_stream_info(cs->video_format_ctx, NULL); - av_dump_format(cs->video_format_ctx, 0, webcam, 0); - - int i; - - for (i = 0; i < cs->video_format_ctx->nb_streams; ++i) { - if (cs->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - cs->video_stream = i; - break; - } - } - - cs->webcam_decoder_ctx = cs->video_format_ctx->streams[cs->video_stream]->codec; - cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id); - - if (cs->webcam_decoder == NULL) { - fprintf(stderr, "Unsupported codec!\n"); - return -1; - } - - if (cs->webcam_decoder_ctx == NULL) { - fprintf(stderr, "Init webcam_decoder_ctx failed!\n"); - return -1; - } - - if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) { - fprintf(stderr, "Opening webcam decoder failed!\n"); + vpx_codec_enc_cfg_t cfg; + 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)); return -1; } - - cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); - - if (!cs->video_encoder) { - fprintf(stderr, "Init video_encoder failed!\n"); - return -1; - } - - cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); - - if (!cs->video_encoder_ctx) { - fprintf(stderr, "Init video_encoder_ctx failed!\n"); - return -1; - } - - cs->video_encoder_ctx->bit_rate = video_bitrate; - 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 = video_bitrate * 6; - cs->video_encoder_ctx->profile = 3; - 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) { - fprintf(stderr, "Opening video encoder failed!\n"); + + cfg.rc_target_bitrate = video_bitrate; + cfg.g_w = width; + cfg.g_h = height; + if(vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { + fprintf(stderr, "Failed to initialize encoder\n"); return -1; } - return 0; } -int init_audio_encoder(CodecState *cs) +int init_audio_encoder(CodecState *cs, uint32_t audio_channels) { int err = OPUS_OK; - cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err); - + cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); - err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); - - /* NOTE: What do we do with this? */ - int nfo; - err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo)); + return err == OPUS_OK ? 0 : -1; } @@ -342,30 +258,26 @@ CodecState* codec_init_session ( uint32_t audio_bitrate, uint16_t audio_frame_duration, uint32_t audio_sample_rate, uint32_t audio_channels, - uint32_t video_bitrate, - const char* webcam, - const char* webcam_driver ) + uint16_t video_width, + uint16_t video_height, + uint32_t video_bitrate ) { - CodecState* _retu = av_calloc(sizeof(CodecState), 1); + CodecState* _retu = calloc(sizeof(CodecState), 1); assert(_retu); - - - avdevice_register_all(); - avcodec_register_all(); - av_register_all(); - - + _retu->audio_bitrate = audio_bitrate; _retu->audio_sample_rate = audio_sample_rate; - pthread_mutex_init(&_retu->ctrl_mutex, NULL); - - /* Encoders */ - if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) ) + if (!video_width || !video_height) { + video_width = 320; + video_height = 240; + } + + if ( 0 == init_video_encoder(_retu, video_width, video_height, video_bitrate) ) printf("Video encoder initialized!\n"); - if ( 0 == init_audio_encoder(_retu) ) + if ( 0 == init_audio_encoder(_retu, audio_channels) ) printf("Audio encoder initialized!\n"); @@ -391,7 +303,8 @@ void codec_terminate_session ( CodecState* cs ) 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); } diff --git a/toxav/media.h b/toxav/media.h index ef2de27c..4230de8f 100644 --- a/toxav/media.h +++ b/toxav/media.h @@ -27,66 +27,27 @@ #include #include -#include "../toxcore/tox.h" +#include -/* Video encoding/decoding */ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) +#define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) /* Audio encoding/decoding */ #include -/* ffmpeg VP8 codec ID */ -#define VIDEO_CODEC AV_CODEC_ID_VP8 - -/* ffmpeg Opus codec ID */ -#define AUDIO_CODEC AV_CODEC_ID_OPUS - -/* default video bitrate in bytes/s */ -#define VIDEO_BITRATE 10*1000 - -/* default audio bitrate in bytes/s */ -#define AUDIO_BITRATE 64000 - -/* audio frame duration in miliseconds */ -#define AUDIO_FRAME_DURATION 20 - -/* audio sample rate recommended to be 48kHz for Opus */ -#define AUDIO_SAMPLE_RATE 48000 - -/* the amount of samples in one audio frame */ -#define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000 - -/* the quit event for SDL */ -#define FF_QUIT_EVENT (SDL_USEREVENT + 2) - -#ifdef __linux__ -#define VIDEO_DRIVER "video4linux2" -#define DEFAULT_WEBCAM "/dev/video0" -#endif - -#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) -#define VIDEO_DRIVER "vfwcap" -#define DEFAULT_WEBCAM "0" -#endif typedef struct _CodecState{ /* 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; + vpx_codec_ctx_t v_encoder; + uint32_t frame_counter; /* video decoding */ - AVCodecContext *video_decoder_ctx; - AVCodec *video_decoder; + vpx_codec_ctx_t v_decoder; /* audio encoding */ OpusEncoder *audio_encoder; @@ -95,11 +56,6 @@ typedef struct _CodecState{ /* audio decoding */ OpusDecoder *audio_decoder; - - pthread_mutex_t ctrl_mutex; - - - uint32_t frame_rate; } CodecState; @@ -112,13 +68,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk); RTPMessage *dequeue(struct jitter_buffer *q, int *success); -CodecState* codec_init_session( uint32_t audio_bitrate, - uint16_t audio_frame_duration, - uint32_t audio_sample_rate, - uint32_t audio_channels, - uint32_t video_bitrate, - const char* webcam, - const char* webcam_driver ); +CodecState* codec_init_session ( uint32_t audio_bitrate, + uint16_t audio_frame_duration, + uint32_t audio_sample_rate, + uint32_t audio_channels, + uint16_t video_width, + uint16_t video_height, + uint32_t video_bitrate ); void codec_terminate_session(CodecState* cs); diff --git a/toxav/msi.c b/toxav/msi.c index 014a904f..f00029ba 100644 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -593,7 +593,7 @@ int send_message ( MSISession* session, MSIMessage* msg, uint32_t to ) uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; uint16_t _length = message_to_string ( msg, _msg_string_final ); - return m_msi_packet((struct Messenger*) session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; + return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; } @@ -616,7 +616,27 @@ void flush_peer_type ( MSISession* session, MSIMessage* msg, int peer_id ) { } else {} /* Error */ } - +void handle_remote_connection_change(Messenger* messenger, int friend_num, uint8_t status, void* session_p) +{ + MSISession* session = session_p; + + switch ( status ) + { + case 0: /* Went offline */ + { + if ( session->call ) { + int i = 0; + for ( ; i < session->call->peer_count; i ++ ) + if ( session->call->peers[i] == friend_num ) { + msi_stopcall(session); /* Stop the call for now */ + return; + } + } + } break; + + default: break; + } +} /** * @brief Sends error response to peer. @@ -694,8 +714,8 @@ void* handle_timeout ( void* arg ) } - ( *callbacks[MSI_OnTimeout] ) ( _session->agent_handler ); - ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler ); + ( *callbacks[MSI_OnRequestTimeout] ) ( _session->agent_handler ); + ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler ); return NULL; } @@ -774,7 +794,7 @@ int terminate_call ( MSISession* session ) { /* Check event loop and cancel timed events if there are any - * Notice: This has to be done before possibly + * NOTE: This has to be done before possibly * locking the mutex the second time */ event.timer_release ( session->call->request_timer_id ); @@ -797,7 +817,7 @@ int terminate_call ( MSISession* session ) { pthread_mutex_destroy ( &_call->mutex ); free ( _call ); - + return 0; } @@ -1136,7 +1156,7 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id ) * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) { +MSISession* msi_init_session ( Messenger* messenger, const uint8_t* ua_name ) { assert ( messenger ); MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); @@ -1152,8 +1172,10 @@ MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) { _retu->call_timeout = 30000; /* default value? */ - m_callback_msi_packet((struct Messenger*) messenger, msi_handle_packet, _retu ); + m_callback_msi_packet(messenger, msi_handle_packet, _retu ); + /* This is called when remote terminates session */ + m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); return _retu; } @@ -1351,7 +1373,7 @@ int msi_stopcall ( MSISession* session ) { return -1; /* just terminate it */ - + terminate_call ( session ); return 0; diff --git a/toxav/msi.h b/toxav/msi.h index 20d6671d..4487dae6 100644 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -26,9 +26,10 @@ #define __TOXMSI #include -#include "../toxcore/tox.h" #include +#include "../toxcore/Messenger.h" + /* define size for call_id */ #define CALL_ID_LEN 12 @@ -106,7 +107,7 @@ typedef struct _MSISession { const uint8_t* ua_name; void* agent_handler; /* Pointer to an object that is handling msi */ - Tox* messenger_handle; + Messenger* messenger_handle; uint32_t frequ; uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ @@ -133,7 +134,7 @@ typedef enum { /* Protocol */ MSI_OnError, - MSI_OnTimeout + MSI_OnRequestTimeout } MSICallbackID; @@ -156,7 +157,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id); * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ); +MSISession* msi_init_session ( Messenger* messenger, const uint8_t* ua_name ); /** diff --git a/toxav/phone.c b/toxav/phone.c index 4f078e2b..7806727d 100755 --- a/toxav/phone.c +++ b/toxav/phone.c @@ -44,18 +44,41 @@ #include #include #include -#include -#include -#include -#include #include -#include -#include "media.h" +//#include "media.h" #include "toxav.h" #include "../toxcore/event.h" #include "../toxcore/tox.h" +#ifdef TOX_FFMPEG +/* Video encoding/decoding */ +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +/* the quit event for SDL */ +#define FF_QUIT_EVENT (SDL_USEREVENT + 2) + +#ifdef __linux__ +#define VIDEO_DRIVER "video4linux2" +#define DEFAULT_WEBCAM "/dev/video0" +#endif + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +#define VIDEO_DRIVER "vfwcap" +#define DEFAULT_WEBCAM "0" +#endif + + /* Define client version */ #define _USERAGENT "v.0.3.0" @@ -96,6 +119,13 @@ typedef struct av_session_s { av_friend_t* _friends; int _friend_cout; char _my_public_id[200]; +#ifdef TOX_FFMPEG + AVInputFormat *video_input_format; + AVFormatContext *video_format_ctx; + uint8_t video_stream; + AVCodecContext *webcam_decoder_ctx; + AVCodec *webcam_decoder; +#endif } av_session_t; @@ -236,8 +266,8 @@ static void fraddr_to_str(uint8_t *id_bin, char *id_str) /* * How av stuff _should_ look like */ - -int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) +/* +int display_received_frame(av_session_t* _phone, vpx_image_t *image) { CodecState* cs = get_cs_temp(_phone->av); AVPicture pict; @@ -249,8 +279,8 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) 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 */ + */ + /* 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 ); @@ -263,60 +293,65 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); return 1; } - +*/ +#ifdef TOX_FFMPEG void *encode_video_thread(void *arg) { INFO("Started encode video thread!"); - + av_session_t* _phone = arg; _phone->running_encvid = 1; - - CodecState *cs = get_cs_temp(_phone->av); + //CodecState *cs = get_cs_temp(_phone->av); AVPacket pkt1, *packet = &pkt1; - int p = 0; - int got_packet; + //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; + //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); + numBytes = avpicture_get_size(PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->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, + avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, + _phone->webcam_decoder_ctx->height); + _phone->sws_ctx = sws_getContext(_phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, + _phone->webcam_decoder_ctx->pix_fmt, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL); + + vpx_image_t *image = + vpx_img_alloc(NULL, VPX_IMG_FMT_I420, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, 1); + + //uint32_t frame_counter = 0; while (_phone->running_encvid) { - if (av_read_frame(cs->video_format_ctx, packet) < 0) { + if (av_read_frame(_phone->video_format_ctx, packet) < 0) { printf("error reading frame\n"); - if (cs->video_format_ctx->pb->error != 0) + if (_phone->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) { + if (packet->stream_index == _phone->video_stream) { + if (avcodec_decode_video2(_phone->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); + _phone->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); /* create a new I-frame every 60 frames */ - ++p; - + //++p; + /* if (p == 60) { s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; @@ -325,53 +360,66 @@ void *encode_video_thread(void *arg) 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) { + memcpy(image->planes[VPX_PLANE_Y], s_video_frame->data[0], s_video_frame->linesize[0] * _phone->webcam_decoder_ctx->height); + memcpy(image->planes[VPX_PLANE_U], s_video_frame->data[1], s_video_frame->linesize[1] * _phone->webcam_decoder_ctx->height / 2); + memcpy(image->planes[VPX_PLANE_V], s_video_frame->data[2], s_video_frame->linesize[2] * _phone->webcam_decoder_ctx->height / 2); + toxav_send_video (_phone->av, image); + //if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { + /*if (vpx_codec_encode(&cs->v_encoder, image, frame_counter, 1, 0, 0) != VPX_CODEC_OK) { printf("could not encode video frame\n"); continue; } + ++frame_counter; - if (!got_packet) { - continue; - } + vpx_codec_iter_t iter = NULL; + vpx_codec_cx_pkt_t *pkt; + while( (pkt = vpx_codec_get_cx_data(&cs->v_encoder, &iter)) ) { + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) + toxav_send_rtp_payload(_phone->av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz); + }*/ + //if (!got_packet) { + // continue; + //} - if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); + //if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); - toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); + //toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); - av_free_packet(&enc_video_packet); + //av_free_packet(&enc_video_packet); } } else { av_free_packet(packet); } } + vpx_img_free(image); + /* clean up codecs */ - pthread_mutex_lock(&cs->ctrl_mutex); + //pthread_mutex_lock(&cs->ctrl_mutex); 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->ctrl_mutex); + //avcodec_close(webcam_decoder_ctx); + //avcodec_close(cs->video_encoder_ctx); + //pthread_mutex_unlock(&cs->ctrl_mutex); _phone->running_encvid = -1; pthread_exit ( NULL ); } +#endif void *encode_audio_thread(void *arg) { INFO("Started encode audio thread!"); av_session_t* _phone = arg; _phone->running_encaud = 1; - - unsigned char encoded_data[4096]; - int encoded_size = 0; + + int ret = 0; int16_t frame[4096]; int frame_size = AUDIO_FRAME_SIZE; ALint sample = 0; @@ -383,94 +431,164 @@ void *encode_audio_thread(void *arg) if (sample >= frame_size) { alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size); - encoded_size = toxav_encode_audio(_phone->av, frame, frame_size, encoded_data); + ret = toxav_send_audio(_phone->av, frame, frame_size); - if (encoded_size <= 0) { - printf("Could not encode audio packet\n"); - } else { - if ( -1 == toxav_send_rtp_payload(_phone->av, TypeAudio, encoded_data, encoded_size) ) - assert(0); - } + if (ret < 0) + printf("Could not encode or send audio packet\n"); + } else { usleep(1000); } } /* clean up codecs * - pthread_mutex_lock(&cs->ctrl_mutex);*/ + pthread_mutex_lock(&cs->ctrl_mutex);* / alcCaptureStop((ALCdevice*)_phone->audio_capture_device); alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); - /*pthread_mutex_unlock(&cs->ctrl_mutex);*/ + / *pthread_mutex_unlock(&cs->ctrl_mutex);*/ _phone->running_encaud = -1; pthread_exit ( NULL ); } +void convert_to_rgb(vpx_image_t *img, unsigned char *out) +{ + const int w = img->d_w; + const int w2 = w/2; + const int pstride = w*3; + const int h = img->d_h; + const int h2 = h/2; + + const int strideY = img->stride[0]; + const int strideU = img->stride[1]; + const int strideV = img->stride[2]; + int posy, posx; + for (posy = 0; posy < h2; posy++) { + unsigned char *dst = out + pstride * (posy * 2); + unsigned char *dst2 = out + pstride * (posy * 2 + 1); + const unsigned char *srcY = img->planes[0] + strideY * posy * 2; + const unsigned char *srcY2 = img->planes[0] + strideY * (posy * 2 + 1); + const unsigned char *srcU = img->planes[1] + strideU * posy; + const unsigned char *srcV = img->planes[2] + strideV * posy; + + for (posx = 0; posx < w2; posx++) { + unsigned char Y,U,V; + short R,G,B; + short iR,iG,iB; + + U = *(srcU++); V = *(srcV++); + iR = (351 * (V-128)) / 256; + iG = - (179 * (V-128)) / 256 - (86 * (U-128)) / 256; + iB = (444 * (U-128)) / 256; + + Y = *(srcY++); + R = Y + iR ; G = Y + iG ; B = Y + iB ; + R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); + *(dst++) = R; *(dst++) = G; *(dst++) = B; + + Y = *(srcY2++); + R = Y + iR ; G = Y + iG ; B = Y + iB ; + R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); + *(dst2++) = R; *(dst2++) = G; *(dst2++) = B; + + Y = *(srcY++) ; + R = Y + iR ; G = Y + iG ; B = Y + iB ; + R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); + *(dst++) = R; *(dst++) = G; *(dst++) = B; + + Y = *(srcY2++); + R = Y + iR ; G = Y + iG ; B = Y + iB ; + R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); + *(dst2++) = R; *(dst2++) = G; *(dst2++) = B; + } + } +} + +#define mask32(BYTE) (*(uint32_t *)(uint8_t [4]){ [BYTE] = 0xff }) + void *decode_video_thread(void *arg) { INFO("Started decode video thread!"); av_session_t* _phone = arg; _phone->running_decvid = 1; - CodecState *cs = get_cs_temp(_phone->av); - cs->video_stream = 0; + //CodecState *cs = get_cs_temp(_phone->av); + //cs->video_stream = 0; - int recved_size; - uint8_t dest[RTP_PAYLOAD_SIZE]; + //int recved_size; + //uint8_t dest[RTP_PAYLOAD_SIZE]; - 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 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 (_phone->running_decvid) { - - recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, 1, dest); - - if (recved_size) { - memcpy(dec_video_packet.data, dest, recved_size); - dec_video_packet.size = recved_size; + //recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, dest); + //if (recved_size) { + vpx_image_t *image; + if (toxav_recv_video(_phone->av, &image) == 0) { + //memcpy(dec_video_packet.data, dest, recved_size); + //dec_video_packet.size = recved_size; - avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); + //avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); - if (dec_frame_finished) { + //if (dec_frame_finished) { /* Check if size has changed */ - if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { + if (image->d_w != width || image->d_h != height) { - width = cs->video_decoder_ctx->width; - height = cs->video_decoder_ctx->height; + width = image->d_w; + height = image->d_h; printf("w: %d h: %d \n", width, height); screen = SDL_SetVideoMode(width, height, 0, 0); - if (_phone->video_picture.bmp) - SDL_FreeYUVOverlay(_phone->video_picture.bmp); + //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, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, - SWS_BILINEAR, NULL, NULL, NULL); + //_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); + // _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, + // SWS_BILINEAR, NULL, NULL, NULL); } + uint8_t *rgb_image = malloc(width*height*3); + convert_to_rgb(image, rgb_image); + SDL_Surface* img_surface = SDL_CreateRGBSurfaceFrom(rgb_image, width, height, 24, width * 3, mask32(0), mask32(1), mask32(2), 0); + if(SDL_BlitSurface(img_surface, NULL, screen, NULL) == 0) + SDL_UpdateRect(screen, 0, 0, 0, 0); + /* + SDL_LockYUVOverlay(_phone->video_picture.bmp); + memcpy(_phone->video_picture.bmp->pixels[0], image->planes[VPX_PLANE_Y], _phone->video_picture.bmp->pitches[0] * height); + memcpy(_phone->video_picture.bmp->pixels[1], image->planes[VPX_PLANE_V], _phone->video_picture.bmp->pitches[1] * height / 2); + memcpy(_phone->video_picture.bmp->pixels[2], image->planes[VPX_PLANE_U], _phone->video_picture.bmp->pitches[2] * height / 2); - display_received_frame(_phone, r_video_frame); - } else { + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = width; + rect.h = height; + SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);*/ + free(rgb_image); + //display_received_frame(_phone, image); + + } //else { /* TODO: request the sender to create a new i-frame immediatly */ - printf("Bad video packet\n"); - } - } + //printf("Bad video packet\n"); + //} + //} usleep(1000); } /* clean up codecs */ - av_free(r_video_frame); + //av_free(r_video_frame); - pthread_mutex_lock(&cs->ctrl_mutex); - avcodec_close(cs->video_decoder_ctx); - pthread_mutex_unlock(&cs->ctrl_mutex); + //pthread_mutex_lock(&cs->ctrl_mutex); + //avcodec_close(cs->video_decoder_ctx); + //pthread_mutex_unlock(&cs->ctrl_mutex); _phone->running_decvid = -1; @@ -483,11 +601,11 @@ void *decode_audio_thread(void *arg) av_session_t* _phone = arg; _phone->running_decaud = 1; - int recved_size; - uint8_t dest [RTP_PAYLOAD_SIZE]; + //int recved_size; + //uint8_t dest [RTP_PAYLOAD_SIZE]; int frame_size = AUDIO_FRAME_SIZE; - int data_size; + //int data_size; ALCdevice *dev; ALCcontext *ctx; @@ -507,7 +625,7 @@ void *decode_audio_thread(void *arg) uint16_t zeros[frame_size]; memset(zeros, 0, frame_size); - opus_int16 PCM[frame_size]; + int16_t PCM[frame_size]; int i; for (i = 0; i < openal_buffers; ++i) { @@ -527,28 +645,15 @@ void *decode_audio_thread(void *arg) while (_phone->running_decaud) { alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); - - recved_size = toxav_recv_rtp_payload(_phone->av, TypeAudio, ready, dest); - - if ( recved_size == ErrorAudioPacketLost ) { - printf("Lost packet\n"); - dec_frame_len = toxav_decode_audio(_phone->av, NULL, 0, frame_size, PCM); - - } else if ( recved_size ) { - dec_frame_len = toxav_decode_audio(_phone->av, dest, recved_size, frame_size, PCM); - } - - + if (ready <= 0) + continue; + + dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM); + /* Play the packet */ - if (dec_frame_len) { - alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); - - if (ready <= 0) - continue; - + if (dec_frame_len > 0) { 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); + alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000); int error = alGetError(); if (error != AL_NO_ERROR) { @@ -573,16 +678,16 @@ void *decode_audio_thread(void *arg) ending: - /* clean up codecs * / - pthread_mutex_lock(&cs->ctrl_mutex); - + /* clean up codecs */ + //pthread_mutex_lock(&cs->ctrl_mutex); + /* alDeleteSources(1, &source); alDeleteBuffers(openal_buffers, buffers); alcMakeContextCurrent(NULL); alcDestroyContext(ctx); alcCloseDevice(dev); - - pthread_mutex_unlock(&cs->ctrl_mutex); */ + */ + //pthread_mutex_unlock(&cs->ctrl_mutex); _phone->running_decaud = -1; @@ -604,7 +709,7 @@ int phone_startmedia_loop ( ToxAv* arg ) /* * Rise all threads */ - +#ifdef TOX_FFMPEG /* Only checks for last peer */ if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo && 0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) ) @@ -612,7 +717,7 @@ int phone_startmedia_loop ( ToxAv* arg ) INFO("Error while starting encode_video_thread()"); return -1; } - +#endif /* Always send audio */ if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) { @@ -779,7 +884,6 @@ av_session_t* av_init_session() } _retu->_friends = NULL; - _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT); const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); @@ -821,13 +925,58 @@ av_session_t* av_init_session() printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); return 0; } - - + uint16_t height = 0, width = 0; +#ifdef TOX_FFMPEG + avdevice_register_all(); + avcodec_register_all(); + av_register_all(); + + _retu->video_input_format = av_find_input_format(VIDEO_DRIVER); + 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; + } + + avformat_find_stream_info(_retu->video_format_ctx, NULL); + av_dump_format(_retu->video_format_ctx, 0, DEFAULT_WEBCAM, 0); + + for (i = 0; i < _retu->video_format_ctx->nb_streams; ++i) { + if (_retu->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + _retu->video_stream = i; + break; + } + } + + _retu->webcam_decoder_ctx = _retu->video_format_ctx->streams[_retu->video_stream]->codec; + _retu->webcam_decoder = avcodec_find_decoder(_retu->webcam_decoder_ctx->codec_id); + + if (_retu->webcam_decoder == NULL) { + fprintf(stderr, "Unsupported codec!\n"); + //return -1; + return NULL; + } + + if (_retu->webcam_decoder_ctx == NULL) { + fprintf(stderr, "Init webcam_decoder_ctx failed!\n"); + //return -1; + return NULL; + } + + if (avcodec_open2(_retu->webcam_decoder_ctx, _retu->webcam_decoder, NULL) < 0) { + fprintf(stderr, "Opening webcam decoder failed!\n"); + //return -1; + return NULL; + } + width = _retu->webcam_decoder_ctx->width; + height = _retu->webcam_decoder_ctx->height; +#endif uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; tox_get_address(_retu->_messenger, _byte_address ); fraddr_to_str( _byte_address, _retu->_my_public_id ); - + + _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT, width, height); /* ------------------ */ @@ -842,7 +991,7 @@ av_session_t* av_init_session() toxav_register_callstate_callback(callback_recv_ending, OnEnding); toxav_register_callstate_callback(callback_recv_error, OnError); - toxav_register_callstate_callback(callback_requ_timeout, OnTimeout); + toxav_register_callstate_callback(callback_requ_timeout, OnRequestTimeout); /* ------------------ */ @@ -1013,9 +1162,9 @@ void do_phone ( av_session_t* _phone ) { ToxAvError rc; - if ( _len > 1 && _line[2] == 'v' ) + if ( _len > 1 && _line[2] == 'v' ) { rc = toxav_answer(_phone->av, TypeVideo); - else + } else rc = toxav_answer(_phone->av, TypeAudio); if ( rc == ErrorInvalidState ) { diff --git a/toxav/rtp.c b/toxav/rtp.c index e23fa132..80fcc630 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -30,10 +30,6 @@ #include #include -#include "../toxcore/util.h" -#include "../toxcore/network.h" -#include "../toxcore/net_crypto.h" -#include "../toxcore/Messenger.h" #define PAYLOAD_ID_VALUE_OPUS 1 #define PAYLOAD_ID_VALUE_VP8 2 @@ -241,8 +237,8 @@ RTPHeader* extract_header ( const uint8_t* payload, int length ) _retu->flags = *_it; ++_it; - /* This indicates if the first 2 bytes are valid. - * Now it my happen that this is out of order but + /* This indicates if the first 2 bits are valid. + * Now it may happen that this is out of order but * it cuts down chances of parsing some invalid value */ @@ -299,7 +295,7 @@ RTPHeader* extract_header ( const uint8_t* payload, int length ) * @return RTPExtHeader* Extracted extension header. * @retval NULL Error occurred while extracting extension header. */ -RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length ) +RTPExtHeader* extract_ext_header ( const uint8_t* payload, uint16_t length ) { const uint8_t* _it = payload; @@ -551,7 +547,7 @@ int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t l /* Hopefully this goes well * NOTE: Is this even used? */ - memcpy(&_msg->from, &ip_port, sizeof(tox_IP_Port)); + memcpy(&_msg->from, &ip_port, sizeof(IP_Port)); /* Check if message came in late */ if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ @@ -689,7 +685,7 @@ int rtp_release_session_recv ( RTPSession* session ) /** - * @brief Get's oldes message in the list. + * @brief Gets oldest message in the list. * * @param session Where the list is. * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. @@ -727,7 +723,7 @@ RTPMessage* rtp_recv_msg ( RTPSession* session ) * @retval -1 On error. * @retval 0 On success. */ -int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ) +int rtp_send_msg ( RTPSession* session, Messenger* messenger, const uint8_t* data, uint16_t length ) { RTPMessage* msg = rtp_new_message (session, data, length); @@ -743,8 +739,8 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin increase_nonce ( _calculated, msg->header->sequnum ); /* Need to skip 2 bytes that are for sequnum */ - int encrypted_length = encrypt_data_symmetric( - (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length - 2, _send_data + 3 ); + int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/ + (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 ); int full_length = encrypted_length + 3; @@ -752,7 +748,8 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin _send_data[2] = msg->data[1]; - if ( full_length != sendpacket ( ((Messenger*)messenger)->net, *((IP_Port*) &session->dest), _send_data, full_length) ) { + /*if ( full_length != sendpacket ( messenger->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {*/ + if ( full_length != send_custom_user_packet(messenger, session->dest, _send_data, full_length) ) { printf("Rtp error: %s\n", strerror(errno)); return -1; } @@ -816,30 +813,26 @@ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ) * @retval NULL Error occurred. */ RTPSession* rtp_init_session ( int payload_type, - Tox* messenger, + Messenger* messenger, int friend_num, const uint8_t* encrypt_key, const uint8_t* decrypt_key, const uint8_t* encrypt_nonce, - const uint8_t* decrypt_nonce -) + const uint8_t* decrypt_nonce ) { - Messenger* _messenger_casted = (Messenger*) messenger; - - IP_Port _dest = get_friend_ipport(_messenger_casted, friend_num ); - - /* This should be enough eh? */ - if ( _dest.port == 0) { - return NULL; - } - RTPSession* _retu = calloc(1, sizeof(RTPSession)); assert(_retu); - networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu); + /*networking_registerhandler(messenger->net, payload_type, rtp_handle_packet, _retu);*/ + if ( -1 == custom_user_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ) + { + fprintf(stderr, "Error setting custom register handler for rtp session\n"); + free(_retu); + return NULL; + } - _retu->version = RTP_VERSION; /* It's always 2 */ - _retu->padding = 0; /* If some additional data is needed about the packet */ + _retu->version = RTP_VERSION; /* It's always 2 */ + _retu->padding = 0; /* If some additional data is needed about the packet */ _retu->extension = 0; /* If extension to header is needed */ _retu->cc = 1; /* Amount of contributors */ _retu->csrc = NULL; /* Container */ @@ -847,7 +840,7 @@ RTPSession* rtp_init_session ( int payload_type, _retu->marker = 0; _retu->payload_type = payload_table[payload_type]; - _retu->dest = *((tox_IP_Port*)&_dest); + _retu->dest = friend_num; _retu->rsequnum = _retu->sequnum = 1; @@ -894,12 +887,12 @@ RTPSession* rtp_init_session ( int payload_type, * @retval -1 Error occurred. * @retval 0 Success. */ -int rtp_terminate_session ( RTPSession* session, Tox* messenger ) +int rtp_terminate_session ( RTPSession* session, Messenger* messenger ) { if ( !session ) return -1; - networking_registerhandler(((Messenger*)messenger)->net, session->prefix, NULL, NULL); + custom_user_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); free ( session->ext_header ); free ( session->csrc ); diff --git a/toxav/rtp.h b/toxav/rtp.h index 4b0d681f..03f6a873 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h @@ -28,10 +28,14 @@ #define RTP_VERSION 2 #include #include -#include "../toxcore/tox.h" + +#include "../toxcore/util.h" +#include "../toxcore/network.h" +#include "../toxcore/net_crypto.h" +#include "../toxcore/Messenger.h" #define MAX_SEQU_NUM 65535 -#define MAX_RTP_SIZE 10400 +#define MAX_RTP_SIZE 65535 /** * @brief Standard rtp header @@ -72,7 +76,7 @@ typedef struct _RTPMessage { uint8_t data[MAX_RTP_SIZE]; uint32_t length; - tox_IP_Port from; + IP_Port from; struct _RTPMessage* next; } RTPMessage; @@ -128,7 +132,7 @@ typedef struct _RTPSession { uint8_t prefix; pthread_mutex_t mutex; - tox_IP_Port dest; + int dest; } RTPSession; @@ -164,7 +168,7 @@ RTPMessage* rtp_recv_msg ( RTPSession* session ); * @retval -1 On error. * @retval 0 On success. */ -int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ); +int rtp_send_msg ( RTPSession* session, Messenger* messenger, const uint8_t* data, uint16_t length ); /** @@ -192,7 +196,7 @@ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ); * @retval NULL Error occurred. */ RTPSession* rtp_init_session ( int payload_type, - Tox* messenger, + Messenger* messenger, int friend_num, const uint8_t* encrypt_key, const uint8_t* decrypt_key, @@ -209,7 +213,7 @@ RTPSession* rtp_init_session ( int payload_type, * @retval -1 Error occurred. * @retval 0 Success. */ -int rtp_terminate_session ( RTPSession* session, Tox* messenger ); +int rtp_terminate_session ( RTPSession* session, Messenger* messenger ); diff --git a/toxav/toxav.c b/toxav/toxav.c index 8757d7fd..5683795e 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -26,16 +26,16 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ -#include "toxav.h" -#include "../toxcore/tox.h" +#include "media.h" #include "rtp.h" #include "msi.h" -#include "media.h" #include #include #include +#include "toxav.h" + #define inline__ inline __attribute__((always_inline)) static const uint8_t audio_index = 0, video_index = 1; @@ -50,7 +50,7 @@ typedef enum { typedef struct _ToxAv { - Tox* messenger; + Messenger* messenger; MSISession* msi_session; /** Main msi session */ @@ -89,21 +89,23 @@ typedef struct _ToxAv -ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name ) -{ +ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name , uint16_t video_width, uint16_t video_height) +{ ToxAv* av = calloc ( sizeof(ToxAv), 1); - - av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name ); + if (av == NULL) + return NULL; + + av->messenger = (Messenger *)messenger; + + av->msi_session = msi_init_session(av->messenger, (const unsigned char*) ua_name ); av->msi_session->agent_handler = av; av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; - - av->messenger = messenger; - + /* NOTE: This should be user defined or? */ av->j_buf = create_queue(20); - av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER); + av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, AUDIO_CHANNELS, video_width, video_height, VIDEO_BITRATE); av->agent_handler = useragent; @@ -273,7 +275,7 @@ inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8 else return -1; } -inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest ) +inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, uint8_t* dest ) { if ( !dest ) return ErrorInternal; @@ -283,20 +285,19 @@ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, if ( type == TypeAudio ) { - message = rtp_recv_msg(av->rtp_sessions[audio_index]); + do { + message = rtp_recv_msg(av->rtp_sessions[audio_index]); + + if (message) { + /* push the packet into the queue */ + queue(av->j_buf, message); + } + } while(message); - if (message) { - /* push the packet into the queue */ - queue(av->j_buf, message); - } - - if (ready) { - int success = 0; - message = dequeue(av->j_buf, &success); - - if ( success == 2) return ErrorAudioPacketLost; - } - else return 0; + int success = 0; + message = dequeue(av->j_buf, &success); + + if ( success == 2) return ErrorAudioPacketLost; } else { message = rtp_recv_msg(av->rtp_sessions[video_index]); @@ -315,19 +316,75 @@ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, return 0; } -inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ) +inline__ int toxav_recv_video ( ToxAv* av, vpx_image_t **output) { - if ( !dest ) return ErrorInternal; + if ( !output ) return ErrorInternal; + uint8_t packet [RTP_PAYLOAD_SIZE]; + int recved_size = 0; + 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))); + } + }while (recved_size > 0); + vpx_codec_iter_t iter = NULL; + vpx_image_t *img; + img = vpx_codec_get_frame(&av->cs->v_decoder, &iter); + if (img == NULL) + return ErrorInternal; - return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1); + *output = img; + return 0; } -inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ) +inline__ int toxav_send_video ( ToxAv* av, vpx_image_t *input) { - if ( !dest ) + 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"); return ErrorInternal; + } + ++av->cs->frame_counter; + + vpx_codec_iter_t iter = NULL; + const vpx_codec_cx_pkt_t *pkt; + int sent = 0; + while( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { + if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) + ++sent; + } + } + if (sent > 0) + return 0; - return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE); + return ErrorInternal; +} + +inline__ int toxav_recv_audio ( ToxAv* av, int frame_size, int16_t* dest ) +{ + if ( !dest ) return ErrorInternal; + uint8_t packet [RTP_PAYLOAD_SIZE]; + + 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); + } else { + return ErrorInternal; + } +} + +inline__ int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size) +{ + uint8_t temp_data[RTP_PAYLOAD_SIZE]; + int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data)); + if (ret <= 0) + return ErrorInternal; + + return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); } int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) @@ -343,10 +400,3 @@ void* toxav_get_agent_handler ( ToxAv* av ) { return av->agent_handler; } - - -/* Only temporary */ -void* get_cs_temp(ToxAv* av) -{ - return av->cs; -} diff --git a/toxav/toxav.h b/toxav/toxav.h index 96a666a2..63dbf162 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -27,6 +27,9 @@ #define __TOXAV #include +/* vpx_image_t */ +#include + typedef void* ( *ToxAVCallback ) ( void* arg ); typedef struct _ToxAv ToxAv; @@ -35,7 +38,29 @@ typedef struct _ToxAv ToxAv; typedef struct Tox Tox; #endif -#define RTP_PAYLOAD_SIZE 10400 +#define RTP_PAYLOAD_SIZE 65535 + +/* Default video bitrate in bytes/s */ +#define VIDEO_BITRATE 10*1000*100 + +/* Default audio bitrate in bits/s */ +#define AUDIO_BITRATE 64000 + +/* Number of audio channels. */ +#define AUDIO_CHANNELS 1 + +/* Audio frame duration in miliseconds */ +#define AUDIO_FRAME_DURATION 20 + +/* Audio sample rate recommended to be 48kHz for Opus */ +#define AUDIO_SAMPLE_RATE 48000 + +/* The amount of samples in one audio frame */ +#define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000 + +/* Assume 60 fps*/ +#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) + /** * @brief Callbacks ids that handle the call states @@ -55,7 +80,7 @@ typedef enum { /* Protocol */ OnError, - OnTimeout + OnRequestTimeout } ToxAvCallbackID; @@ -86,7 +111,7 @@ typedef enum { } ToxAvError; -ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name); +ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name, uint16_t video_width, uint16_t video_height) ; void toxav_kill(ToxAv* av); void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); @@ -103,27 +128,25 @@ int toxav_prepare_transmission(ToxAv* av); int toxav_kill_transmission(ToxAv* av); -int toxav_send_rtp_payload(ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length); + /* Return length of received packet. Returns 0 if nothing recved. Dest has to have * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque. * For video packets set 'ready' at _any_ value. */ -int toxav_recv_rtp_payload(ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest); - - +/* returns 0 on success */ +int toxav_recv_video ( ToxAv* av, vpx_image_t **output); -int toxav_decode_audio( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ); +int toxav_recv_audio( ToxAv* av, int frame_size, int16_t* dest ); -/* Please make sure 'dest' has enough storage for RTP_PAYLOAD_SIZE length of data */ -int toxav_encode_audio( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ); +int toxav_send_video ( ToxAv* av, vpx_image_t *input); +/* Encode and send audio frame. */ +int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size); int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); void* toxav_get_agent_handler ( ToxAv* av ); -/* Use this to get handle of CodecState from ToxAv struct */ -void* get_cs_temp( ToxAv* av ); #endif /* __TOXAV */ \ No newline at end of file diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 02175c2a..982b06c4 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -379,6 +379,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, uint8_t want_good) { + memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format)); #ifdef ENABLE_ASSOC_DHT if (!dht->assoc) @@ -1249,9 +1250,9 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id) --dht->num_friends; if (dht->num_friends != i) { - memcpy( dht->friends_list[i].client_id, - dht->friends_list[dht->num_friends].client_id, - CLIENT_ID_SIZE ); + memcpy( &dht->friends_list[i], + &dht->friends_list[dht->num_friends], + sizeof(DHT_Friend) ); } if (dht->num_friends == 0) { @@ -1553,7 +1554,7 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt IP_Port ip_list[MAX_FRIEND_CLIENTS]; int ip_num = friend_iplist(dht, ip_list, num); - if (ip_num < (MAX_FRIEND_CLIENTS / 2)) + if (ip_num < (MAX_FRIEND_CLIENTS / 4)) return 0; /* Reason for that? */ DHT_Friend *friend = &dht->friends_list[num]; @@ -2394,7 +2395,6 @@ static int dht_load_state_callback(void *outer, uint8_t *data, uint32_t length, num = length / sizeof(DHT_Friend); for (i = 0; i < num; ++i) { - DHT_addfriend(dht, friend_list[i].client_id); for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { Client_data *client = &friend_list[i].client_list[j]; diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index c1301767..692d3d0e 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -43,6 +43,71 @@ static uint8_t friend_not_valid(Messenger *m, int friendnumber) return (unsigned int)friendnumber >= m->numfriends; } +static int add_online_friend(Messenger *m, int friendnumber) +{ + if (friend_not_valid(m, friendnumber)) + return -1; + + IP_Port temp_ip_port = get_friend_ipport(m, friendnumber); + + if (temp_ip_port.port == 0) + return -1; + + uint32_t i; + + for (i = 0; i < m->numonline_friends; ++i) { + if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) + return 0; + } + + Online_Friend *temp; + temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends + 1)); + + if (temp == NULL) + return -1; + + m->online_friendlist = temp; + m->online_friendlist[m->numonline_friends].friend_num = friendnumber; + m->online_friendlist[m->numonline_friends].ip_port = temp_ip_port; + ++m->numonline_friends; + return 0; +} + + +static int remove_online_friend(Messenger *m, int friendnumber) +{ + uint32_t i; + Online_Friend *temp; + + for (i = 0; i < m->numonline_friends; ++i) { + /* Equal */ + if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) { + --m->numonline_friends; + + if (m->numonline_friends != i) { + memcpy( &m->online_friendlist[i], + &m->online_friendlist[m->numonline_friends], + sizeof(Online_Friend) ); + } + + if (m->numonline_friends == 0) { + free(m->online_friendlist); + m->online_friendlist = NULL; + return 0; + } + + temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends)); + + if (temp == NULL) + return -1; + + m->online_friendlist = temp; + return 0; + } + } + + return -1; +} /* Set the size of the friend list to numfriends. * * return -1 if realloc fails. @@ -273,6 +338,9 @@ int m_delfriend(Messenger *m, int friendnumber) if (friend_not_valid(m, friendnumber)) return -1; + if (m->friendlist[friendnumber].status == FRIEND_ONLINE) + remove_online_friend(m, friendnumber); + onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); free(m->friendlist[friendnumber].statusmessage); @@ -650,12 +718,17 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in m->friend_connectionstatuschange = function; m->friend_connectionstatuschange_userdata = userdata; } + +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), + void *userdata) +{ + m->friend_connectionstatuschange_internal = function; + m->friend_connectionstatuschange_internal_userdata = userdata; +} + static void break_files(Messenger *m, int friendnumber); static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) { - if (!m->friend_connectionstatuschange) - return; - if (status == NOFRIEND) return; @@ -665,10 +738,19 @@ static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_ onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); if (is_online != was_online) { - if (was_online) + if (was_online) { break_files(m, friendnumber); + remove_online_friend(m, friendnumber); + } else { + add_online_friend(m, friendnumber); + } + + if (m->friend_connectionstatuschange) + m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); - m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); + if (m->friend_connectionstatuschange_internal) + m->friend_connectionstatuschange_internal(m, friendnumber, is_online, + m->friend_connectionstatuschange_internal_userdata); } } @@ -814,6 +896,8 @@ static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *m if (i == -1) return; + message[length - 1] = 0; /* Force NULL terminator */ + if (m->group_message) (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); } @@ -826,6 +910,8 @@ static void group_action_function(Group_Chat *chat, int peer_number, uint8_t *ac if (i == -1) return; + action[length - 1] = 0; /* Force NULL terminator */ + if (m->group_action) (*m->group_action)(m, i, peer_number, action, length, m->group_action_userdata); } @@ -1489,6 +1575,60 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); } +static int friendnum_from_ip_port(Messenger *m, IP_Port ip_port) +{ + uint32_t i; + + for (i = 0; i < m->numonline_friends; ++i) { + if (ipport_equal(&m->online_friendlist[i].ip_port, &ip_port)) + return m->online_friendlist[i].friend_num; + } + + return -1; +} + +static int handle_custom_user_packet(void *object, IP_Port source, uint8_t *packet, uint32_t length) +{ + Messenger *m = object; + int friend_num = friendnum_from_ip_port(m, source); + + if (friend_num == -1) + return 1; + + if (m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function) + return m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function( + m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].object, source, packet, length); + + return 1; +} + + +int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, + void *object) +{ + if (friend_not_valid(m, friendnumber)) + return -1; + + if (byte < NET_PACKET_CUSTOM_RANGE_START || byte >= NET_PACKET_CUSTOM_RANGE_END) + return -1; + + m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].function = cb; + m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].object = object; + networking_registerhandler(m->net, byte, handle_custom_user_packet, m); + return 0; +} + +int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length) +{ + IP_Port ip_port = get_friend_ipport(m, friendnumber); + + if (ip_port.port == 0) + return -1; + + return sendpacket(m->net, ip_port, data, length); +} + + /* Function to filter out some friend requests*/ static int friend_already_added(uint8_t *client_id, void *data) { @@ -1841,6 +1981,8 @@ void do_friends(Messenger *m) m->friendlist[i].file_receiving[filenumber].size = filesize; m->friendlist[i].file_receiving[filenumber].transferred = 0; + data[data_length - 1] = 0; /* Force NULL terminate file name. */ + if (m->file_sendrequest) (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), m->file_sendrequest_userdata); @@ -2360,6 +2502,12 @@ uint32_t count_friendlist(Messenger *m) return ret; } +/* Return the number of online friends in the instance m. */ +uint32_t get_num_online_friends(Messenger *m) +{ + return m->numonline_friends; +} + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * Otherwise, returns the number of elements copied. diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index e09b2f30..ccca8fba 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -155,8 +155,15 @@ typedef struct { struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; int invited_groups[MAX_INVITED_GROUPS]; uint16_t invited_groups_num; + + Packet_Handles packethandlers[TOTAL_USERPACKETS]; } Friend; +typedef struct { + uint32_t friend_num; + IP_Port ip_port; +} Online_Friend; + typedef struct Messenger { Networking_Core *net; @@ -179,6 +186,9 @@ typedef struct Messenger { Friend *friendlist; uint32_t numfriends; + Online_Friend *online_friendlist; + uint32_t numonline_friends; + Group_Chat **chats; uint32_t numchats; @@ -200,6 +210,8 @@ typedef struct Messenger { void *friend_statuschange_userdata; void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); void *friend_connectionstatuschange_userdata; + void (*friend_connectionstatuschange_internal)(struct Messenger *m, int, uint8_t, void *); + void *friend_connectionstatuschange_internal_userdata; void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); void *group_invite_userdata; @@ -450,6 +462,9 @@ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, u * It's assumed that when adding friends, their connection status is offline. */ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); +/* Same as previous but for internal A/V core usage only */ +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), + void *userdata); /**********GROUP CHATS************/ @@ -627,6 +642,22 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) /**********************************************/ +/* Set handlers for custom user packets (RTP packets for example.) + * + * return -1 on failure. + * return 0 on success. + */ +int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, + void *object); + +/* High level function to send custom user packets. + * + * return -1 on failure. + * return number of bytes sent on success. + */ +int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length); + +/**********************************************/ /* Run this at startup. * return allocated instance of Messenger on success. * return 0 if there are problems. @@ -682,6 +713,9 @@ int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8 * for copy_friendlist. */ uint32_t count_friendlist(Messenger *m); +/* Return the number of online friends in the instance m. */ +uint32_t get_num_online_friends(Messenger *m); + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * Otherwise, returns the number of elements copied. diff --git a/toxcore/event.c b/toxcore/event.c index 05e2a03c..2fdc9442 100755 --- a/toxcore/event.c +++ b/toxcore/event.c @@ -31,6 +31,7 @@ #include "event.h" #include "util.h" +#include "network.h" #define _GNU_SOURCE diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c index 5c294c76..9ac72097 100644 --- a/toxcore/friend_requests.c +++ b/toxcore/friend_requests.c @@ -140,6 +140,9 @@ static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t return 1; addto_receivedlist(fr, source_pubkey); + + packet[length - 1] = 0; /* Force NULL terminator. */ + (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); return 0; } diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index 90ffdd14..6dff52ef 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c @@ -75,6 +75,32 @@ static int peer_in_chat(Group_Chat *chat, uint8_t *client_id) return -1; } +/* Compares client_id1 and client_id2 with client_id. + * + * return 0 if both are same distance. + * return 1 if client_id1 is closer. + * return 2 if client_id2 is closer. + */ +static int id_closest_groupchats(uint8_t *id, uint8_t *id1, uint8_t *id2) +{ + size_t i; + uint8_t distance1, distance2; + + for (i = 0; i < CLIENT_ID_SIZE; ++i) { + + distance1 = abs(((int8_t *)id)[i] - ((int8_t *)id1)[i]); + distance2 = abs(((int8_t *)id)[i] - ((int8_t *)id2)[i]); + + if (distance1 < distance2) + return 1; + + if (distance1 > distance2) + return 2; + } + + return 0; +} + #define BAD_GROUPNODE_TIMEOUT 30 /* @@ -100,7 +126,7 @@ static int peer_okping(Group_Chat *chat, uint8_t *client_id) if (id_equal(chat->close[i].client_id, client_id)) return -1; - if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) + if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) ++j; } @@ -137,7 +163,7 @@ static int add_closepeer(Group_Chat *chat, uint8_t *client_id, IP_Port ip_port) } for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ - if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { + if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { id_copy(chat->close[i].client_id, client_id); chat->close[i].ip_port = ip_port; chat->close[i].last_recv = unix_time(); diff --git a/toxcore/network.c b/toxcore/network.c index 1186a468..839618bf 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -540,8 +540,10 @@ Networking_Core *new_networking(IP ip, uint16_t port) addr6->sin6_scope_id = 0; portptr = &addr6->sin6_port; - } else + } else { + free(temp); return NULL; + } if (ip.family == AF_INET6) { char ipv6only = 0; diff --git a/toxcore/network.h b/toxcore/network.h index 4c7f1a83..aaf89f19 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -129,6 +129,12 @@ typedef int sock_t; #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ +/* Range of ids that custom user packets can use. */ +#define NET_PACKET_CUSTOM_RANGE_START 64 +#define NET_PACKET_CUSTOM_RANGE_END 96 + +#define TOTAL_USERPACKETS (NET_PACKET_CUSTOM_RANGE_END - NET_PACKET_CUSTOM_RANGE_START) + /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ #define NET_PACKET_ONION_SEND_INITIAL 128 #define NET_PACKET_ONION_SEND_1 129 @@ -143,6 +149,9 @@ typedef int sock_t; #define NET_PACKET_ONION_RECV_2 141 #define NET_PACKET_ONION_RECV_1 142 +/* Only used for bootstrap servers */ +#define BOOTSTRAP_INFO_PACKET_ID 240 + #define TOX_PORTRANGE_FROM 33445 #define TOX_PORTRANGE_TO 33545 diff --git a/toxcore/onion.c b/toxcore/onion.c index 961f5bd5..578621cc 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c @@ -24,6 +24,7 @@ #endif #include "onion.h" +#include "util.h" #define MAX_ONION_SIZE MAX_DATA_SIZE @@ -36,6 +37,16 @@ #define SEND_2 ONION_SEND_2 #define SEND_1 ONION_SEND_1 +/* Change symmetric keys every hour to make paths expire eventually. */ +#define KEY_REFRESH_INTERVAL (60 * 60) +static void change_symmetric_key(Onion *onion) +{ + if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) { + new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); + } +} + /* Create and send a onion packet. * * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data @@ -126,6 +137,8 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui if (length <= 1 + SEND_1) return 1; + change_symmetric_key(onion); + uint8_t plain[MAX_ONION_SIZE]; int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, @@ -170,6 +183,8 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t if (length <= 1 + SEND_2) return 1; + change_symmetric_key(onion); + uint8_t plain[MAX_ONION_SIZE]; int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, @@ -217,6 +232,8 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t if (length <= 1 + SEND_3) return 1; + change_symmetric_key(onion); + uint8_t plain[MAX_ONION_SIZE]; int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, @@ -263,6 +280,8 @@ static int handle_recv_3(void *object, IP_Port source, uint8_t *packet, uint32_t if (length <= 1 + RETURN_3) return 1; + change_symmetric_key(onion); + uint8_t plain[sizeof(IP_Port) + RETURN_2]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, sizeof(IP_Port) + RETURN_2 + crypto_secretbox_MACBYTES, plain); @@ -295,6 +314,8 @@ static int handle_recv_2(void *object, IP_Port source, uint8_t *packet, uint32_t if (length <= 1 + RETURN_2) return 1; + change_symmetric_key(onion); + uint8_t plain[sizeof(IP_Port) + RETURN_1]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, sizeof(IP_Port) + RETURN_1 + crypto_secretbox_MACBYTES, plain); @@ -327,6 +348,8 @@ static int handle_recv_1(void *object, IP_Port source, uint8_t *packet, uint32_t if (length <= 1 + RETURN_1) return 1; + change_symmetric_key(onion); + IP_Port send_to; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, @@ -358,6 +381,7 @@ Onion *new_onion(DHT *dht) onion->dht = dht; onion->net = dht->c->lossless_udp->net; new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); diff --git a/toxcore/onion.h b/toxcore/onion.h index b46dbdfe..a52bcb86 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h @@ -29,6 +29,7 @@ typedef struct { DHT *dht; Networking_Core *net; uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; + uint64_t timestamp; } Onion; #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 2ca53896..da40584d 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -325,7 +325,7 @@ Onion_Announce *new_onion_announce(DHT *dht) return NULL; onion_a->dht = dht; - onion_a->net = dht->c->lossless_udp->net; + onion_a->net = dht->net; new_symmetric_key(onion_a->secret_bytes); networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 93697c28..c03dfcea 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c @@ -390,6 +390,8 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t crypto_box_PUBLICKEYBYTES) != 0) { DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); + onion_c->friends_list[friend_num].last_seen = unix_time(); + if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { return 1; } @@ -712,6 +714,9 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on if ((uint32_t)friend_num >= onion_c->num_friends) return -1; + if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1) + onion_c->friends_list[friend_num].last_seen = unix_time(); + onion_c->friends_list[friend_num].is_online = is_online; /* This should prevent some clock related issues */ @@ -767,7 +772,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) } if (count != MAX_ONION_CLIENTS) { - if (count < rand() % MAX_ONION_CLIENTS) { + if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { Node_format nodes_list[MAX_SENT_NODES]; uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->friends_list[friendnum].real_client_id, nodes_list, rand() % 2 ? AF_INET : AF_INET6, 1, 0); @@ -788,6 +793,25 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) } } + +/* Timeout before which a peer is considered dead and removed from the DHT search. */ +#define DEAD_ONION_TIMEOUT (10 * 60) + +static void cleanup_friend(Onion_Client *onion_c, uint16_t friendnum) +{ + if (friendnum >= onion_c->num_friends) + return; + + if (onion_c->friends_list[friendnum].status == 0) + return; + + if (onion_c->friends_list[friendnum].is_fake_clientid && !onion_c->friends_list[friendnum].is_online + && is_timeout(onion_c->friends_list[friendnum].last_seen, DEAD_ONION_TIMEOUT)) { + onion_c->friends_list[friendnum].is_fake_clientid = 0; + DHT_delfriend(onion_c->dht, onion_c->friends_list[friendnum].fake_client_id); + } +} + /* Function to call when onion data packet with contents beginning with byte is received. */ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) { @@ -823,7 +847,7 @@ static void do_announce(Onion_Client *onion_c) } if (count != MAX_ONION_CLIENTS) { - if (count < rand() % MAX_ONION_CLIENTS) { + if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { Node_format nodes_list[MAX_SENT_NODES]; uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, rand() % 2 ? AF_INET : AF_INET6, 1, 0); @@ -845,6 +869,7 @@ void do_onion_client(Onion_Client *onion_c) for (i = 0; i < onion_c->num_friends; ++i) { do_friend(onion_c, i); + cleanup_friend(onion_c, i); } onion_c->last_run = unix_time(); diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 708d9093..36b5b5c3 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h @@ -61,6 +61,8 @@ typedef struct { uint64_t last_fakeid_dht_sent; uint64_t last_noreplay; + + uint64_t last_seen; } Onion_Friend; typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); diff --git a/toxcore/tox.c b/toxcore/tox.c index 04e412be..f4690080 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -289,6 +289,13 @@ uint32_t tox_count_friendlist(Tox *tox) return count_friendlist(m); } +/* Return the number of online friends in the instance m. */ +uint32_t tox_get_num_online_friends(Tox *tox) +{ + Messenger *m = tox; + return get_num_online_friends(m); +} + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * Otherwise, returns the number of elements copied. diff --git a/toxcore/tox.h b/toxcore/tox.h index f3118270..447a1146 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -128,6 +128,13 @@ TOX_USERSTATUS; typedef struct Tox Tox; #endif +/* NOTE: Strings in Tox are all UTF-8, also the last byte in all strings must be NULL (0). + * + * The length when passing those strings to the core includes that NULL character. + * + * If you send non NULL terminated strings Tox will force NULL terminates them when it receives them. + */ + /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] */ @@ -284,6 +291,9 @@ void tox_set_sends_receipts(Tox *tox, int friendnumber, int yesno); * for copy_friendlist. */ uint32_t tox_count_friendlist(Tox *tox); +/* Return the number of online friends in the instance m. */ +uint32_t tox_get_num_online_friends(Tox *tox); + /* Copy a list of valid friend IDs into the array out_list. * If out_list is NULL, returns 0. * Otherwise, returns the number of elements copied. -- cgit v1.2.3 From 3ae37315e154152daa9051d2c0a58fbcea0230e0 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 15 Feb 2014 21:29:41 +0100 Subject: Added comments... --- toxav/toxav.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++---------- toxav/toxav.h | 177 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 334 insertions(+), 47 deletions(-) (limited to 'toxav/toxav.c') diff --git a/toxav/toxav.c b/toxav/toxav.c index 5683795e..daf6fe77 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -56,39 +56,24 @@ typedef struct _ToxAv RTPSession* rtp_sessions[2]; /* Audio is first and video is second */ - /* TODO: Add media session */ struct jitter_buffer* j_buf; - CodecState* cs; - /* TODO: Add media session threads */ - + CodecState* cs; void* agent_handler; } ToxAv; - - - - -/******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - * - * +/** + * @brief Start new A/V session. There can only be one session at the time. If you register more + * it will result in undefined behaviour. * - * PUBLIC API FUNCTIONS IMPLEMENTATIONS - * - * - * - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ********************************************************************************************************************/ - - - + * @param messenger The messenger handle. + * @param useragent The agent handling A/V session (i.e. phone). + * @param ua_name Useragent name. + * @param video_width Width of video frame. + * @param video_height Height of video frame. + * @return ToxAv* + * @retval NULL On error. + */ ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name , uint16_t video_width, uint16_t video_height) { ToxAv* av = calloc ( sizeof(ToxAv), 1); @@ -112,6 +97,12 @@ ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name , uint16_ return av; } +/** + * @brief Remove A/V session. + * + * @param av Handler. + * @return void + */ void toxav_kill ( ToxAv* av ) { msi_terminate_session(av->msi_session); @@ -129,13 +120,29 @@ void toxav_kill ( ToxAv* av ) free(av); } +/** + * @brief Register callback for call state. + * + * @param callback The callback + * @param id One of the ToxAvCallbackID values + * @return void + */ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id ) { msi_register_callback((MSICallback)callback, (MSICallbackID) id); } - - +/** + * @brief Call user. Use its friend_id. + * + * @param av Handler. + * @param user The user. + * @param call_type Call type. + * @param ringing_seconds Ringing timeout. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_call (ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds ) { if ( av->msi_session->call ) { @@ -145,6 +152,14 @@ int toxav_call (ToxAv* av, int user, ToxAvCallType call_type, int ringing_second return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user); } +/** + * @brief Hangup active call. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_hangup ( ToxAv* av ) { if ( !av->msi_session->call ) { @@ -158,6 +173,15 @@ int toxav_hangup ( ToxAv* av ) return msi_hangup(av->msi_session); } +/** + * @brief Answer incomming call. + * + * @param av Handler. + * @param call_type Answer with... + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_answer ( ToxAv* av, ToxAvCallType call_type ) { if ( !av->msi_session->call ) { @@ -171,6 +195,15 @@ int toxav_answer ( ToxAv* av, ToxAvCallType call_type ) return msi_answer(av->msi_session, call_type); } +/** + * @brief Reject incomming call. + * + * @param av Handler. + * @param reason Optional reason. Set NULL if none. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_reject ( ToxAv* av, const char* reason ) { if ( !av->msi_session->call ) { @@ -184,6 +217,15 @@ int toxav_reject ( ToxAv* av, const char* reason ) return msi_reject(av->msi_session, (const uint8_t*) reason); } +/** + * @brief Cancel outgoing request. + * + * @param av Handler. + * @param reason Optional reason. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_cancel ( ToxAv* av, const char* reason ) { if ( !av->msi_session->call ) { @@ -193,7 +235,14 @@ int toxav_cancel ( ToxAv* av, const char* reason ) return msi_cancel(av->msi_session, 0, (const uint8_t*)reason); } -/* You can stop the call at any state */ +/** + * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_stop_call ( ToxAv* av ) { if ( !av->msi_session->call ) { @@ -203,7 +252,14 @@ int toxav_stop_call ( ToxAv* av ) return msi_stopcall(av->msi_session); } - +/** + * @brief Must be call before any RTP transmission occurs. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_prepare_transmission ( ToxAv* av ) { assert(av->msi_session); @@ -246,7 +302,14 @@ int toxav_prepare_transmission ( ToxAv* av ) return ErrorNone; } - +/** + * @brief Call this at the end of the transmission. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_kill_transmission ( ToxAv* av ) { /* Both sessions should be active at any time */ @@ -268,6 +331,17 @@ int toxav_kill_transmission ( ToxAv* av ) } +/** + * @brief Send RTP payload. + * + * @param av Handler. + * @param type Type of payload. + * @param payload The payload. + * @param length Size of it. + * @return int + * @retval 0 Success. + * @retval -1 Failure. + */ inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length ) { if ( av->rtp_sessions[type - TypeAudio] ) @@ -275,6 +349,16 @@ inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8 else return -1; } +/** + * @brief Receive RTP payload. + * + * @param av Handler. + * @param type Type of the payload. + * @param dest Storage. + * @return int + * @retval ToxAvError On Error. + * @retval >=0 Size of received payload. + */ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, uint8_t* dest ) { if ( !dest ) return ErrorInternal; @@ -316,6 +400,15 @@ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, uint8_t* de return 0; } +/** + * @brief Receive decoded video packet. + * + * @param av Handler. + * @param output Storage. + * @return int + * @retval 0 Success. + * @retval ToxAvError On Error. + */ inline__ int toxav_recv_video ( ToxAv* av, vpx_image_t **output) { if ( !output ) return ErrorInternal; @@ -337,6 +430,15 @@ inline__ int toxav_recv_video ( ToxAv* av, vpx_image_t **output) return 0; } +/** + * @brief Encode and send video packet. + * + * @param av Handler. + * @param input The packet. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ 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) { @@ -360,6 +462,17 @@ inline__ int toxav_send_video ( ToxAv* av, vpx_image_t *input) return ErrorInternal; } +/** + * @brief Receive decoded audio frame. + * + * @param av Handler. + * @param frame_size ... + * @param dest Destination of the packet. Make sure it has enough space for + * RTP_PAYLOAD_SIZE bytes. + * @return int + * @retval >=0 Size of received packet. + * @retval ToxAvError On error. + */ inline__ int toxav_recv_audio ( ToxAv* av, int frame_size, int16_t* dest ) { if ( !dest ) return ErrorInternal; @@ -373,10 +486,20 @@ inline__ int toxav_recv_audio ( ToxAv* av, int frame_size, int16_t* dest ) } else if ( recved_size ){ return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); } else { - return ErrorInternal; + return 0; /* Nothing received */ } } +/** + * @brief Encode and send audio frame. + * + * @param av Handler. + * @param frame The frame. + * @param frame_size It's size. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ inline__ int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size) { uint8_t temp_data[RTP_PAYLOAD_SIZE]; @@ -387,6 +510,15 @@ inline__ int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size) return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); } +/** + * @brief Get peer transmission type. It can either be audio or video. + * + * @param av Handler. + * @param peer The peer + * @return int + * @retval ToxAvCallType On success. + * @retval ToxAvError On error. + */ int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) { assert(av->msi_session); @@ -396,6 +528,12 @@ int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) return av->msi_session->call->type_peer[peer]; } +/** + * @brief Get reference to an object that is handling av session. + * + * @param av Handler. + * @return void* + */ void* toxav_get_agent_handler ( ToxAv* av ) { return av->agent_handler; diff --git a/toxav/toxav.h b/toxav/toxav.h index 63dbf162..4863f8eb 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -63,7 +63,7 @@ typedef struct Tox Tox; /** - * @brief Callbacks ids that handle the call states + * @brief Callbacks ids that handle the call states. */ typedef enum { /* Requests */ @@ -94,6 +94,10 @@ typedef enum { } ToxAvCallType; +/** + * @brief Error indicators. + * + */ typedef enum { ErrorNone = 0, ErrorInternal = -1, /* Internal error */ @@ -111,42 +115,187 @@ typedef enum { } ToxAvError; -ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name, uint16_t video_width, uint16_t video_height) ; +/** + * @brief Start new A/V session. There can only be one session at the time. If you register more + * it will result in undefined behaviour. + * + * @param messenger The messenger handle. + * @param useragent The agent handling A/V session (i.e. phone). + * @param ua_name Useragent name. + * @param video_width Width of video frame. + * @param video_height Height of video frame. + * @return ToxAv* + * @retval NULL On error. + */ +ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name, uint16_t video_width, uint16_t video_height); + +/** + * @brief Remove A/V session. + * + * @param av Handler. + * @return void + */ void toxav_kill(ToxAv* av); +/** + * @brief Register callback for call state. + * + * @param callback The callback + * @param id One of the ToxAvCallbackID values + * @return void + */ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); - +/** + * @brief Call user. Use its friend_id. + * + * @param av Handler. + * @param user The user. + * @param call_type Call type. + * @param ringing_seconds Ringing timeout. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_call(ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds); + +/** + * @brief Hangup active call. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_hangup(ToxAv* av); + +/** + * @brief Answer incomming call. + * + * @param av Handler. + * @param call_type Answer with... + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_answer(ToxAv* av, ToxAvCallType call_type ); + +/** + * @brief Reject incomming call. + * + * @param av Handler. + * @param reason Optional reason. Set NULL if none. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_reject(ToxAv* av, const char* reason); + +/** + * @brief Cancel outgoing request. + * + * @param av Handler. + * @param reason Optional reason. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_cancel(ToxAv* av, const char* reason); + +/** + * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_stop_call(ToxAv* av); +/** + * @brief Must be call before any RTP transmission occurs. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_prepare_transmission(ToxAv* av); -int toxav_kill_transmission(ToxAv* av); - - - -/* Return length of received packet. Returns 0 if nothing recved. Dest has to have - * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque. - * For video packets set 'ready' at _any_ value. +/** + * @brief Call this at the end of the transmission. + * + * @param av Handler. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. */ +int toxav_kill_transmission(ToxAv* av); -/* returns 0 on success */ +/** + * @brief Receive decoded video packet. + * + * @param av Handler. + * @param output Storage. + * @return int + * @retval 0 Success. + * @retval ToxAvError On Error. + */ int toxav_recv_video ( ToxAv* av, vpx_image_t **output); +/** + * @brief Receive decoded audio frame. + * + * @param av Handler. + * @param frame_size ... + * @param dest Destination of the packet. Make sure it has enough space for + * RTP_PAYLOAD_SIZE bytes. + * @return int + * @retval >=0 Size of received packet. + * @retval ToxAvError On error. + */ int toxav_recv_audio( ToxAv* av, int frame_size, int16_t* dest ); +/** + * @brief Encode and send video packet. + * + * @param av Handler. + * @param input The packet. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ int toxav_send_video ( ToxAv* av, vpx_image_t *input); -/* Encode and send audio frame. */ -int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size); - +/** + * @brief Encode and send audio frame. + * + * @param av Handler. + * @param frame The frame. + * @param frame_size It's size. + * @return int + * @retval 0 Success. + * @retval ToxAvError On error. + */ +int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size); +/** + * @brief Get peer transmission type. It can either be audio or video. + * + * @param av Handler. + * @param peer The peer + * @return int + * @retval ToxAvCallType On success. + * @retval ToxAvError On error. + */ int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); + +/** + * @brief Get reference to an object that is handling av session. + * + * @param av Handler. + * @return void* + */ void* toxav_get_agent_handler ( ToxAv* av ); #endif /* __TOXAV */ \ No newline at end of file -- cgit v1.2.3 From 272ed7e6db2c76be6829c36d9ce4c77de7b4cf52 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 15 Feb 2014 22:36:15 +0100 Subject: Moved event to toxav --- configure.ac | 16 ++- toxav/Makefile.inc | 13 +- toxav/event.c | 373 ++++++++++++++++++++++++++++++++++++++++++++++++++ toxav/event.h | 50 +++++++ toxav/media.c | 31 +++-- toxav/media.h | 31 +++-- toxav/msi.c | 5 +- toxav/msi.h | 3 +- toxav/phone.c | 3 +- toxav/rtp.c | 3 +- toxav/rtp.h | 3 +- toxav/toxav.c | 3 +- toxav/toxav.h | 3 +- toxcore/Makefile.inc | 8 +- toxcore/event.c | 374 --------------------------------------------------- toxcore/event.h | 51 ------- 16 files changed, 483 insertions(+), 487 deletions(-) create mode 100755 toxav/event.c create mode 100755 toxav/event.h delete mode 100755 toxcore/event.c delete mode 100755 toxcore/event.h (limited to 'toxav/toxav.c') diff --git a/configure.ac b/configure.ac index 28b5e7e1..2b4fad78 100644 --- a/configure.ac +++ b/configure.ac @@ -349,12 +349,16 @@ AC_C_BIGENDIAN AC_FUNC_FORK AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc]) -AX_PTHREAD( - [], - [ - AC_MSG_ERROR([Error: required pthread library not found]) - ] -) +if test "x$BUILD_AV" = "xyes"; then + AX_PTHREAD( + [], + [ + AC_MSG_WARN([disabling AV support: required pthread library not found]) + BUILD_AV="no" + BUILD_PHONE="no" + ] + ) +fi if test "x$BUILD_PHONE" = "xyes"; then PKG_CHECK_MODULES([AVFORMAT], [libavformat], diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index 578b6ffc..50b3ad83 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc @@ -4,7 +4,9 @@ lib_LTLIBRARIES += libtoxav.la libtoxav_la_include_HEADERS = ../toxav/toxav.h libtoxav_la_includedir = $(includedir)/tox -libtoxav_la_SOURCES = ../toxav/rtp.h \ +libtoxav_la_SOURCES = ../toxav/event.h \ + ../toxav/event.c \ + ../toxav/rtp.h \ ../toxav/rtp.c \ ../toxav/msi.h \ ../toxav/msi.c \ @@ -18,7 +20,8 @@ libtoxav_la_CFLAGS = -I../toxcore \ -I../toxav \ $(NACL_CFLAGS) \ $(OPUS_CFLAGS) \ - $(VPX_CFLAGS) + $(VPX_CFLAGS) \ + $(PTHREAD_CFLAGS) libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \ $(NACL_LDFLAGS) \ @@ -26,7 +29,8 @@ libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \ libtoxav_la_LIBS = $(NACL_LIBS) \ $(OPUS_LIBS) \ - $(VPX_LIBS) + $(VPX_LIBS) \ + $(PTHREAD_LIBS) endif @@ -63,7 +67,8 @@ phone_LDADD = libtoxav.la \ $(SDL_LIBS) \ $(OPENAL_LIBS) \ $(OPUS_LIBS) \ - $(VPX_LIBS) + $(VPX_LIBS)\ + $(PTHREAD_LIBS) endif \ No newline at end of file diff --git a/toxav/event.c b/toxav/event.c new file mode 100755 index 00000000..9efe4be4 --- /dev/null +++ b/toxav/event.c @@ -0,0 +1,373 @@ +/** event.c + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + * + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include "event.h" + +#include "../toxcore/util.h" +#include "../toxcore/network.h" + +#define _GNU_SOURCE + +#include +#include +#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 LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex) +#define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex) + +#define FREQUENCY 10000 + +#define inline__ inline __attribute__((always_inline)) + + +typedef struct _EventContainer { + 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; + + pthread_mutex_t mutex; + +} EventHandler; + +int throw_event( void* (func)(void*), void* arg ); +int reset_timer_event ( int id, uint32_t timeout ); +int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout); +int cancel_timer_event ( int id ); +int execute_timer_event ( int id ); + +struct _Event event = +{ + throw_event, + /* reset_timer_event */ NULL, + throw_timer_event, + cancel_timer_event, + /*execute_timer_event*/ NULL +}; + +/* + * Random functions used by this file + */ +void clear_events (EventContainer** event_container, size_t* counter) +{ + free(*event_container ); + + *event_container = NULL; + *counter = 0; +} + +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 ); + + 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 ) +{ + 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; + } + } + + } +} + +/* ============================================= */ + +/* main poll for event execution */ +void* event_poll( void* arg ) +{ + EventHandler* _event_handler = arg; + + while ( _event_handler->running ) + { + + 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); + + } + + } + + UNLOCK( _event_handler ); + + usleep(FREQUENCY); + } + + LOCK( _event_handler ); + + clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count); + + UNLOCK( _event_handler ); + + _event_handler->running = -1; + pthread_exit(NULL); +} + +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); +} + +EventHandler event_handler; + +/* Place and order array of timers */ +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)); + EventContainer* _it = event_handler.timed_events; + + int _i = event_handler.timed_events_count; + + /* Find it and execute */ + for ( ; _i; _i-- ) { + if ( _it->id == id ) { + RUN_IN_THREAD ( _it->func, _it->func_args ); + break; + } + ++_it; + } + + /* Now remove it from the queue */ + + if ( _i ) { + for ( ; _i; -- _i ){ *_it = *(_it + 1); ++_it; } + + -- event_handler.timed_events_count; + + 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)); + + return _status; +} + +int reset_timer_event ( int id, uint32_t timeout ) +{ + int _status; + + 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 ) { + _it->timeout = timeout + ((uint32_t)(current_time() / 1000)); + break; + } + ++_it; + } + + _status = _i ? -1 : 0; + + UNLOCK((&event_handler)); + + return _status; +} + +/* Remove timer from array */ +inline__ int cancel_timer_event ( int id ) +{ + return pop_id (&event_handler.timed_events, &event_handler.timed_events_count, id ); +} + + +/* Initialization and termination of event polls + * This will be run at the beginning and the end of the program execution. + * I think that's the best way to do it. + */ + +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); +} + +/* NOTE: Do we need this? */ +void __attribute__((destructor)) terminate_event_poll() +{ + /* Exit thread */ + event_handler.running = 0; + + /* Give it enought time to exit */ + usleep(FREQUENCY*2); + + pthread_mutex_destroy( &event_handler.mutex ); +} \ No newline at end of file diff --git a/toxav/event.h b/toxav/event.h new file mode 100755 index 00000000..17dadbd5 --- /dev/null +++ b/toxav/event.h @@ -0,0 +1,50 @@ +/** event.h + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + * + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 + */ + + +#ifndef __TOXEVENT +#define __TOXEVENT + + +/** + * - Events are, in fact, ran in their own threads upon execution. + * - Event handler is initialized at the start, before the main() function + * and terminated after it's execution. + * - Timers are checked for timeout every ~10000 ns. + * - Timers can be canceled or ran immediately via + * timer_release() or timer_now() functions. + * - Timeout is measured in milliseconds. + * + * NOTE: timer_reset () and timer_now() are not tested nor usable atm + * + */ +extern struct _Event +{ + int (*rise) (void* ( func ) ( void* ), void* arg); + int (*timer_reset ) ( int id, unsigned timeout ); + int (*timer_alloc) (void* ( func ) ( void* ), void* arg, unsigned timeout); + int (*timer_release) (int id); + int (*timer_now) ( int id ); +} event; + +#endif /* _MSI__EVENT_H_ */ diff --git a/toxav/media.c b/toxav/media.c index a327c751..c4894076 100644 --- a/toxav/media.c +++ b/toxav/media.c @@ -1,27 +1,26 @@ -/* AV_codec.c -// * - * Audio and video codec intitialisation, encoding/decoding and playback +/** media.c + * + * Audio and video codec intitialization, encoding/decoding and playback * - * Copyright (C) 2013 Tox project All Rights Reserved. + * Copyright (C) 2013 Tox project All Rights Reserved. * - * This file is part of Tox. + * This file is part of Tox. * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . * */ -/*----------------------------------------------------------------------------------*/ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/toxav/media.h b/toxav/media.h index 4230de8f..030a36ac 100644 --- a/toxav/media.h +++ b/toxav/media.h @@ -1,27 +1,26 @@ -/* AV_codec.h +/** media.h + * + * Audio and video codec intitialization, encoding/decoding and playback * - * Audio and video codec intitialisation, encoding/decoding and playback + * Copyright (C) 2013 Tox project All Rights Reserved. * - * Copyright (C) 2013 Tox project All Rights Reserved. + * This file is part of Tox. * - * This file is part of Tox. + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . * */ -/*----------------------------------------------------------------------------------*/ #ifndef _AVCODEC_H_ #define _AVCODEC_H_ diff --git a/toxav/msi.c b/toxav/msi.c index f00029ba..84ab973f 100644 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -18,8 +18,7 @@ * along with Tox. If not, see . * * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 */ @@ -30,9 +29,9 @@ #define _BSD_SOURCE #include "msi.h" +#include "event.h" #include "../toxcore/util.h" #include "../toxcore/network.h" -#include "../toxcore/event.h" #include "../toxcore/Messenger.h" #include diff --git a/toxav/msi.h b/toxav/msi.h index 4487dae6..5b693da4 100644 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -18,8 +18,7 @@ * along with Tox. If not, see . * * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 */ #ifndef __TOXMSI diff --git a/toxav/phone.c b/toxav/phone.c index 92d16906..161275d9 100755 --- a/toxav/phone.c +++ b/toxav/phone.c @@ -47,7 +47,7 @@ //#include "media.h" #include "toxav.h" -#include "../toxcore/event.h" +#include "event.h" #include "../toxcore/tox.h" #ifdef TOX_FFMPEG @@ -904,6 +904,7 @@ av_session_t* av_init_session() char dev[2]; char* left; char* warned_ = fgets(dev, 2, stdin); + (void)warned_; long selection = strtol(dev, &left, 10); if ( *left ) { diff --git a/toxav/rtp.c b/toxav/rtp.c index 80fcc630..2543c509 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -18,8 +18,7 @@ * along with Tox. If not, see . * * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 */ #ifdef HAVE_CONFIG_H diff --git a/toxav/rtp.h b/toxav/rtp.h index 03f6a873..acec8b0a 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h @@ -18,8 +18,7 @@ * along with Tox. If not, see . * * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 */ #ifndef __TOXRTP diff --git a/toxav/toxav.c b/toxav/toxav.c index daf6fe77..b40a1c02 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -18,8 +18,7 @@ * along with Tox. If not, see . * * - * Report bugs/suggestions at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 */ #ifdef HAVE_CONFIG_H diff --git a/toxav/toxav.h b/toxav/toxav.h index 4863f8eb..82334273 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -18,8 +18,7 @@ * along with Tox. If not, see . * * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com + * Report bugs/suggestions at #tox-dev @ freenode.net:6667 */ diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index c9e94911..51b4c20b 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -29,8 +29,6 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/group_chats.c \ ../toxcore/assoc.h \ ../toxcore/assoc.c \ - ../toxcore/event.h \ - ../toxcore/event.c \ ../toxcore/onion.h \ ../toxcore/onion.c \ ../toxcore/onion_announce.h \ @@ -42,8 +40,7 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ libtoxcore_la_CFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/toxcore \ $(LIBSODIUM_CFLAGS) \ - $(NACL_CFLAGS) \ - $(PTHREAD_CFLAGS) + $(NACL_CFLAGS) libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \ $(EXTRA_LT_LDFLAGS) \ @@ -52,5 +49,4 @@ libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \ $(WINSOCK2_LIBS) libtoxcore_la_LIBS = $(LIBSODIUM_LIBS) \ - $(NAC_LIBS) \ - $(PTHREAD_LIBS) + $(NAC_LIBS) diff --git a/toxcore/event.c b/toxcore/event.c deleted file mode 100755 index 2fdc9442..00000000 --- a/toxcore/event.c +++ /dev/null @@ -1,374 +0,0 @@ -/** event.c - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include -#include "event.h" - -#include "util.h" -#include "network.h" - -#define _GNU_SOURCE - -#include -#include -#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 LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex) -#define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex) - -#define FREQUENCY 10000 - -#define inline__ inline __attribute__((always_inline)) - - -typedef struct _EventContainer { - 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; - - pthread_mutex_t mutex; - -} EventHandler; - -int throw_event( void* (func)(void*), void* arg ); -int reset_timer_event ( int id, uint32_t timeout ); -int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout); -int cancel_timer_event ( int id ); -int execute_timer_event ( int id ); - -struct _Event event = -{ - throw_event, - /* reset_timer_event */ NULL, - throw_timer_event, - cancel_timer_event, - /*execute_timer_event*/ NULL -}; - -/* - * Random functions used by this file - */ -void clear_events (EventContainer** event_container, size_t* counter) -{ - free(*event_container ); - - *event_container = NULL; - *counter = 0; -} - -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 ); - - 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 ) -{ - 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; - } - } - - } -} - -/* ============================================= */ - -/* main poll for event execution */ -void* event_poll( void* arg ) -{ - EventHandler* _event_handler = arg; - - while ( _event_handler->running ) - { - - 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); - - } - - } - - UNLOCK( _event_handler ); - - usleep(FREQUENCY); - } - - LOCK( _event_handler ); - - clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count); - - UNLOCK( _event_handler ); - - _event_handler->running = -1; - pthread_exit(NULL); -} - -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); -} - -EventHandler event_handler; - -/* Place and order array of timers */ -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)); - EventContainer* _it = event_handler.timed_events; - - int _i = event_handler.timed_events_count; - - /* Find it and execute */ - for ( ; _i; _i-- ) { - if ( _it->id == id ) { - RUN_IN_THREAD ( _it->func, _it->func_args ); - break; - } - ++_it; - } - - /* Now remove it from the queue */ - - if ( _i ) { - for ( ; _i; -- _i ){ *_it = *(_it + 1); ++_it; } - - -- event_handler.timed_events_count; - - 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)); - - return _status; -} - -int reset_timer_event ( int id, uint32_t timeout ) -{ - int _status; - - 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 ) { - _it->timeout = timeout + ((uint32_t)(current_time() / 1000)); - break; - } - ++_it; - } - - _status = _i ? -1 : 0; - - UNLOCK((&event_handler)); - - return _status; -} - -/* Remove timer from array */ -inline__ int cancel_timer_event ( int id ) -{ - return pop_id (&event_handler.timed_events, &event_handler.timed_events_count, id ); -} - - -/* Initialization and termination of event polls - * This will be run at the beginning and the end of the program execution. - * I think that's the best way to do it. - */ - -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); -} - -/* NOTE: Do we need this? */ -void __attribute__((destructor)) terminate_event_poll() -{ - /* Exit thread */ - event_handler.running = 0; - - /* Give it enought time to exit */ - usleep(FREQUENCY*2); - - pthread_mutex_destroy( &event_handler.mutex ); -} \ No newline at end of file diff --git a/toxcore/event.h b/toxcore/event.h deleted file mode 100755 index 690cc1ca..00000000 --- a/toxcore/event.h +++ /dev/null @@ -1,51 +0,0 @@ -/** event.h - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - * - * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or - * my email: eniz_vukovic@hotmail.com - */ - - -#ifndef __TOXEVENT -#define __TOXEVENT - - -/** - * - Events are, in fact, ran in their own threads upon execution. - * - Event handler is initialized at the start, before the main() function - * and terminated after it's execution. - * - Timers are checked for timeout every ~10000 ns. - * - Timers can be canceled or ran immediately via - * timer_release() or timer_now() functions. - * - Timeout is measured in milliseconds. - * - * NOTE: timer_reset () and timer_now() are not tested nor usable atm - * - */ -extern struct _Event -{ - int (*rise) (void* ( func ) ( void* ), void* arg); - int (*timer_reset ) ( int id, unsigned timeout ); - int (*timer_alloc) (void* ( func ) ( void* ), void* arg, unsigned timeout); - int (*timer_release) (int id); - int (*timer_now) ( int id ); -} event; - -#endif /* _MSI__EVENT_H_ */ -- cgit v1.2.3