mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Public header ready to go
This commit is contained in:
parent
292708c336
commit
393433ce99
92
configure.ac
92
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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
# ****** RTP ****** #
|
||||
|
||||
libtoxrtp_la_include_HEADERS = \
|
||||
../toxav/toxrtp.h
|
||||
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
|
||||
|
||||
libtoxrtp_la_includedir = $(includedir)/tox
|
||||
|
||||
libtoxrtp_la_SOURCES = ../toxav/toxrtp.h \
|
||||
../toxav/toxrtp.c
|
||||
libtoxav_la_CFLAGS = -I../toxcore \
|
||||
-I../toxav \
|
||||
$(NACL_CFLAGS) \
|
||||
$(OPUS_CFLAGS) \
|
||||
$(VPX_CFLAGS)
|
||||
|
||||
libtoxrtp_la_CFLAGS = -I../toxcore \
|
||||
-I../toxav \
|
||||
$(NACL_CFLAGS)
|
||||
libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
$(EXTRA_LT_LDFLAGS)
|
||||
|
||||
libtoxav_la_LIBS = $(NACL_LIBS) \
|
||||
$(OPUS_LIBS) \
|
||||
$(VPX_LIBS)
|
||||
|
||||
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 ****** #
|
||||
if BUILD_PHONE
|
||||
|
||||
libtoxmedia_la_include_HEADERS = \
|
||||
../toxav/toxmedia.h
|
||||
|
||||
libtoxmedia_la_includedir = $(includedir)/tox
|
||||
|
||||
libtoxmedia_la_SOURCES = ../toxav/toxmedia.h \
|
||||
../toxav/toxmedia.c
|
||||
|
||||
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
|
151
toxav/media.c
151
toxav/media.c
|
@ -28,13 +28,8 @@
|
|||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavdevice/avdevice.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <opus/opus.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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");
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
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");
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -27,66 +27,27 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "../toxcore/tox.h"
|
||||
#include <pthread.h>
|
||||
|
||||
/* Video encoding/decoding */
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavdevice/avdevice.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <vpx/vpx_decoder.h>
|
||||
#include <vpx/vpx_encoder.h>
|
||||
#include <vpx/vp8dx.h>
|
||||
#include <vpx/vp8cx.h>
|
||||
#define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx())
|
||||
#define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx())
|
||||
|
||||
/* Audio encoding/decoding */
|
||||
#include <opus/opus.h>
|
||||
|
||||
/* 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);
|
||||
|
||||
|
|
40
toxav/msi.c
40
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;
|
||||
|
|
|
@ -26,9 +26,10 @@
|
|||
#define __TOXMSI
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "../toxcore/tox.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#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 );
|
||||
|
||||
|
||||
/**
|
||||
|
|
401
toxav/phone.c
401
toxav/phone.c
|
@ -44,17 +44,40 @@
|
|||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
|
||||
//#include "media.h"
|
||||
#include "toxav.h"
|
||||
#include "../toxcore/event.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
#ifdef TOX_FFMPEG
|
||||
/* Video encoding/decoding */
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavdevice/avdevice.h>
|
||||
#include <libavutil/opt.h>
|
||||
#endif
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_thread.h>
|
||||
#include <pthread.h>
|
||||
#include <opus/opus.h>
|
||||
|
||||
#include "media.h"
|
||||
#include "toxav.h"
|
||||
#include "../toxcore/event.h"
|
||||
#include "../toxcore/tox.h"
|
||||
/* 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 ) {
|
||||
|
|
55
toxav/rtp.c
55
toxav/rtp.c
|
@ -30,10 +30,6 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 );
|
||||
|
|
18
toxav/rtp.h
18
toxav/rtp.h
|
@ -28,10 +28,14 @@
|
|||
#define RTP_VERSION 2
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#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 );
|
||||
|
||||
|
||||
|
||||
|
|
136
toxav/toxav.c
136
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
|
||||
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 )
|
||||
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_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE);
|
||||
*output = img;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline__ int toxav_send_video ( ToxAv* av, vpx_image_t *input)
|
||||
{
|
||||
if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) {
|
||||
printf("could not encode video frame\n");
|
||||
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 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;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#define __TOXAV
|
||||
#include <inttypes.h>
|
||||
|
||||
/* vpx_image_t */
|
||||
#include <vpx/vpx_image.h>
|
||||
|
||||
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_recv_audio( ToxAv* av, int frame_size, int16_t* dest );
|
||||
|
||||
|
||||
int toxav_decode_audio( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* 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 */
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata);
|
||||
if (m->friend_connectionstatuschange)
|
||||
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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "event.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "network.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user