diff options
-rw-r--r-- | configure.ac | 92 | ||||
-rw-r--r-- | toxav/Makefile.inc | 134 | ||||
-rw-r--r-- | toxav/media.c | 151 | ||||
-rw-r--r-- | toxav/media.h | 78 | ||||
-rw-r--r-- | toxav/msi.c | 40 | ||||
-rw-r--r-- | toxav/msi.h | 9 | ||||
-rwxr-xr-x | toxav/phone.c | 401 | ||||
-rw-r--r-- | toxav/rtp.c | 55 | ||||
-rw-r--r-- | toxav/rtp.h | 18 | ||||
-rw-r--r-- | toxav/toxav.c | 128 | ||||
-rw-r--r-- | toxav/toxav.h | 47 | ||||
-rw-r--r-- | toxcore/DHT.c | 10 | ||||
-rw-r--r-- | toxcore/Messenger.c | 158 | ||||
-rw-r--r-- | toxcore/Messenger.h | 34 | ||||
-rwxr-xr-x | toxcore/event.c | 1 | ||||
-rw-r--r-- | toxcore/friend_requests.c | 3 | ||||
-rw-r--r-- | toxcore/group_chats.c | 30 | ||||
-rw-r--r-- | toxcore/network.c | 4 | ||||
-rw-r--r-- | toxcore/network.h | 9 | ||||
-rw-r--r-- | toxcore/onion.c | 24 | ||||
-rw-r--r-- | toxcore/onion.h | 1 | ||||
-rw-r--r-- | toxcore/onion_announce.c | 2 | ||||
-rw-r--r-- | toxcore/onion_client.c | 29 | ||||
-rw-r--r-- | toxcore/onion_client.h | 2 | ||||
-rw-r--r-- | toxcore/tox.c | 7 | ||||
-rw-r--r-- | toxcore/tox.h | 10 |
26 files changed, 915 insertions, 562 deletions
diff --git a/configure.ac b/configure.ac index afb327cb..28b5e7e1 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -13,8 +13,7 @@ AC_CONFIG_MACRO_DIR([m4]) | |||
13 | EXTRA_LT_LDFLAGS= | 13 | EXTRA_LT_LDFLAGS= |
14 | 14 | ||
15 | LIBTOXCORE_LT_VERSION=0:0:0 | 15 | LIBTOXCORE_LT_VERSION=0:0:0 |
16 | LIBTOXMSI_LT_VERSION=0:0:0 | 16 | LIBTOXAV_LT_VERSION=0:0:0 |
17 | LIBTOXRTP_LT_VERSION=0:0:0 | ||
18 | dnl | 17 | dnl |
19 | dnl current:revision:age | 18 | dnl current:revision:age |
20 | dnl | 19 | dnl |
@@ -24,12 +23,10 @@ dnl incremented | |||
24 | dnl age: increment if interfaces have been added, set to zero if | 23 | dnl age: increment if interfaces have been added, set to zero if |
25 | dnl interfaces have been removed or changed | 24 | dnl interfaces have been removed or changed |
26 | TOXCORE_LT_LDFLAGS="-version-info $LIBTOXCORE_LT_VERSION" | 25 | TOXCORE_LT_LDFLAGS="-version-info $LIBTOXCORE_LT_VERSION" |
27 | TOXMSI_LT_LDFLAGS="-version-info $LIBTOXMSI_LT_VERSION" | 26 | TOXAV_LT_LDFLAGS="-version-info $LIBTOXAV_LT_VERSION" |
28 | TOXRTP_LT_LDFLAGS="-version-info $LIBTOXMSI_LT_VERSION" | ||
29 | 27 | ||
30 | AC_SUBST(TOXCORE_LT_LDFLAGS) | 28 | AC_SUBST(TOXCORE_LT_LDFLAGS) |
31 | AC_SUBST(TOXMSI_LT_LDFLAGS) | 29 | AC_SUBST(TOXAV_LT_LDFLAGS) |
32 | AC_SUBST(TOXRTP_LT_LDFLAGS) | ||
33 | 30 | ||
34 | if test "x${prefix}" = "xNONE"; then | 31 | if test "x${prefix}" = "xNONE"; then |
35 | prefix="${ac_default_prefix}" | 32 | prefix="${ac_default_prefix}" |
@@ -39,6 +36,7 @@ BUILD_DHT_BOOTSTRAP_DAEMON="yes" | |||
39 | BUILD_NTOX="yes" | 36 | BUILD_NTOX="yes" |
40 | BUILD_TESTS="yes" | 37 | BUILD_TESTS="yes" |
41 | BUILD_AV="yes" | 38 | BUILD_AV="yes" |
39 | BUILD_PHONE="yes" | ||
42 | BUILD_TESTING="yes" | 40 | BUILD_TESTING="yes" |
43 | 41 | ||
44 | NCURSES_FOUND="no" | 42 | NCURSES_FOUND="no" |
@@ -64,12 +62,24 @@ AC_ARG_ENABLE([av], | |||
64 | [ | 62 | [ |
65 | if test "x$enableval" = "xno"; then | 63 | if test "x$enableval" = "xno"; then |
66 | BUILD_AV="no" | 64 | BUILD_AV="no" |
65 | BUILD_PHONE="no" | ||
67 | elif test "x$enableval" = "xyes"; then | 66 | elif test "x$enableval" = "xyes"; then |
68 | BUILD_AV="yes" | 67 | BUILD_AV="yes" |
69 | fi | 68 | fi |
70 | ] | 69 | ] |
71 | ) | 70 | ) |
72 | 71 | ||
72 | AC_ARG_ENABLE([phone], | ||
73 | [AC_HELP_STRING([--disable-phone], [build test phone (default: auto)]) ], | ||
74 | [ | ||
75 | if test "x$enableval" = "xno"; then | ||
76 | BUILD_PHONE="no" | ||
77 | elif test "x$enableval" = "xyes"; then | ||
78 | BUILD_PHONE="yes" | ||
79 | fi | ||
80 | ] | ||
81 | ) | ||
82 | |||
73 | AC_ARG_ENABLE([tests], | 83 | AC_ARG_ENABLE([tests], |
74 | [AC_HELP_STRING([--disable-tests], [build unit tests (default: auto)]) ], | 84 | [AC_HELP_STRING([--disable-tests], [build unit tests (default: auto)]) ], |
75 | [ | 85 | [ |
@@ -339,82 +349,79 @@ AC_C_BIGENDIAN | |||
339 | AC_FUNC_FORK | 349 | AC_FUNC_FORK |
340 | AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc]) | 350 | AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc]) |
341 | 351 | ||
342 | if test "x$BUILD_AV" = "xyes"; then | 352 | AX_PTHREAD( |
343 | AX_PTHREAD( | 353 | [], |
344 | [], | 354 | [ |
345 | [ | 355 | AC_MSG_ERROR([Error: required pthread library not found]) |
346 | AC_MSG_WARN([disabling AV support: required pthread library not found]) | 356 | ] |
347 | BUILD_AV="no" | 357 | ) |
348 | ] | ||
349 | ) | ||
350 | fi | ||
351 | 358 | ||
352 | if test "x$BUILD_AV" = "xyes"; then | 359 | if test "x$BUILD_PHONE" = "xyes"; then |
353 | PKG_CHECK_MODULES([AVFORMAT], [libavformat], | 360 | PKG_CHECK_MODULES([AVFORMAT], [libavformat], |
354 | [], | 361 | [], |
355 | [ | 362 | [ |
356 | AC_MSG_WARN([disabling AV support $AVFORMAT_PKG_ERRORS]) | 363 | AC_MSG_WARN([disabling phone $AVFORMAT_PKG_ERRORS]) |
357 | BUILD_AV="no" | 364 | BUILD_PHONE="no" |
358 | ] | 365 | ] |
359 | ) | 366 | ) |
360 | fi | 367 | fi |
361 | 368 | ||
362 | if test "x$BUILD_AV" = "xyes"; then | 369 | if test "x$BUILD_PHONE" = "xyes"; then |
363 | PKG_CHECK_MODULES([AVCODEC], [libavcodec], | 370 | PKG_CHECK_MODULES([AVCODEC], [libavcodec], |
364 | [], | 371 | [], |
365 | [ | 372 | [ |
366 | AC_MSG_WARN([disabling AV support $AVCODEC_PKG_ERRORS]) | 373 | AC_MSG_WARN([disabling phone $AVCODEC_PKG_ERRORS]) |
367 | BUILD_AV="no" | 374 | BUILD_PHONE="no" |
368 | ] | 375 | ] |
369 | ) | 376 | ) |
370 | fi | 377 | fi |
371 | 378 | ||
372 | if test "x$BUILD_AV" = "xyes"; then | 379 | if test "x$BUILD_PHONE" = "xyes"; then |
373 | PKG_CHECK_MODULES([AVUTIL], [libavutil], | 380 | PKG_CHECK_MODULES([AVUTIL], [libavutil], |
374 | [], | 381 | [], |
375 | [ | 382 | [ |
376 | AC_MSG_WARN([disabling AV support $AVUTIL_PKG_ERRORS]) | 383 | AC_MSG_WARN([disabling phone $AVUTIL_PKG_ERRORS]) |
377 | BUILD_AV="no" | 384 | BUILD_PHONE="no" |
378 | ] | 385 | ] |
379 | ) | 386 | ) |
380 | fi | 387 | fi |
381 | 388 | ||
382 | if test "x$BUILD_AV" = "xyes"; then | 389 | if test "x$BUILD_PHONE" = "xyes"; then |
383 | PKG_CHECK_MODULES([AVDEVICE], [libavdevice], | 390 | PKG_CHECK_MODULES([AVDEVICE], [libavdevice], |
384 | [], | 391 | [], |
385 | [ | 392 | [ |
386 | AC_MSG_WARN([disabling AV support $AVDEVICE_PKG_ERRORS]) | 393 | AC_MSG_WARN([disabling phone $AVDEVICE_PKG_ERRORS]) |
387 | BUILD_AV="no" | 394 | BUILD_PHONE="no" |
388 | ] | 395 | ] |
389 | ) | 396 | ) |
390 | fi | 397 | fi |
391 | 398 | ||
392 | if test "x$BUILD_AV" = "xyes"; then | 399 | if test "x$BUILD_PHONE" = "xyes"; then |
393 | PKG_CHECK_MODULES([SWSCALE], [libswscale], | 400 | PKG_CHECK_MODULES([SWSCALE], [libswscale], |
394 | [], | 401 | [], |
395 | [ | 402 | [ |
396 | AC_MSG_WARN([disabling AV support $SWSCALE_PKG_ERRORS]) | 403 | AC_MSG_WARN([disabling phone $SWSCALE_PKG_ERRORS]) |
397 | BUILD_AV="no" | 404 | BUILD_PHONE="no" |
398 | ] | 405 | ] |
399 | ) | 406 | ) |
400 | fi | 407 | fi |
401 | 408 | ||
402 | if test "x$BUILD_AV" = "xyes"; then | 409 | if test "x$BUILD_PHONE" = "xyes"; then |
403 | PKG_CHECK_MODULES([SDL], [sdl], | 410 | PKG_CHECK_MODULES([SDL], [sdl], |
404 | [], | 411 | [], |
405 | [ | 412 | [ |
406 | AC_MSG_WARN([disabling AV support $SDL_PKG_ERRORS]) | 413 | AC_MSG_WARN([disabling phone $SDL_PKG_ERRORS]) |
407 | BUILD_AV="no" | 414 | BUILD_PHONE="no" |
408 | ] | 415 | ] |
409 | ) | 416 | ) |
410 | fi | 417 | fi |
411 | 418 | ||
412 | if test "x$BUILD_AV" = "xyes"; then | 419 | if test "x$BUILD_PHONE" = "xyes"; then |
413 | PKG_CHECK_MODULES([OPENAL], [openal], | 420 | PKG_CHECK_MODULES([OPENAL], [openal], |
414 | [], | 421 | [], |
415 | [ | 422 | [ |
416 | AC_MSG_WARN([disabling AV support $OPENAL_PKG_ERRORS]) | 423 | AC_MSG_WARN([disabling phone $OPENAL_PKG_ERRORS]) |
417 | BUILD_AV="no" | 424 | BUILD_PHONE="no" |
418 | ] | 425 | ] |
419 | ) | 426 | ) |
420 | fi | 427 | fi |
@@ -425,6 +432,18 @@ if test "x$BUILD_AV" = "xyes"; then | |||
425 | [ | 432 | [ |
426 | AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS]) | 433 | AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS]) |
427 | BUILD_AV="no" | 434 | BUILD_AV="no" |
435 | BUILD_PHONE="no" | ||
436 | ] | ||
437 | ) | ||
438 | fi | ||
439 | |||
440 | if test "x$BUILD_AV" = "xyes"; then | ||
441 | PKG_CHECK_MODULES([VPX], [vpx], | ||
442 | [], | ||
443 | [ | ||
444 | AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS]) | ||
445 | BUILD_AV="no" | ||
446 | BUILD_PHONE="no" | ||
428 | ] | 447 | ] |
429 | ) | 448 | ) |
430 | fi | 449 | fi |
@@ -587,6 +606,7 @@ AM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test "x$BUILD_DHT_BOOTSTRAP_DAEMON" = | |||
587 | AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") | 606 | AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes") |
588 | AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes") | 607 | AM_CONDITIONAL(BUILD_NTOX, test "x$BUILD_NTOX" = "xyes") |
589 | AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") | 608 | AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") |
609 | AM_CONDITIONAL(BUILD_PHONE, test "x$BUILD_PHONE" = "xyes") | ||
590 | AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") | 610 | AM_CONDITIONAL(BUILD_TESTING, test "x$BUILD_TESTING" = "xyes") |
591 | AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") | 611 | AM_CONDITIONAL(WIN32, test "x$WIN32" = "xyes") |
592 | 612 | ||
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index 203d8a07..0472d361 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc | |||
@@ -1,105 +1,43 @@ | |||
1 | if BUILD_AV | 1 | if BUILD_AV |
2 | 2 | ||
3 | lib_LTLIBRARIES += libtoxrtp.la \ | 3 | lib_LTLIBRARIES += libtoxav.la |
4 | libtoxmsi.la \ | 4 | libtoxav_la_include_HEADERS = ../toxav/toxav.h |
5 | libtoxmedia.la | 5 | libtoxav_la_includedir = $(includedir)/tox |
6 | |||
7 | libtoxav_la_SOURCES = ../toxav/rtp.h \ | ||
8 | ../toxav/rtp.c \ | ||
9 | ../toxav/msi.h \ | ||
10 | ../toxav/msi.c \ | ||
11 | ../toxav/media.h \ | ||
12 | ../toxav/media.c \ | ||
13 | ../toxav/toxav.h \ | ||
14 | ../toxav/toxav.c | ||
15 | |||
16 | |||
17 | libtoxav_la_CFLAGS = -I../toxcore \ | ||
18 | -I../toxav \ | ||
19 | $(NACL_CFLAGS) \ | ||
20 | $(OPUS_CFLAGS) \ | ||
21 | $(VPX_CFLAGS) | ||
22 | |||
23 | libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \ | ||
24 | $(NACL_LDFLAGS) \ | ||
25 | $(EXTRA_LT_LDFLAGS) | ||
26 | |||
27 | libtoxav_la_LIBS = $(NACL_LIBS) \ | ||
28 | $(OPUS_LIBS) \ | ||
29 | $(VPX_LIBS) | ||
6 | 30 | ||
7 | |||
8 | # ****** RTP ****** # | ||
9 | |||
10 | libtoxrtp_la_include_HEADERS = \ | ||
11 | ../toxav/toxrtp.h | ||
12 | |||
13 | libtoxrtp_la_includedir = $(includedir)/tox | ||
14 | |||
15 | libtoxrtp_la_SOURCES = ../toxav/toxrtp.h \ | ||
16 | ../toxav/toxrtp.c | ||
17 | |||
18 | libtoxrtp_la_CFLAGS = -I../toxcore \ | ||
19 | -I../toxav \ | ||
20 | $(NACL_CFLAGS) | ||
21 | |||
22 | libtoxrtp_la_LDFLAGS = $(TOXRTP_LT_LDFLAGS) \ | ||
23 | $(NACL_LDFLAGS) \ | ||
24 | $(EXTRA_LT_LDFLAGS) | ||
25 | |||
26 | libtoxrtp_la_LIBS = libtoxcore.la \ | ||
27 | $(NACL_LIBS) | ||
28 | |||
29 | |||
30 | 31 | ||
32 | endif | ||
31 | 33 | ||
32 | 34 | ||
33 | # ****** MSI ****** # | ||
34 | |||
35 | libtoxmsi_la_include_HEADERS = \ | ||
36 | ../toxav/toxmsi.h | ||
37 | |||
38 | libtoxmsi_la_includedir = $(includedir)/tox | ||
39 | |||
40 | libtoxmsi_la_SOURCES = ../toxav/toxmsi.h \ | ||
41 | ../toxav/toxmsi.c | ||
42 | |||
43 | libtoxmsi_la_CFLAGS = -I../toxcore \ | ||
44 | -I../toxav \ | ||
45 | $(NACL_CFLAGS) | ||
46 | |||
47 | libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ | ||
48 | $(EXTRA_LT_LDFLAGS) \ | ||
49 | $(NACL_LDFLAGS) | ||
50 | |||
51 | libtoxmsi_la_LIBS = libtoxcore.la \ | ||
52 | $(NACL_LIBS) | ||
53 | |||
54 | 35 | ||
55 | 36 | ||
56 | 37 | ||
57 | 38 | ||
58 | # ****** MEDIA ****** # | 39 | if BUILD_PHONE |
59 | |||
60 | libtoxmedia_la_include_HEADERS = \ | ||
61 | ../toxav/toxmedia.h | ||
62 | |||
63 | libtoxmedia_la_includedir = $(includedir)/tox | ||
64 | |||
65 | libtoxmedia_la_SOURCES = ../toxav/toxmedia.h \ | ||
66 | ../toxav/toxmedia.c | ||
67 | 40 | ||
68 | libtoxmedia_la_CFLAGS = -I../toxcore \ | ||
69 | -I../toxav \ | ||
70 | $(AVFORMAT_CFLAGS) \ | ||
71 | $(AVCODEC_CFLAGS) \ | ||
72 | $(AVUTIL_CFLAGS) \ | ||
73 | $(AVDEVICE_CFLAGS) \ | ||
74 | $(SWSCALE_CFLAGS) \ | ||
75 | $(SDL_CFLAGS) \ | ||
76 | $(OPENAL_CFLAGS) \ | ||
77 | $(NACL_CFLAGS) \ | ||
78 | $(OPUS_CFLAGS) | ||
79 | |||
80 | |||
81 | libtoxmedia_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ | ||
82 | $(TOXRTP_LT_LDFLAGS) \ | ||
83 | $(EXTRA_LT_LDFLAGS) \ | ||
84 | $(NACL_LDFLAGS) | ||
85 | |||
86 | |||
87 | libtoxmedia_la_LIBS = libtoxcore.la \ | ||
88 | $(NACL_LDFLAGS) \ | ||
89 | $(AVFORMAT_LIBS) \ | ||
90 | $(AVCODEC_LIBS) \ | ||
91 | $(AVUTIL_LIBS) \ | ||
92 | $(AVDEVICE_LIBS) \ | ||
93 | $(SWSCALE_LIBS) \ | ||
94 | $(SDL_LIBS) \ | ||
95 | $(OPENAL_LIBS) \ | ||
96 | $(NACL_LIBS) \ | ||
97 | $(OPUS_LIBS) | ||
98 | |||
99 | |||
100 | |||
101 | |||
102 | # ***** PHONE ***** # | ||
103 | 41 | ||
104 | noinst_PROGRAMS += phone | 42 | noinst_PROGRAMS += phone |
105 | 43 | ||
@@ -113,25 +51,17 @@ phone_CFLAGS = -I../toxcore \ | |||
113 | $(AVDEVICE_CFLAGS) \ | 51 | $(AVDEVICE_CFLAGS) \ |
114 | $(SWSCALE_CFLAGS) \ | 52 | $(SWSCALE_CFLAGS) \ |
115 | $(SDL_CFLAGS) \ | 53 | $(SDL_CFLAGS) \ |
116 | $(OPENAL_CFLAGS) \ | 54 | $(OPENAL_CFLAGS) |
117 | $(NACL_CFLAGS) \ | ||
118 | $(OPUS_CFLAGS) | ||
119 | |||
120 | 55 | ||
121 | phone_LDADD = libtoxrtp.la \ | 56 | phone_LDADD = libtoxav.la \ |
122 | libtoxmsi.la \ | ||
123 | libtoxmedia.la \ | ||
124 | libtoxcore.la \ | 57 | libtoxcore.la \ |
125 | $(NACL_LDFLAGS) \ | ||
126 | $(AVFORMAT_LIBS) \ | 58 | $(AVFORMAT_LIBS) \ |
127 | $(AVCODEC_LIBS) \ | 59 | $(AVCODEC_LIBS) \ |
128 | $(AVUTIL_LIBS) \ | 60 | $(AVUTIL_LIBS) \ |
129 | $(AVDEVICE_LIBS) \ | 61 | $(AVDEVICE_LIBS) \ |
130 | $(SWSCALE_LIBS) \ | 62 | $(SWSCALE_LIBS) \ |
131 | $(SDL_LIBS) \ | 63 | $(SDL_LIBS) \ |
132 | $(OPENAL_LIBS) \ | 64 | $(OPENAL_LIBS) |
133 | $(NACL_LIBS) \ | ||
134 | $(OPUS_LIBS) | ||
135 | 65 | ||
136 | 66 | ||
137 | endif \ No newline at end of file | 67 | endif \ No newline at end of file |
diff --git a/toxav/media.c b/toxav/media.c index e18c1803..a327c751 100644 --- a/toxav/media.c +++ b/toxav/media.c | |||
@@ -28,13 +28,8 @@ | |||
28 | #endif /* HAVE_CONFIG_H */ | 28 | #endif /* HAVE_CONFIG_H */ |
29 | 29 | ||
30 | #include <stdio.h> | 30 | #include <stdio.h> |
31 | #include <stdlib.h> | ||
31 | #include <math.h> | 32 | #include <math.h> |
32 | #include <libavcodec/avcodec.h> | ||
33 | #include <libavformat/avformat.h> | ||
34 | #include <libswscale/swscale.h> | ||
35 | #include <libavdevice/avdevice.h> | ||
36 | #include <libavutil/opt.h> | ||
37 | #include <opus/opus.h> | ||
38 | #include <assert.h> | 33 | #include <assert.h> |
39 | 34 | ||
40 | #include "rtp.h" | 35 | #include "rtp.h" |
@@ -206,25 +201,11 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) | |||
206 | 201 | ||
207 | int init_video_decoder(CodecState *cs) | 202 | int init_video_decoder(CodecState *cs) |
208 | { | 203 | { |
209 | cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); | 204 | if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { |
210 | |||
211 | if (!cs->video_decoder) { | ||
212 | fprintf(stderr, "Init video_decoder failed!\n"); | 205 | fprintf(stderr, "Init video_decoder failed!\n"); |
213 | return -1; | 206 | return -1; |
214 | } | 207 | } |
215 | 208 | ||
216 | cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); | ||
217 | |||
218 | if (!cs->video_decoder_ctx) { | ||
219 | fprintf(stderr, "Init video_decoder_ctx failed!\n"); | ||
220 | return -1; | ||
221 | } | ||
222 | |||
223 | if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { | ||
224 | fprintf(stderr, "Opening video decoder failed!\n"); | ||
225 | return -1; | ||
226 | } | ||
227 | |||
228 | return 0; | 209 | return 0; |
229 | } | 210 | } |
230 | 211 | ||
@@ -242,97 +223,32 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels) | |||
242 | } | 223 | } |
243 | 224 | ||
244 | 225 | ||
245 | int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate) | 226 | int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) |
246 | { | 227 | { |
247 | cs->video_input_format = av_find_input_format(video_driver); | 228 | vpx_codec_enc_cfg_t cfg; |
248 | 229 | int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | |
249 | if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) { | 230 | if(res) { |
250 | fprintf(stderr, "Opening video_input_format failed!\n"); | 231 | printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); |
251 | return -1; | ||
252 | } | ||
253 | |||
254 | avformat_find_stream_info(cs->video_format_ctx, NULL); | ||
255 | av_dump_format(cs->video_format_ctx, 0, webcam, 0); | ||
256 | |||
257 | int i; | ||
258 | |||
259 | for (i = 0; i < cs->video_format_ctx->nb_streams; ++i) { | ||
260 | if (cs->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
261 | cs->video_stream = i; | ||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | cs->webcam_decoder_ctx = cs->video_format_ctx->streams[cs->video_stream]->codec; | ||
267 | cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id); | ||
268 | |||
269 | if (cs->webcam_decoder == NULL) { | ||
270 | fprintf(stderr, "Unsupported codec!\n"); | ||
271 | return -1; | ||
272 | } | ||
273 | |||
274 | if (cs->webcam_decoder_ctx == NULL) { | ||
275 | fprintf(stderr, "Init webcam_decoder_ctx failed!\n"); | ||
276 | return -1; | ||
277 | } | ||
278 | |||
279 | if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) { | ||
280 | fprintf(stderr, "Opening webcam decoder failed!\n"); | ||
281 | return -1; | 232 | return -1; |
282 | } | 233 | } |
283 | 234 | ||
284 | cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); | 235 | cfg.rc_target_bitrate = video_bitrate; |
285 | 236 | cfg.g_w = width; | |
286 | if (!cs->video_encoder) { | 237 | cfg.g_h = height; |
287 | fprintf(stderr, "Init video_encoder failed!\n"); | 238 | if(vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { |
288 | return -1; | 239 | fprintf(stderr, "Failed to initialize encoder\n"); |
289 | } | ||
290 | |||
291 | cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); | ||
292 | |||
293 | if (!cs->video_encoder_ctx) { | ||
294 | fprintf(stderr, "Init video_encoder_ctx failed!\n"); | ||
295 | return -1; | ||
296 | } | ||
297 | |||
298 | cs->video_encoder_ctx->bit_rate = video_bitrate; | ||
299 | cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; | ||
300 | av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); | ||
301 | av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); | ||
302 | |||
303 | cs->video_encoder_ctx->thread_count = 4; | ||
304 | cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; | ||
305 | cs->video_encoder_ctx->rc_buffer_size = video_bitrate * 6; | ||
306 | cs->video_encoder_ctx->profile = 3; | ||
307 | cs->video_encoder_ctx->qmax = 54; | ||
308 | cs->video_encoder_ctx->qmin = 4; | ||
309 | AVRational myrational = {1, 25}; | ||
310 | cs->video_encoder_ctx->time_base = myrational; | ||
311 | cs->video_encoder_ctx->gop_size = 99999; | ||
312 | cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; | ||
313 | cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; | ||
314 | cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; | ||
315 | |||
316 | if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { | ||
317 | fprintf(stderr, "Opening video encoder failed!\n"); | ||
318 | return -1; | 240 | return -1; |
319 | } | 241 | } |
320 | |||
321 | return 0; | 242 | return 0; |
322 | } | 243 | } |
323 | 244 | ||
324 | int init_audio_encoder(CodecState *cs) | 245 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) |
325 | { | 246 | { |
326 | int err = OPUS_OK; | 247 | int err = OPUS_OK; |
327 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err); | 248 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); |
328 | |||
329 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | 249 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); |
330 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); | 250 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); |
331 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); | 251 | |
332 | |||
333 | /* NOTE: What do we do with this? */ | ||
334 | int nfo; | ||
335 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo)); | ||
336 | 252 | ||
337 | return err == OPUS_OK ? 0 : -1; | 253 | return err == OPUS_OK ? 0 : -1; |
338 | } | 254 | } |
@@ -342,30 +258,26 @@ CodecState* codec_init_session ( uint32_t audio_bitrate, | |||
342 | uint16_t audio_frame_duration, | 258 | uint16_t audio_frame_duration, |
343 | uint32_t audio_sample_rate, | 259 | uint32_t audio_sample_rate, |
344 | uint32_t audio_channels, | 260 | uint32_t audio_channels, |
345 | uint32_t video_bitrate, | 261 | uint16_t video_width, |
346 | const char* webcam, | 262 | uint16_t video_height, |
347 | const char* webcam_driver ) | 263 | uint32_t video_bitrate ) |
348 | { | 264 | { |
349 | CodecState* _retu = av_calloc(sizeof(CodecState), 1); | 265 | CodecState* _retu = calloc(sizeof(CodecState), 1); |
350 | assert(_retu); | 266 | assert(_retu); |
351 | 267 | ||
352 | |||
353 | avdevice_register_all(); | ||
354 | avcodec_register_all(); | ||
355 | av_register_all(); | ||
356 | |||
357 | |||
358 | _retu->audio_bitrate = audio_bitrate; | 268 | _retu->audio_bitrate = audio_bitrate; |
359 | _retu->audio_sample_rate = audio_sample_rate; | 269 | _retu->audio_sample_rate = audio_sample_rate; |
360 | 270 | ||
361 | pthread_mutex_init(&_retu->ctrl_mutex, NULL); | ||
362 | |||
363 | |||
364 | /* Encoders */ | 271 | /* Encoders */ |
365 | if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) ) | 272 | if (!video_width || !video_height) { |
273 | video_width = 320; | ||
274 | video_height = 240; | ||
275 | } | ||
276 | |||
277 | if ( 0 == init_video_encoder(_retu, video_width, video_height, video_bitrate) ) | ||
366 | printf("Video encoder initialized!\n"); | 278 | printf("Video encoder initialized!\n"); |
367 | 279 | ||
368 | if ( 0 == init_audio_encoder(_retu) ) | 280 | if ( 0 == init_audio_encoder(_retu, audio_channels) ) |
369 | printf("Audio encoder initialized!\n"); | 281 | printf("Audio encoder initialized!\n"); |
370 | 282 | ||
371 | 283 | ||
@@ -391,7 +303,8 @@ void codec_terminate_session ( CodecState* cs ) | |||
391 | opus_decoder_destroy(cs->audio_decoder); | 303 | opus_decoder_destroy(cs->audio_decoder); |
392 | printf("Terminated decoder!\n"); | 304 | printf("Terminated decoder!\n"); |
393 | } | 305 | } |
394 | 306 | ||
395 | /* TODO: Terminate video */ | 307 | /* TODO: Terminate video */ |
396 | 308 | vpx_codec_destroy(&cs->v_decoder); | |
309 | vpx_codec_destroy(&cs->v_encoder); | ||
397 | } | 310 | } |
diff --git a/toxav/media.h b/toxav/media.h index ef2de27c..4230de8f 100644 --- a/toxav/media.h +++ b/toxav/media.h | |||
@@ -27,66 +27,27 @@ | |||
27 | 27 | ||
28 | #include <stdio.h> | 28 | #include <stdio.h> |
29 | #include <math.h> | 29 | #include <math.h> |
30 | #include "../toxcore/tox.h" | 30 | #include <pthread.h> |
31 | 31 | ||
32 | /* Video encoding/decoding */ | 32 | #include <vpx/vpx_decoder.h> |
33 | #include <libavcodec/avcodec.h> | 33 | #include <vpx/vpx_encoder.h> |
34 | #include <libavformat/avformat.h> | 34 | #include <vpx/vp8dx.h> |
35 | #include <libswscale/swscale.h> | 35 | #include <vpx/vp8cx.h> |
36 | #include <libavdevice/avdevice.h> | 36 | #define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) |
37 | #include <libavutil/opt.h> | 37 | #define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) |
38 | 38 | ||
39 | /* Audio encoding/decoding */ | 39 | /* Audio encoding/decoding */ |
40 | #include <opus/opus.h> | 40 | #include <opus/opus.h> |
41 | 41 | ||
42 | /* ffmpeg VP8 codec ID */ | ||
43 | #define VIDEO_CODEC AV_CODEC_ID_VP8 | ||
44 | |||
45 | /* ffmpeg Opus codec ID */ | ||
46 | #define AUDIO_CODEC AV_CODEC_ID_OPUS | ||
47 | |||
48 | /* default video bitrate in bytes/s */ | ||
49 | #define VIDEO_BITRATE 10*1000 | ||
50 | |||
51 | /* default audio bitrate in bytes/s */ | ||
52 | #define AUDIO_BITRATE 64000 | ||
53 | |||
54 | /* audio frame duration in miliseconds */ | ||
55 | #define AUDIO_FRAME_DURATION 20 | ||
56 | |||
57 | /* audio sample rate recommended to be 48kHz for Opus */ | ||
58 | #define AUDIO_SAMPLE_RATE 48000 | ||
59 | |||
60 | /* the amount of samples in one audio frame */ | ||
61 | #define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000 | ||
62 | |||
63 | /* the quit event for SDL */ | ||
64 | #define FF_QUIT_EVENT (SDL_USEREVENT + 2) | ||
65 | |||
66 | #ifdef __linux__ | ||
67 | #define VIDEO_DRIVER "video4linux2" | ||
68 | #define DEFAULT_WEBCAM "/dev/video0" | ||
69 | #endif | ||
70 | |||
71 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
72 | #define VIDEO_DRIVER "vfwcap" | ||
73 | #define DEFAULT_WEBCAM "0" | ||
74 | #endif | ||
75 | 42 | ||
76 | typedef struct _CodecState{ | 43 | typedef struct _CodecState{ |
77 | 44 | ||
78 | /* video encoding */ | 45 | /* video encoding */ |
79 | AVInputFormat *video_input_format; | 46 | vpx_codec_ctx_t v_encoder; |
80 | AVFormatContext *video_format_ctx; | 47 | uint32_t frame_counter; |
81 | uint8_t video_stream; | ||
82 | AVCodecContext *webcam_decoder_ctx; | ||
83 | AVCodec *webcam_decoder; | ||
84 | AVCodecContext *video_encoder_ctx; | ||
85 | AVCodec *video_encoder; | ||
86 | 48 | ||
87 | /* video decoding */ | 49 | /* video decoding */ |
88 | AVCodecContext *video_decoder_ctx; | 50 | vpx_codec_ctx_t v_decoder; |
89 | AVCodec *video_decoder; | ||
90 | 51 | ||
91 | /* audio encoding */ | 52 | /* audio encoding */ |
92 | OpusEncoder *audio_encoder; | 53 | OpusEncoder *audio_encoder; |
@@ -95,11 +56,6 @@ typedef struct _CodecState{ | |||
95 | 56 | ||
96 | /* audio decoding */ | 57 | /* audio decoding */ |
97 | OpusDecoder *audio_decoder; | 58 | OpusDecoder *audio_decoder; |
98 | |||
99 | pthread_mutex_t ctrl_mutex; | ||
100 | |||
101 | |||
102 | uint32_t frame_rate; | ||
103 | 59 | ||
104 | } CodecState; | 60 | } CodecState; |
105 | 61 | ||
@@ -112,13 +68,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk); | |||
112 | RTPMessage *dequeue(struct jitter_buffer *q, int *success); | 68 | RTPMessage *dequeue(struct jitter_buffer *q, int *success); |
113 | 69 | ||
114 | 70 | ||
115 | CodecState* codec_init_session( uint32_t audio_bitrate, | 71 | CodecState* codec_init_session ( uint32_t audio_bitrate, |
116 | uint16_t audio_frame_duration, | 72 | uint16_t audio_frame_duration, |
117 | uint32_t audio_sample_rate, | 73 | uint32_t audio_sample_rate, |
118 | uint32_t audio_channels, | 74 | uint32_t audio_channels, |
119 | uint32_t video_bitrate, | 75 | uint16_t video_width, |
120 | const char* webcam, | 76 | uint16_t video_height, |
121 | const char* webcam_driver ); | 77 | uint32_t video_bitrate ); |
122 | 78 | ||
123 | void codec_terminate_session(CodecState* cs); | 79 | void codec_terminate_session(CodecState* cs); |
124 | 80 | ||
diff --git a/toxav/msi.c b/toxav/msi.c index 014a904f..f00029ba 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -593,7 +593,7 @@ int send_message ( MSISession* session, MSIMessage* msg, uint32_t to ) | |||
593 | uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; | 593 | uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; |
594 | uint16_t _length = message_to_string ( msg, _msg_string_final ); | 594 | uint16_t _length = message_to_string ( msg, _msg_string_final ); |
595 | 595 | ||
596 | return m_msi_packet((struct Messenger*) session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; | 596 | return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; |
597 | } | 597 | } |
598 | 598 | ||
599 | 599 | ||
@@ -616,7 +616,27 @@ void flush_peer_type ( MSISession* session, MSIMessage* msg, int peer_id ) { | |||
616 | } else {} /* Error */ | 616 | } else {} /* Error */ |
617 | } | 617 | } |
618 | 618 | ||
619 | 619 | void handle_remote_connection_change(Messenger* messenger, int friend_num, uint8_t status, void* session_p) | |
620 | { | ||
621 | MSISession* session = session_p; | ||
622 | |||
623 | switch ( status ) | ||
624 | { | ||
625 | case 0: /* Went offline */ | ||
626 | { | ||
627 | if ( session->call ) { | ||
628 | int i = 0; | ||
629 | for ( ; i < session->call->peer_count; i ++ ) | ||
630 | if ( session->call->peers[i] == friend_num ) { | ||
631 | msi_stopcall(session); /* Stop the call for now */ | ||
632 | return; | ||
633 | } | ||
634 | } | ||
635 | } break; | ||
636 | |||
637 | default: break; | ||
638 | } | ||
639 | } | ||
620 | 640 | ||
621 | /** | 641 | /** |
622 | * @brief Sends error response to peer. | 642 | * @brief Sends error response to peer. |
@@ -694,8 +714,8 @@ void* handle_timeout ( void* arg ) | |||
694 | 714 | ||
695 | } | 715 | } |
696 | 716 | ||
697 | ( *callbacks[MSI_OnTimeout] ) ( _session->agent_handler ); | 717 | ( *callbacks[MSI_OnRequestTimeout] ) ( _session->agent_handler ); |
698 | ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler ); | 718 | ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler ); |
699 | 719 | ||
700 | return NULL; | 720 | return NULL; |
701 | } | 721 | } |
@@ -774,7 +794,7 @@ int terminate_call ( MSISession* session ) { | |||
774 | 794 | ||
775 | 795 | ||
776 | /* Check event loop and cancel timed events if there are any | 796 | /* Check event loop and cancel timed events if there are any |
777 | * Notice: This has to be done before possibly | 797 | * NOTE: This has to be done before possibly |
778 | * locking the mutex the second time | 798 | * locking the mutex the second time |
779 | */ | 799 | */ |
780 | event.timer_release ( session->call->request_timer_id ); | 800 | event.timer_release ( session->call->request_timer_id ); |
@@ -797,7 +817,7 @@ int terminate_call ( MSISession* session ) { | |||
797 | pthread_mutex_destroy ( &_call->mutex ); | 817 | pthread_mutex_destroy ( &_call->mutex ); |
798 | 818 | ||
799 | free ( _call ); | 819 | free ( _call ); |
800 | 820 | ||
801 | return 0; | 821 | return 0; |
802 | } | 822 | } |
803 | 823 | ||
@@ -1136,7 +1156,7 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id ) | |||
1136 | * @return MSISession* The created session. | 1156 | * @return MSISession* The created session. |
1137 | * @retval NULL Error occured. | 1157 | * @retval NULL Error occured. |
1138 | */ | 1158 | */ |
1139 | MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) { | 1159 | MSISession* msi_init_session ( Messenger* messenger, const uint8_t* ua_name ) { |
1140 | assert ( messenger ); | 1160 | assert ( messenger ); |
1141 | 1161 | ||
1142 | MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); | 1162 | MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); |
@@ -1152,8 +1172,10 @@ MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) { | |||
1152 | _retu->call_timeout = 30000; /* default value? */ | 1172 | _retu->call_timeout = 30000; /* default value? */ |
1153 | 1173 | ||
1154 | 1174 | ||
1155 | m_callback_msi_packet((struct Messenger*) messenger, msi_handle_packet, _retu ); | 1175 | m_callback_msi_packet(messenger, msi_handle_packet, _retu ); |
1156 | 1176 | ||
1177 | /* This is called when remote terminates session */ | ||
1178 | m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); | ||
1157 | 1179 | ||
1158 | return _retu; | 1180 | return _retu; |
1159 | } | 1181 | } |
@@ -1351,7 +1373,7 @@ int msi_stopcall ( MSISession* session ) { | |||
1351 | return -1; | 1373 | return -1; |
1352 | 1374 | ||
1353 | /* just terminate it */ | 1375 | /* just terminate it */ |
1354 | 1376 | ||
1355 | terminate_call ( session ); | 1377 | terminate_call ( session ); |
1356 | 1378 | ||
1357 | return 0; | 1379 | return 0; |
diff --git a/toxav/msi.h b/toxav/msi.h index 20d6671d..4487dae6 100644 --- a/toxav/msi.h +++ b/toxav/msi.h | |||
@@ -26,9 +26,10 @@ | |||
26 | #define __TOXMSI | 26 | #define __TOXMSI |
27 | 27 | ||
28 | #include <inttypes.h> | 28 | #include <inttypes.h> |
29 | #include "../toxcore/tox.h" | ||
30 | #include <pthread.h> | 29 | #include <pthread.h> |
31 | 30 | ||
31 | #include "../toxcore/Messenger.h" | ||
32 | |||
32 | /* define size for call_id */ | 33 | /* define size for call_id */ |
33 | #define CALL_ID_LEN 12 | 34 | #define CALL_ID_LEN 12 |
34 | 35 | ||
@@ -106,7 +107,7 @@ typedef struct _MSISession { | |||
106 | const uint8_t* ua_name; | 107 | const uint8_t* ua_name; |
107 | 108 | ||
108 | void* agent_handler; /* Pointer to an object that is handling msi */ | 109 | void* agent_handler; /* Pointer to an object that is handling msi */ |
109 | Tox* messenger_handle; | 110 | Messenger* messenger_handle; |
110 | 111 | ||
111 | uint32_t frequ; | 112 | uint32_t frequ; |
112 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ | 113 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ |
@@ -133,7 +134,7 @@ typedef enum { | |||
133 | 134 | ||
134 | /* Protocol */ | 135 | /* Protocol */ |
135 | MSI_OnError, | 136 | MSI_OnError, |
136 | MSI_OnTimeout | 137 | MSI_OnRequestTimeout |
137 | 138 | ||
138 | } MSICallbackID; | 139 | } MSICallbackID; |
139 | 140 | ||
@@ -156,7 +157,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id); | |||
156 | * @return MSISession* The created session. | 157 | * @return MSISession* The created session. |
157 | * @retval NULL Error occured. | 158 | * @retval NULL Error occured. |
158 | */ | 159 | */ |
159 | MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ); | 160 | MSISession* msi_init_session ( Messenger* messenger, const uint8_t* ua_name ); |
160 | 161 | ||
161 | 162 | ||
162 | /** | 163 | /** |
diff --git a/toxav/phone.c b/toxav/phone.c index 4f078e2b..7806727d 100755 --- a/toxav/phone.c +++ b/toxav/phone.c | |||
@@ -44,18 +44,41 @@ | |||
44 | #include <unistd.h> | 44 | #include <unistd.h> |
45 | #include <assert.h> | 45 | #include <assert.h> |
46 | #include <math.h> | 46 | #include <math.h> |
47 | #include <AL/al.h> | ||
48 | #include <AL/alc.h> | ||
49 | #include <SDL/SDL.h> | ||
50 | #include <SDL/SDL_thread.h> | ||
51 | #include <pthread.h> | 47 | #include <pthread.h> |
52 | #include <opus/opus.h> | ||
53 | 48 | ||
54 | #include "media.h" | 49 | //#include "media.h" |
55 | #include "toxav.h" | 50 | #include "toxav.h" |
56 | #include "../toxcore/event.h" | 51 | #include "../toxcore/event.h" |
57 | #include "../toxcore/tox.h" | 52 | #include "../toxcore/tox.h" |
58 | 53 | ||
54 | #ifdef TOX_FFMPEG | ||
55 | /* Video encoding/decoding */ | ||
56 | #include <libavcodec/avcodec.h> | ||
57 | #include <libavformat/avformat.h> | ||
58 | #include <libswscale/swscale.h> | ||
59 | #include <libavdevice/avdevice.h> | ||
60 | #include <libavutil/opt.h> | ||
61 | #endif | ||
62 | |||
63 | #include <AL/al.h> | ||
64 | #include <AL/alc.h> | ||
65 | #include <SDL/SDL.h> | ||
66 | #include <SDL/SDL_thread.h> | ||
67 | |||
68 | /* the quit event for SDL */ | ||
69 | #define FF_QUIT_EVENT (SDL_USEREVENT + 2) | ||
70 | |||
71 | #ifdef __linux__ | ||
72 | #define VIDEO_DRIVER "video4linux2" | ||
73 | #define DEFAULT_WEBCAM "/dev/video0" | ||
74 | #endif | ||
75 | |||
76 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
77 | #define VIDEO_DRIVER "vfwcap" | ||
78 | #define DEFAULT_WEBCAM "0" | ||
79 | #endif | ||
80 | |||
81 | |||
59 | /* Define client version */ | 82 | /* Define client version */ |
60 | #define _USERAGENT "v.0.3.0" | 83 | #define _USERAGENT "v.0.3.0" |
61 | 84 | ||
@@ -96,6 +119,13 @@ typedef struct av_session_s { | |||
96 | av_friend_t* _friends; | 119 | av_friend_t* _friends; |
97 | int _friend_cout; | 120 | int _friend_cout; |
98 | char _my_public_id[200]; | 121 | char _my_public_id[200]; |
122 | #ifdef TOX_FFMPEG | ||
123 | AVInputFormat *video_input_format; | ||
124 | AVFormatContext *video_format_ctx; | ||
125 | uint8_t video_stream; | ||
126 | AVCodecContext *webcam_decoder_ctx; | ||
127 | AVCodec *webcam_decoder; | ||
128 | #endif | ||
99 | } av_session_t; | 129 | } av_session_t; |
100 | 130 | ||
101 | 131 | ||
@@ -236,8 +266,8 @@ static void fraddr_to_str(uint8_t *id_bin, char *id_str) | |||
236 | /* | 266 | /* |
237 | * How av stuff _should_ look like | 267 | * How av stuff _should_ look like |
238 | */ | 268 | */ |
239 | 269 | /* | |
240 | int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | 270 | int display_received_frame(av_session_t* _phone, vpx_image_t *image) |
241 | { | 271 | { |
242 | CodecState* cs = get_cs_temp(_phone->av); | 272 | CodecState* cs = get_cs_temp(_phone->av); |
243 | AVPicture pict; | 273 | AVPicture pict; |
@@ -249,8 +279,8 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | |||
249 | pict.linesize[0] = _phone->video_picture.bmp->pitches[0]; | 279 | pict.linesize[0] = _phone->video_picture.bmp->pitches[0]; |
250 | pict.linesize[1] = _phone->video_picture.bmp->pitches[2]; | 280 | pict.linesize[1] = _phone->video_picture.bmp->pitches[2]; |
251 | pict.linesize[2] = _phone->video_picture.bmp->pitches[1]; | 281 | pict.linesize[2] = _phone->video_picture.bmp->pitches[1]; |
252 | 282 | */ | |
253 | /* Convert the image into YUV format that SDL uses */ | 283 | /* Convert the image into YUV format that SDL uses *//* |
254 | sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, | 284 | sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, |
255 | cs->video_decoder_ctx->height, pict.data, pict.linesize ); | 285 | cs->video_decoder_ctx->height, pict.data, pict.linesize ); |
256 | 286 | ||
@@ -263,60 +293,65 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | |||
263 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); | 293 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect); |
264 | return 1; | 294 | return 1; |
265 | } | 295 | } |
266 | 296 | */ | |
297 | #ifdef TOX_FFMPEG | ||
267 | void *encode_video_thread(void *arg) | 298 | void *encode_video_thread(void *arg) |
268 | { | 299 | { |
269 | INFO("Started encode video thread!"); | 300 | INFO("Started encode video thread!"); |
270 | 301 | ||
271 | av_session_t* _phone = arg; | 302 | av_session_t* _phone = arg; |
272 | 303 | ||
273 | _phone->running_encvid = 1; | 304 | _phone->running_encvid = 1; |
274 | 305 | //CodecState *cs = get_cs_temp(_phone->av); | |
275 | CodecState *cs = get_cs_temp(_phone->av); | ||
276 | AVPacket pkt1, *packet = &pkt1; | 306 | AVPacket pkt1, *packet = &pkt1; |
277 | int p = 0; | 307 | //int p = 0; |
278 | int got_packet; | 308 | //int got_packet; |
279 | int video_frame_finished; | 309 | int video_frame_finished; |
280 | AVFrame *s_video_frame; | 310 | AVFrame *s_video_frame; |
281 | AVFrame *webcam_frame; | 311 | AVFrame *webcam_frame; |
282 | s_video_frame = avcodec_alloc_frame(); | 312 | s_video_frame = avcodec_alloc_frame(); |
283 | webcam_frame = avcodec_alloc_frame(); | 313 | webcam_frame = avcodec_alloc_frame(); |
284 | AVPacket enc_video_packet; | 314 | //AVPacket enc_video_packet; |
285 | 315 | ||
286 | uint8_t *buffer; | 316 | uint8_t *buffer; |
287 | int numBytes; | 317 | int numBytes; |
288 | /* Determine required buffer size and allocate buffer */ | 318 | /* Determine required buffer size and allocate buffer */ |
289 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height); | 319 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height); |
290 | buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); | 320 | buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); |
291 | avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, | 321 | avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, |
292 | cs->webcam_decoder_ctx->height); | 322 | _phone->webcam_decoder_ctx->height); |
293 | _phone->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, | 323 | _phone->sws_ctx = sws_getContext(_phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, |
294 | cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, | 324 | _phone->webcam_decoder_ctx->pix_fmt, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, PIX_FMT_YUV420P, |
295 | SWS_BILINEAR, NULL, NULL, NULL); | 325 | SWS_BILINEAR, NULL, NULL, NULL); |
296 | 326 | ||
327 | |||
328 | vpx_image_t *image = | ||
329 | vpx_img_alloc(NULL, VPX_IMG_FMT_I420, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, 1); | ||
330 | |||
331 | //uint32_t frame_counter = 0; | ||
297 | while (_phone->running_encvid) { | 332 | while (_phone->running_encvid) { |
298 | 333 | ||
299 | if (av_read_frame(cs->video_format_ctx, packet) < 0) { | 334 | if (av_read_frame(_phone->video_format_ctx, packet) < 0) { |
300 | printf("error reading frame\n"); | 335 | printf("error reading frame\n"); |
301 | 336 | ||
302 | if (cs->video_format_ctx->pb->error != 0) | 337 | if (_phone->video_format_ctx->pb->error != 0) |
303 | break; | 338 | break; |
304 | 339 | ||
305 | continue; | 340 | continue; |
306 | } | 341 | } |
307 | 342 | ||
308 | if (packet->stream_index == cs->video_stream) { | 343 | if (packet->stream_index == _phone->video_stream) { |
309 | if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { | 344 | if (avcodec_decode_video2(_phone->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { |
310 | printf("couldn't decode\n"); | 345 | printf("couldn't decode\n"); |
311 | continue; | 346 | continue; |
312 | } | 347 | } |
313 | 348 | ||
314 | av_free_packet(packet); | 349 | av_free_packet(packet); |
315 | sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, | 350 | sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, |
316 | cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); | 351 | _phone->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); |
317 | /* create a new I-frame every 60 frames */ | 352 | /* create a new I-frame every 60 frames */ |
318 | ++p; | 353 | //++p; |
319 | 354 | /* | |
320 | if (p == 60) { | 355 | if (p == 60) { |
321 | 356 | ||
322 | s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; | 357 | s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; |
@@ -325,53 +360,66 @@ void *encode_video_thread(void *arg) | |||
325 | p = 0; | 360 | p = 0; |
326 | } else { | 361 | } else { |
327 | s_video_frame->pict_type = AV_PICTURE_TYPE_P ; | 362 | s_video_frame->pict_type = AV_PICTURE_TYPE_P ; |
328 | } | 363 | }*/ |
329 | 364 | ||
330 | if (video_frame_finished) { | 365 | if (video_frame_finished) { |
331 | 366 | memcpy(image->planes[VPX_PLANE_Y], s_video_frame->data[0], s_video_frame->linesize[0] * _phone->webcam_decoder_ctx->height); | |
332 | if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { | 367 | memcpy(image->planes[VPX_PLANE_U], s_video_frame->data[1], s_video_frame->linesize[1] * _phone->webcam_decoder_ctx->height / 2); |
368 | memcpy(image->planes[VPX_PLANE_V], s_video_frame->data[2], s_video_frame->linesize[2] * _phone->webcam_decoder_ctx->height / 2); | ||
369 | toxav_send_video (_phone->av, image); | ||
370 | //if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) { | ||
371 | /*if (vpx_codec_encode(&cs->v_encoder, image, frame_counter, 1, 0, 0) != VPX_CODEC_OK) { | ||
333 | printf("could not encode video frame\n"); | 372 | printf("could not encode video frame\n"); |
334 | continue; | 373 | continue; |
335 | } | 374 | } |
375 | ++frame_counter; | ||
336 | 376 | ||
337 | if (!got_packet) { | 377 | vpx_codec_iter_t iter = NULL; |
338 | continue; | 378 | vpx_codec_cx_pkt_t *pkt; |
339 | } | 379 | while( (pkt = vpx_codec_get_cx_data(&cs->v_encoder, &iter)) ) { |
380 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) | ||
381 | toxav_send_rtp_payload(_phone->av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz); | ||
382 | }*/ | ||
383 | //if (!got_packet) { | ||
384 | // continue; | ||
385 | //} | ||
340 | 386 | ||
341 | if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); | 387 | //if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); |
342 | 388 | ||
343 | toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); | 389 | //toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size); |
344 | 390 | ||
345 | av_free_packet(&enc_video_packet); | 391 | //av_free_packet(&enc_video_packet); |
346 | } | 392 | } |
347 | } else { | 393 | } else { |
348 | av_free_packet(packet); | 394 | av_free_packet(packet); |
349 | } | 395 | } |
350 | } | 396 | } |
351 | 397 | ||
398 | vpx_img_free(image); | ||
399 | |||
352 | /* clean up codecs */ | 400 | /* clean up codecs */ |
353 | pthread_mutex_lock(&cs->ctrl_mutex); | 401 | //pthread_mutex_lock(&cs->ctrl_mutex); |
354 | av_free(buffer); | 402 | av_free(buffer); |
355 | av_free(webcam_frame); | 403 | av_free(webcam_frame); |
356 | av_free(s_video_frame); | 404 | av_free(s_video_frame); |
357 | sws_freeContext(_phone->sws_ctx); | 405 | sws_freeContext(_phone->sws_ctx); |
358 | avcodec_close(cs->webcam_decoder_ctx); | 406 | //avcodec_close(webcam_decoder_ctx); |
359 | avcodec_close(cs->video_encoder_ctx); | 407 | //avcodec_close(cs->video_encoder_ctx); |
360 | pthread_mutex_unlock(&cs->ctrl_mutex); | 408 | //pthread_mutex_unlock(&cs->ctrl_mutex); |
361 | 409 | ||
362 | _phone->running_encvid = -1; | 410 | _phone->running_encvid = -1; |
363 | 411 | ||
364 | pthread_exit ( NULL ); | 412 | pthread_exit ( NULL ); |
365 | } | 413 | } |
414 | #endif | ||
366 | 415 | ||
367 | void *encode_audio_thread(void *arg) | 416 | void *encode_audio_thread(void *arg) |
368 | { | 417 | { |
369 | INFO("Started encode audio thread!"); | 418 | INFO("Started encode audio thread!"); |
370 | av_session_t* _phone = arg; | 419 | av_session_t* _phone = arg; |
371 | _phone->running_encaud = 1; | 420 | _phone->running_encaud = 1; |
372 | 421 | ||
373 | unsigned char encoded_data[4096]; | 422 | int ret = 0; |
374 | int encoded_size = 0; | ||
375 | int16_t frame[4096]; | 423 | int16_t frame[4096]; |
376 | int frame_size = AUDIO_FRAME_SIZE; | 424 | int frame_size = AUDIO_FRAME_SIZE; |
377 | ALint sample = 0; | 425 | ALint sample = 0; |
@@ -383,94 +431,164 @@ void *encode_audio_thread(void *arg) | |||
383 | if (sample >= frame_size) { | 431 | if (sample >= frame_size) { |
384 | alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size); | 432 | alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size); |
385 | 433 | ||
386 | encoded_size = toxav_encode_audio(_phone->av, frame, frame_size, encoded_data); | 434 | ret = toxav_send_audio(_phone->av, frame, frame_size); |
387 | 435 | ||
388 | if (encoded_size <= 0) { | 436 | if (ret < 0) |
389 | printf("Could not encode audio packet\n"); | 437 | printf("Could not encode or send audio packet\n"); |
390 | } else { | 438 | |
391 | if ( -1 == toxav_send_rtp_payload(_phone->av, TypeAudio, encoded_data, encoded_size) ) | ||
392 | assert(0); | ||
393 | } | ||
394 | } else { | 439 | } else { |
395 | usleep(1000); | 440 | usleep(1000); |
396 | } | 441 | } |
397 | } | 442 | } |
398 | 443 | ||
399 | /* clean up codecs * | 444 | /* clean up codecs * |
400 | pthread_mutex_lock(&cs->ctrl_mutex);*/ | 445 | pthread_mutex_lock(&cs->ctrl_mutex);* / |
401 | alcCaptureStop((ALCdevice*)_phone->audio_capture_device); | 446 | alcCaptureStop((ALCdevice*)_phone->audio_capture_device); |
402 | alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); | 447 | alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); |
403 | /*pthread_mutex_unlock(&cs->ctrl_mutex);*/ | 448 | / *pthread_mutex_unlock(&cs->ctrl_mutex);*/ |
404 | _phone->running_encaud = -1; | 449 | _phone->running_encaud = -1; |
405 | pthread_exit ( NULL ); | 450 | pthread_exit ( NULL ); |
406 | } | 451 | } |
407 | 452 | ||
453 | void convert_to_rgb(vpx_image_t *img, unsigned char *out) | ||
454 | { | ||
455 | const int w = img->d_w; | ||
456 | const int w2 = w/2; | ||
457 | const int pstride = w*3; | ||
458 | const int h = img->d_h; | ||
459 | const int h2 = h/2; | ||
460 | |||
461 | const int strideY = img->stride[0]; | ||
462 | const int strideU = img->stride[1]; | ||
463 | const int strideV = img->stride[2]; | ||
464 | int posy, posx; | ||
465 | for (posy = 0; posy < h2; posy++) { | ||
466 | unsigned char *dst = out + pstride * (posy * 2); | ||
467 | unsigned char *dst2 = out + pstride * (posy * 2 + 1); | ||
468 | const unsigned char *srcY = img->planes[0] + strideY * posy * 2; | ||
469 | const unsigned char *srcY2 = img->planes[0] + strideY * (posy * 2 + 1); | ||
470 | const unsigned char *srcU = img->planes[1] + strideU * posy; | ||
471 | const unsigned char *srcV = img->planes[2] + strideV * posy; | ||
472 | |||
473 | for (posx = 0; posx < w2; posx++) { | ||
474 | unsigned char Y,U,V; | ||
475 | short R,G,B; | ||
476 | short iR,iG,iB; | ||
477 | |||
478 | U = *(srcU++); V = *(srcV++); | ||
479 | iR = (351 * (V-128)) / 256; | ||
480 | iG = - (179 * (V-128)) / 256 - (86 * (U-128)) / 256; | ||
481 | iB = (444 * (U-128)) / 256; | ||
482 | |||
483 | Y = *(srcY++); | ||
484 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
485 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
486 | *(dst++) = R; *(dst++) = G; *(dst++) = B; | ||
487 | |||
488 | Y = *(srcY2++); | ||
489 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
490 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
491 | *(dst2++) = R; *(dst2++) = G; *(dst2++) = B; | ||
492 | |||
493 | Y = *(srcY++) ; | ||
494 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
495 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
496 | *(dst++) = R; *(dst++) = G; *(dst++) = B; | ||
497 | |||
498 | Y = *(srcY2++); | ||
499 | R = Y + iR ; G = Y + iG ; B = Y + iB ; | ||
500 | R = (R<0?0:(R>255?255:R)); G = (G<0?0:(G>255?255:G)); B = (B<0?0:(B>255?255:B)); | ||
501 | *(dst2++) = R; *(dst2++) = G; *(dst2++) = B; | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | |||
506 | #define mask32(BYTE) (*(uint32_t *)(uint8_t [4]){ [BYTE] = 0xff }) | ||
507 | |||
408 | void *decode_video_thread(void *arg) | 508 | void *decode_video_thread(void *arg) |
409 | { | 509 | { |
410 | INFO("Started decode video thread!"); | 510 | INFO("Started decode video thread!"); |
411 | av_session_t* _phone = arg; | 511 | av_session_t* _phone = arg; |
412 | _phone->running_decvid = 1; | 512 | _phone->running_decvid = 1; |
413 | 513 | ||
414 | CodecState *cs = get_cs_temp(_phone->av); | 514 | //CodecState *cs = get_cs_temp(_phone->av); |
415 | cs->video_stream = 0; | 515 | //cs->video_stream = 0; |
416 | 516 | ||
417 | int recved_size; | 517 | //int recved_size; |
418 | uint8_t dest[RTP_PAYLOAD_SIZE]; | 518 | //uint8_t dest[RTP_PAYLOAD_SIZE]; |
419 | 519 | ||
420 | int dec_frame_finished; | 520 | //int dec_frame_finished; |
421 | AVFrame *r_video_frame; | 521 | //AVFrame *r_video_frame; |
422 | r_video_frame = avcodec_alloc_frame(); | 522 | //r_video_frame = avcodec_alloc_frame(); |
423 | AVPacket dec_video_packet; | 523 | //AVPacket dec_video_packet; |
424 | av_new_packet (&dec_video_packet, 65536); | 524 | //av_new_packet (&dec_video_packet, 65536); |
425 | int width = 0; | 525 | int width = 0; |
426 | int height = 0; | 526 | int height = 0; |
427 | 527 | ||
428 | while (_phone->running_decvid) { | 528 | while (_phone->running_decvid) { |
429 | 529 | //recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, dest); | |
430 | recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, 1, dest); | 530 | //if (recved_size) { |
431 | 531 | vpx_image_t *image; | |
432 | if (recved_size) { | 532 | if (toxav_recv_video(_phone->av, &image) == 0) { |
433 | memcpy(dec_video_packet.data, dest, recved_size); | 533 | //memcpy(dec_video_packet.data, dest, recved_size); |
434 | dec_video_packet.size = recved_size; | 534 | //dec_video_packet.size = recved_size; |
435 | 535 | ||
436 | avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); | 536 | //avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); |
437 | 537 | ||
438 | if (dec_frame_finished) { | 538 | //if (dec_frame_finished) { |
439 | 539 | ||
440 | /* Check if size has changed */ | 540 | /* Check if size has changed */ |
441 | if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { | 541 | if (image->d_w != width || image->d_h != height) { |
442 | 542 | ||
443 | width = cs->video_decoder_ctx->width; | 543 | width = image->d_w; |
444 | height = cs->video_decoder_ctx->height; | 544 | height = image->d_h; |
445 | 545 | ||
446 | printf("w: %d h: %d \n", width, height); | 546 | printf("w: %d h: %d \n", width, height); |
447 | 547 | ||
448 | screen = SDL_SetVideoMode(width, height, 0, 0); | 548 | screen = SDL_SetVideoMode(width, height, 0, 0); |
449 | 549 | ||
450 | if (_phone->video_picture.bmp) | 550 | //if (_phone->video_picture.bmp) |
451 | SDL_FreeYUVOverlay(_phone->video_picture.bmp); | 551 | // SDL_FreeYUVOverlay(_phone->video_picture.bmp); |
452 | 552 | ||
453 | _phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); | 553 | //_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); |
454 | _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, | 554 | // _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, |
455 | SWS_BILINEAR, NULL, NULL, NULL); | 555 | // SWS_BILINEAR, NULL, NULL, NULL); |
456 | } | 556 | } |
557 | uint8_t *rgb_image = malloc(width*height*3); | ||
558 | convert_to_rgb(image, rgb_image); | ||
559 | SDL_Surface* img_surface = SDL_CreateRGBSurfaceFrom(rgb_image, width, height, 24, width * 3, mask32(0), mask32(1), mask32(2), 0); | ||
560 | if(SDL_BlitSurface(img_surface, NULL, screen, NULL) == 0) | ||
561 | SDL_UpdateRect(screen, 0, 0, 0, 0); | ||
562 | /* | ||
563 | SDL_LockYUVOverlay(_phone->video_picture.bmp); | ||
564 | memcpy(_phone->video_picture.bmp->pixels[0], image->planes[VPX_PLANE_Y], _phone->video_picture.bmp->pitches[0] * height); | ||
565 | memcpy(_phone->video_picture.bmp->pixels[1], image->planes[VPX_PLANE_V], _phone->video_picture.bmp->pitches[1] * height / 2); | ||
566 | memcpy(_phone->video_picture.bmp->pixels[2], image->planes[VPX_PLANE_U], _phone->video_picture.bmp->pitches[2] * height / 2); | ||
457 | 567 | ||
458 | display_received_frame(_phone, r_video_frame); | 568 | SDL_Rect rect; |
459 | } else { | 569 | rect.x = 0; |
570 | rect.y = 0; | ||
571 | rect.w = width; | ||
572 | rect.h = height; | ||
573 | SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);*/ | ||
574 | free(rgb_image); | ||
575 | //display_received_frame(_phone, image); | ||
576 | |||
577 | } //else { | ||
460 | /* TODO: request the sender to create a new i-frame immediatly */ | 578 | /* TODO: request the sender to create a new i-frame immediatly */ |
461 | printf("Bad video packet\n"); | 579 | //printf("Bad video packet\n"); |
462 | } | 580 | //} |
463 | } | 581 | //} |
464 | 582 | ||
465 | usleep(1000); | 583 | usleep(1000); |
466 | } | 584 | } |
467 | 585 | ||
468 | /* clean up codecs */ | 586 | /* clean up codecs */ |
469 | av_free(r_video_frame); | 587 | //av_free(r_video_frame); |
470 | 588 | ||
471 | pthread_mutex_lock(&cs->ctrl_mutex); | 589 | //pthread_mutex_lock(&cs->ctrl_mutex); |
472 | avcodec_close(cs->video_decoder_ctx); | 590 | //avcodec_close(cs->video_decoder_ctx); |
473 | pthread_mutex_unlock(&cs->ctrl_mutex); | 591 | //pthread_mutex_unlock(&cs->ctrl_mutex); |
474 | 592 | ||
475 | _phone->running_decvid = -1; | 593 | _phone->running_decvid = -1; |
476 | 594 | ||
@@ -483,11 +601,11 @@ void *decode_audio_thread(void *arg) | |||
483 | av_session_t* _phone = arg; | 601 | av_session_t* _phone = arg; |
484 | _phone->running_decaud = 1; | 602 | _phone->running_decaud = 1; |
485 | 603 | ||
486 | int recved_size; | 604 | //int recved_size; |
487 | uint8_t dest [RTP_PAYLOAD_SIZE]; | 605 | //uint8_t dest [RTP_PAYLOAD_SIZE]; |
488 | 606 | ||
489 | int frame_size = AUDIO_FRAME_SIZE; | 607 | int frame_size = AUDIO_FRAME_SIZE; |
490 | int data_size; | 608 | //int data_size; |
491 | 609 | ||
492 | ALCdevice *dev; | 610 | ALCdevice *dev; |
493 | ALCcontext *ctx; | 611 | ALCcontext *ctx; |
@@ -507,7 +625,7 @@ void *decode_audio_thread(void *arg) | |||
507 | 625 | ||
508 | uint16_t zeros[frame_size]; | 626 | uint16_t zeros[frame_size]; |
509 | memset(zeros, 0, frame_size); | 627 | memset(zeros, 0, frame_size); |
510 | opus_int16 PCM[frame_size]; | 628 | int16_t PCM[frame_size]; |
511 | 629 | ||
512 | int i; | 630 | int i; |
513 | for (i = 0; i < openal_buffers; ++i) { | 631 | for (i = 0; i < openal_buffers; ++i) { |
@@ -527,28 +645,15 @@ void *decode_audio_thread(void *arg) | |||
527 | while (_phone->running_decaud) { | 645 | while (_phone->running_decaud) { |
528 | 646 | ||
529 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); | 647 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); |
530 | 648 | if (ready <= 0) | |
531 | recved_size = toxav_recv_rtp_payload(_phone->av, TypeAudio, ready, dest); | 649 | continue; |
532 | 650 | ||
533 | if ( recved_size == ErrorAudioPacketLost ) { | 651 | dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM); |
534 | printf("Lost packet\n"); | 652 | |
535 | dec_frame_len = toxav_decode_audio(_phone->av, NULL, 0, frame_size, PCM); | ||
536 | |||
537 | } else if ( recved_size ) { | ||
538 | dec_frame_len = toxav_decode_audio(_phone->av, dest, recved_size, frame_size, PCM); | ||
539 | } | ||
540 | |||
541 | |||
542 | /* Play the packet */ | 653 | /* Play the packet */ |
543 | if (dec_frame_len) { | 654 | if (dec_frame_len > 0) { |
544 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); | ||
545 | |||
546 | if (ready <= 0) | ||
547 | continue; | ||
548 | |||
549 | alSourceUnqueueBuffers(source, 1, &buffer); | 655 | alSourceUnqueueBuffers(source, 1, &buffer); |
550 | data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1); | 656 | alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000); |
551 | alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000); | ||
552 | int error = alGetError(); | 657 | int error = alGetError(); |
553 | 658 | ||
554 | if (error != AL_NO_ERROR) { | 659 | if (error != AL_NO_ERROR) { |
@@ -573,16 +678,16 @@ void *decode_audio_thread(void *arg) | |||
573 | 678 | ||
574 | 679 | ||
575 | ending: | 680 | ending: |
576 | /* clean up codecs * / | 681 | /* clean up codecs */ |
577 | pthread_mutex_lock(&cs->ctrl_mutex); | 682 | //pthread_mutex_lock(&cs->ctrl_mutex); |
578 | 683 | /* | |
579 | alDeleteSources(1, &source); | 684 | alDeleteSources(1, &source); |
580 | alDeleteBuffers(openal_buffers, buffers); | 685 | alDeleteBuffers(openal_buffers, buffers); |
581 | alcMakeContextCurrent(NULL); | 686 | alcMakeContextCurrent(NULL); |
582 | alcDestroyContext(ctx); | 687 | alcDestroyContext(ctx); |
583 | alcCloseDevice(dev); | 688 | alcCloseDevice(dev); |
584 | 689 | */ | |
585 | pthread_mutex_unlock(&cs->ctrl_mutex); */ | 690 | //pthread_mutex_unlock(&cs->ctrl_mutex); |
586 | 691 | ||
587 | _phone->running_decaud = -1; | 692 | _phone->running_decaud = -1; |
588 | 693 | ||
@@ -604,7 +709,7 @@ int phone_startmedia_loop ( ToxAv* arg ) | |||
604 | /* | 709 | /* |
605 | * Rise all threads | 710 | * Rise all threads |
606 | */ | 711 | */ |
607 | 712 | #ifdef TOX_FFMPEG | |
608 | /* Only checks for last peer */ | 713 | /* Only checks for last peer */ |
609 | if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo && | 714 | if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo && |
610 | 0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) ) | 715 | 0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) ) |
@@ -612,7 +717,7 @@ int phone_startmedia_loop ( ToxAv* arg ) | |||
612 | INFO("Error while starting encode_video_thread()"); | 717 | INFO("Error while starting encode_video_thread()"); |
613 | return -1; | 718 | return -1; |
614 | } | 719 | } |
615 | 720 | #endif | |
616 | /* Always send audio */ | 721 | /* Always send audio */ |
617 | if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) | 722 | if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) |
618 | { | 723 | { |
@@ -779,7 +884,6 @@ av_session_t* av_init_session() | |||
779 | } | 884 | } |
780 | 885 | ||
781 | _retu->_friends = NULL; | 886 | _retu->_friends = NULL; |
782 | _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT); | ||
783 | 887 | ||
784 | 888 | ||
785 | const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); | 889 | const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); |
@@ -821,13 +925,58 @@ av_session_t* av_init_session() | |||
821 | printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); | 925 | printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); |
822 | return 0; | 926 | return 0; |
823 | } | 927 | } |
824 | 928 | uint16_t height = 0, width = 0; | |
825 | 929 | #ifdef TOX_FFMPEG | |
930 | avdevice_register_all(); | ||
931 | avcodec_register_all(); | ||
932 | av_register_all(); | ||
933 | |||
934 | _retu->video_input_format = av_find_input_format(VIDEO_DRIVER); | ||
935 | if (avformat_open_input(&_retu->video_format_ctx, DEFAULT_WEBCAM, _retu->video_input_format, NULL) != 0) { | ||
936 | fprintf(stderr, "Opening video_input_format failed!\n"); | ||
937 | //return -1; | ||
938 | return NULL; | ||
939 | } | ||
940 | |||
941 | avformat_find_stream_info(_retu->video_format_ctx, NULL); | ||
942 | av_dump_format(_retu->video_format_ctx, 0, DEFAULT_WEBCAM, 0); | ||
943 | |||
944 | for (i = 0; i < _retu->video_format_ctx->nb_streams; ++i) { | ||
945 | if (_retu->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
946 | _retu->video_stream = i; | ||
947 | break; | ||
948 | } | ||
949 | } | ||
950 | |||
951 | _retu->webcam_decoder_ctx = _retu->video_format_ctx->streams[_retu->video_stream]->codec; | ||
952 | _retu->webcam_decoder = avcodec_find_decoder(_retu->webcam_decoder_ctx->codec_id); | ||
953 | |||
954 | if (_retu->webcam_decoder == NULL) { | ||
955 | fprintf(stderr, "Unsupported codec!\n"); | ||
956 | //return -1; | ||
957 | return NULL; | ||
958 | } | ||
959 | |||
960 | if (_retu->webcam_decoder_ctx == NULL) { | ||
961 | fprintf(stderr, "Init webcam_decoder_ctx failed!\n"); | ||
962 | //return -1; | ||
963 | return NULL; | ||
964 | } | ||
965 | |||
966 | if (avcodec_open2(_retu->webcam_decoder_ctx, _retu->webcam_decoder, NULL) < 0) { | ||
967 | fprintf(stderr, "Opening webcam decoder failed!\n"); | ||
968 | //return -1; | ||
969 | return NULL; | ||
970 | } | ||
971 | width = _retu->webcam_decoder_ctx->width; | ||
972 | height = _retu->webcam_decoder_ctx->height; | ||
973 | #endif | ||
826 | uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; | 974 | uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; |
827 | tox_get_address(_retu->_messenger, _byte_address ); | 975 | tox_get_address(_retu->_messenger, _byte_address ); |
828 | fraddr_to_str( _byte_address, _retu->_my_public_id ); | 976 | fraddr_to_str( _byte_address, _retu->_my_public_id ); |
829 | 977 | ||
830 | 978 | ||
979 | _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT, width, height); | ||
831 | 980 | ||
832 | /* ------------------ */ | 981 | /* ------------------ */ |
833 | 982 | ||
@@ -842,7 +991,7 @@ av_session_t* av_init_session() | |||
842 | toxav_register_callstate_callback(callback_recv_ending, OnEnding); | 991 | toxav_register_callstate_callback(callback_recv_ending, OnEnding); |
843 | 992 | ||
844 | toxav_register_callstate_callback(callback_recv_error, OnError); | 993 | toxav_register_callstate_callback(callback_recv_error, OnError); |
845 | toxav_register_callstate_callback(callback_requ_timeout, OnTimeout); | 994 | toxav_register_callstate_callback(callback_requ_timeout, OnRequestTimeout); |
846 | 995 | ||
847 | /* ------------------ */ | 996 | /* ------------------ */ |
848 | 997 | ||
@@ -1013,9 +1162,9 @@ void do_phone ( av_session_t* _phone ) | |||
1013 | { | 1162 | { |
1014 | ToxAvError rc; | 1163 | ToxAvError rc; |
1015 | 1164 | ||
1016 | if ( _len > 1 && _line[2] == 'v' ) | 1165 | if ( _len > 1 && _line[2] == 'v' ) { |
1017 | rc = toxav_answer(_phone->av, TypeVideo); | 1166 | rc = toxav_answer(_phone->av, TypeVideo); |
1018 | else | 1167 | } else |
1019 | rc = toxav_answer(_phone->av, TypeAudio); | 1168 | rc = toxav_answer(_phone->av, TypeAudio); |
1020 | 1169 | ||
1021 | if ( rc == ErrorInvalidState ) { | 1170 | if ( rc == ErrorInvalidState ) { |
diff --git a/toxav/rtp.c b/toxav/rtp.c index e23fa132..80fcc630 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c | |||
@@ -30,10 +30,6 @@ | |||
30 | #include <assert.h> | 30 | #include <assert.h> |
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | 32 | ||
33 | #include "../toxcore/util.h" | ||
34 | #include "../toxcore/network.h" | ||
35 | #include "../toxcore/net_crypto.h" | ||
36 | #include "../toxcore/Messenger.h" | ||
37 | 33 | ||
38 | #define PAYLOAD_ID_VALUE_OPUS 1 | 34 | #define PAYLOAD_ID_VALUE_OPUS 1 |
39 | #define PAYLOAD_ID_VALUE_VP8 2 | 35 | #define PAYLOAD_ID_VALUE_VP8 2 |
@@ -241,8 +237,8 @@ RTPHeader* extract_header ( const uint8_t* payload, int length ) | |||
241 | 237 | ||
242 | _retu->flags = *_it; ++_it; | 238 | _retu->flags = *_it; ++_it; |
243 | 239 | ||
244 | /* This indicates if the first 2 bytes are valid. | 240 | /* This indicates if the first 2 bits are valid. |
245 | * Now it my happen that this is out of order but | 241 | * Now it may happen that this is out of order but |
246 | * it cuts down chances of parsing some invalid value | 242 | * it cuts down chances of parsing some invalid value |
247 | */ | 243 | */ |
248 | 244 | ||
@@ -299,7 +295,7 @@ RTPHeader* extract_header ( const uint8_t* payload, int length ) | |||
299 | * @return RTPExtHeader* Extracted extension header. | 295 | * @return RTPExtHeader* Extracted extension header. |
300 | * @retval NULL Error occurred while extracting extension header. | 296 | * @retval NULL Error occurred while extracting extension header. |
301 | */ | 297 | */ |
302 | RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length ) | 298 | RTPExtHeader* extract_ext_header ( const uint8_t* payload, uint16_t length ) |
303 | { | 299 | { |
304 | const uint8_t* _it = payload; | 300 | const uint8_t* _it = payload; |
305 | 301 | ||
@@ -551,7 +547,7 @@ int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t l | |||
551 | /* Hopefully this goes well | 547 | /* Hopefully this goes well |
552 | * NOTE: Is this even used? | 548 | * NOTE: Is this even used? |
553 | */ | 549 | */ |
554 | memcpy(&_msg->from, &ip_port, sizeof(tox_IP_Port)); | 550 | memcpy(&_msg->from, &ip_port, sizeof(IP_Port)); |
555 | 551 | ||
556 | /* Check if message came in late */ | 552 | /* Check if message came in late */ |
557 | if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ | 553 | if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ |
@@ -689,7 +685,7 @@ int rtp_release_session_recv ( RTPSession* session ) | |||
689 | 685 | ||
690 | 686 | ||
691 | /** | 687 | /** |
692 | * @brief Get's oldes message in the list. | 688 | * @brief Gets oldest message in the list. |
693 | * | 689 | * |
694 | * @param session Where the list is. | 690 | * @param session Where the list is. |
695 | * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. | 691 | * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. |
@@ -727,7 +723,7 @@ RTPMessage* rtp_recv_msg ( RTPSession* session ) | |||
727 | * @retval -1 On error. | 723 | * @retval -1 On error. |
728 | * @retval 0 On success. | 724 | * @retval 0 On success. |
729 | */ | 725 | */ |
730 | int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ) | 726 | int rtp_send_msg ( RTPSession* session, Messenger* messenger, const uint8_t* data, uint16_t length ) |
731 | { | 727 | { |
732 | RTPMessage* msg = rtp_new_message (session, data, length); | 728 | RTPMessage* msg = rtp_new_message (session, data, length); |
733 | 729 | ||
@@ -743,8 +739,8 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin | |||
743 | increase_nonce ( _calculated, msg->header->sequnum ); | 739 | increase_nonce ( _calculated, msg->header->sequnum ); |
744 | 740 | ||
745 | /* Need to skip 2 bytes that are for sequnum */ | 741 | /* Need to skip 2 bytes that are for sequnum */ |
746 | int encrypted_length = encrypt_data_symmetric( | 742 | int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/ |
747 | (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length - 2, _send_data + 3 ); | 743 | (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 ); |
748 | 744 | ||
749 | int full_length = encrypted_length + 3; | 745 | int full_length = encrypted_length + 3; |
750 | 746 | ||
@@ -752,7 +748,8 @@ int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uin | |||
752 | _send_data[2] = msg->data[1]; | 748 | _send_data[2] = msg->data[1]; |
753 | 749 | ||
754 | 750 | ||
755 | if ( full_length != sendpacket ( ((Messenger*)messenger)->net, *((IP_Port*) &session->dest), _send_data, full_length) ) { | 751 | /*if ( full_length != sendpacket ( messenger->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {*/ |
752 | if ( full_length != send_custom_user_packet(messenger, session->dest, _send_data, full_length) ) { | ||
756 | printf("Rtp error: %s\n", strerror(errno)); | 753 | printf("Rtp error: %s\n", strerror(errno)); |
757 | return -1; | 754 | return -1; |
758 | } | 755 | } |
@@ -816,30 +813,26 @@ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ) | |||
816 | * @retval NULL Error occurred. | 813 | * @retval NULL Error occurred. |
817 | */ | 814 | */ |
818 | RTPSession* rtp_init_session ( int payload_type, | 815 | RTPSession* rtp_init_session ( int payload_type, |
819 | Tox* messenger, | 816 | Messenger* messenger, |
820 | int friend_num, | 817 | int friend_num, |
821 | const uint8_t* encrypt_key, | 818 | const uint8_t* encrypt_key, |
822 | const uint8_t* decrypt_key, | 819 | const uint8_t* decrypt_key, |
823 | const uint8_t* encrypt_nonce, | 820 | const uint8_t* encrypt_nonce, |
824 | const uint8_t* decrypt_nonce | 821 | const uint8_t* decrypt_nonce ) |
825 | ) | ||
826 | { | 822 | { |
827 | Messenger* _messenger_casted = (Messenger*) messenger; | ||
828 | |||
829 | IP_Port _dest = get_friend_ipport(_messenger_casted, friend_num ); | ||
830 | |||
831 | /* This should be enough eh? */ | ||
832 | if ( _dest.port == 0) { | ||
833 | return NULL; | ||
834 | } | ||
835 | |||
836 | RTPSession* _retu = calloc(1, sizeof(RTPSession)); | 823 | RTPSession* _retu = calloc(1, sizeof(RTPSession)); |
837 | assert(_retu); | 824 | assert(_retu); |
838 | 825 | ||
839 | networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu); | 826 | /*networking_registerhandler(messenger->net, payload_type, rtp_handle_packet, _retu);*/ |
827 | if ( -1 == custom_user_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ) | ||
828 | { | ||
829 | fprintf(stderr, "Error setting custom register handler for rtp session\n"); | ||
830 | free(_retu); | ||
831 | return NULL; | ||
832 | } | ||
840 | 833 | ||
841 | _retu->version = RTP_VERSION; /* It's always 2 */ | 834 | _retu->version = RTP_VERSION; /* It's always 2 */ |
842 | _retu->padding = 0; /* If some additional data is needed about the packet */ | 835 | _retu->padding = 0; /* If some additional data is needed about the packet */ |
843 | _retu->extension = 0; /* If extension to header is needed */ | 836 | _retu->extension = 0; /* If extension to header is needed */ |
844 | _retu->cc = 1; /* Amount of contributors */ | 837 | _retu->cc = 1; /* Amount of contributors */ |
845 | _retu->csrc = NULL; /* Container */ | 838 | _retu->csrc = NULL; /* Container */ |
@@ -847,7 +840,7 @@ RTPSession* rtp_init_session ( int payload_type, | |||
847 | _retu->marker = 0; | 840 | _retu->marker = 0; |
848 | _retu->payload_type = payload_table[payload_type]; | 841 | _retu->payload_type = payload_table[payload_type]; |
849 | 842 | ||
850 | _retu->dest = *((tox_IP_Port*)&_dest); | 843 | _retu->dest = friend_num; |
851 | 844 | ||
852 | _retu->rsequnum = _retu->sequnum = 1; | 845 | _retu->rsequnum = _retu->sequnum = 1; |
853 | 846 | ||
@@ -894,12 +887,12 @@ RTPSession* rtp_init_session ( int payload_type, | |||
894 | * @retval -1 Error occurred. | 887 | * @retval -1 Error occurred. |
895 | * @retval 0 Success. | 888 | * @retval 0 Success. |
896 | */ | 889 | */ |
897 | int rtp_terminate_session ( RTPSession* session, Tox* messenger ) | 890 | int rtp_terminate_session ( RTPSession* session, Messenger* messenger ) |
898 | { | 891 | { |
899 | if ( !session ) | 892 | if ( !session ) |
900 | return -1; | 893 | return -1; |
901 | 894 | ||
902 | networking_registerhandler(((Messenger*)messenger)->net, session->prefix, NULL, NULL); | 895 | custom_user_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); |
903 | 896 | ||
904 | free ( session->ext_header ); | 897 | free ( session->ext_header ); |
905 | free ( session->csrc ); | 898 | free ( session->csrc ); |
diff --git a/toxav/rtp.h b/toxav/rtp.h index 4b0d681f..03f6a873 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h | |||
@@ -28,10 +28,14 @@ | |||
28 | #define RTP_VERSION 2 | 28 | #define RTP_VERSION 2 |
29 | #include <inttypes.h> | 29 | #include <inttypes.h> |
30 | #include <pthread.h> | 30 | #include <pthread.h> |
31 | #include "../toxcore/tox.h" | 31 | |
32 | #include "../toxcore/util.h" | ||
33 | #include "../toxcore/network.h" | ||
34 | #include "../toxcore/net_crypto.h" | ||
35 | #include "../toxcore/Messenger.h" | ||
32 | 36 | ||
33 | #define MAX_SEQU_NUM 65535 | 37 | #define MAX_SEQU_NUM 65535 |
34 | #define MAX_RTP_SIZE 10400 | 38 | #define MAX_RTP_SIZE 65535 |
35 | 39 | ||
36 | /** | 40 | /** |
37 | * @brief Standard rtp header | 41 | * @brief Standard rtp header |
@@ -72,7 +76,7 @@ typedef struct _RTPMessage { | |||
72 | 76 | ||
73 | uint8_t data[MAX_RTP_SIZE]; | 77 | uint8_t data[MAX_RTP_SIZE]; |
74 | uint32_t length; | 78 | uint32_t length; |
75 | tox_IP_Port from; | 79 | IP_Port from; |
76 | 80 | ||
77 | struct _RTPMessage* next; | 81 | struct _RTPMessage* next; |
78 | } RTPMessage; | 82 | } RTPMessage; |
@@ -128,7 +132,7 @@ typedef struct _RTPSession { | |||
128 | uint8_t prefix; | 132 | uint8_t prefix; |
129 | 133 | ||
130 | pthread_mutex_t mutex; | 134 | pthread_mutex_t mutex; |
131 | tox_IP_Port dest; | 135 | int dest; |
132 | 136 | ||
133 | } RTPSession; | 137 | } RTPSession; |
134 | 138 | ||
@@ -164,7 +168,7 @@ RTPMessage* rtp_recv_msg ( RTPSession* session ); | |||
164 | * @retval -1 On error. | 168 | * @retval -1 On error. |
165 | * @retval 0 On success. | 169 | * @retval 0 On success. |
166 | */ | 170 | */ |
167 | int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ); | 171 | int rtp_send_msg ( RTPSession* session, Messenger* messenger, const uint8_t* data, uint16_t length ); |
168 | 172 | ||
169 | 173 | ||
170 | /** | 174 | /** |
@@ -192,7 +196,7 @@ void rtp_free_msg ( RTPSession* session, RTPMessage* msg ); | |||
192 | * @retval NULL Error occurred. | 196 | * @retval NULL Error occurred. |
193 | */ | 197 | */ |
194 | RTPSession* rtp_init_session ( int payload_type, | 198 | RTPSession* rtp_init_session ( int payload_type, |
195 | Tox* messenger, | 199 | Messenger* messenger, |
196 | int friend_num, | 200 | int friend_num, |
197 | const uint8_t* encrypt_key, | 201 | const uint8_t* encrypt_key, |
198 | const uint8_t* decrypt_key, | 202 | const uint8_t* decrypt_key, |
@@ -209,7 +213,7 @@ RTPSession* rtp_init_session ( int payload_type, | |||
209 | * @retval -1 Error occurred. | 213 | * @retval -1 Error occurred. |
210 | * @retval 0 Success. | 214 | * @retval 0 Success. |
211 | */ | 215 | */ |
212 | int rtp_terminate_session ( RTPSession* session, Tox* messenger ); | 216 | int rtp_terminate_session ( RTPSession* session, Messenger* messenger ); |
213 | 217 | ||
214 | 218 | ||
215 | 219 | ||
diff --git a/toxav/toxav.c b/toxav/toxav.c index 8757d7fd..5683795e 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c | |||
@@ -26,16 +26,16 @@ | |||
26 | #include "config.h" | 26 | #include "config.h" |
27 | #endif /* HAVE_CONFIG_H */ | 27 | #endif /* HAVE_CONFIG_H */ |
28 | 28 | ||
29 | #include "toxav.h" | 29 | #include "media.h" |
30 | #include "../toxcore/tox.h" | ||
31 | #include "rtp.h" | 30 | #include "rtp.h" |
32 | #include "msi.h" | 31 | #include "msi.h" |
33 | #include "media.h" | ||
34 | 32 | ||
35 | #include <stdlib.h> | 33 | #include <stdlib.h> |
36 | #include <string.h> | 34 | #include <string.h> |
37 | #include <assert.h> | 35 | #include <assert.h> |
38 | 36 | ||
37 | #include "toxav.h" | ||
38 | |||
39 | #define inline__ inline __attribute__((always_inline)) | 39 | #define inline__ inline __attribute__((always_inline)) |
40 | 40 | ||
41 | static const uint8_t audio_index = 0, video_index = 1; | 41 | static const uint8_t audio_index = 0, video_index = 1; |
@@ -50,7 +50,7 @@ typedef enum { | |||
50 | 50 | ||
51 | typedef struct _ToxAv | 51 | typedef struct _ToxAv |
52 | { | 52 | { |
53 | Tox* messenger; | 53 | Messenger* messenger; |
54 | 54 | ||
55 | MSISession* msi_session; /** Main msi session */ | 55 | MSISession* msi_session; /** Main msi session */ |
56 | 56 | ||
@@ -89,21 +89,23 @@ typedef struct _ToxAv | |||
89 | 89 | ||
90 | 90 | ||
91 | 91 | ||
92 | ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name ) | 92 | ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name , uint16_t video_width, uint16_t video_height) |
93 | { | 93 | { |
94 | ToxAv* av = calloc ( sizeof(ToxAv), 1); | 94 | ToxAv* av = calloc ( sizeof(ToxAv), 1); |
95 | 95 | if (av == NULL) | |
96 | av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name ); | 96 | return NULL; |
97 | |||
98 | av->messenger = (Messenger *)messenger; | ||
99 | |||
100 | av->msi_session = msi_init_session(av->messenger, (const unsigned char*) ua_name ); | ||
97 | av->msi_session->agent_handler = av; | 101 | av->msi_session->agent_handler = av; |
98 | 102 | ||
99 | av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; | 103 | av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; |
100 | 104 | ||
101 | av->messenger = messenger; | ||
102 | |||
103 | /* NOTE: This should be user defined or? */ | 105 | /* NOTE: This should be user defined or? */ |
104 | av->j_buf = create_queue(20); | 106 | av->j_buf = create_queue(20); |
105 | 107 | ||
106 | av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER); | 108 | av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, AUDIO_CHANNELS, video_width, video_height, VIDEO_BITRATE); |
107 | 109 | ||
108 | av->agent_handler = useragent; | 110 | av->agent_handler = useragent; |
109 | 111 | ||
@@ -273,7 +275,7 @@ inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8 | |||
273 | else return -1; | 275 | else return -1; |
274 | } | 276 | } |
275 | 277 | ||
276 | inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest ) | 278 | inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, uint8_t* dest ) |
277 | { | 279 | { |
278 | if ( !dest ) return ErrorInternal; | 280 | if ( !dest ) return ErrorInternal; |
279 | 281 | ||
@@ -283,20 +285,19 @@ inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, | |||
283 | 285 | ||
284 | if ( type == TypeAudio ) { | 286 | if ( type == TypeAudio ) { |
285 | 287 | ||
286 | message = rtp_recv_msg(av->rtp_sessions[audio_index]); | 288 | do { |
289 | message = rtp_recv_msg(av->rtp_sessions[audio_index]); | ||
290 | |||
291 | if (message) { | ||
292 | /* push the packet into the queue */ | ||
293 | queue(av->j_buf, message); | ||
294 | } | ||
295 | } while(message); | ||
287 | 296 | ||
288 | if (message) { | 297 | int success = 0; |
289 | /* push the packet into the queue */ | 298 | message = dequeue(av->j_buf, &success); |
290 | queue(av->j_buf, message); | 299 | |
291 | } | 300 | if ( success == 2) return ErrorAudioPacketLost; |
292 | |||
293 | if (ready) { | ||
294 | int success = 0; | ||
295 | message = dequeue(av->j_buf, &success); | ||
296 | |||
297 | if ( success == 2) return ErrorAudioPacketLost; | ||
298 | } | ||
299 | else return 0; | ||
300 | } | 301 | } |
301 | else { | 302 | else { |
302 | message = rtp_recv_msg(av->rtp_sessions[video_index]); | 303 | 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, | |||
315 | return 0; | 316 | return 0; |
316 | } | 317 | } |
317 | 318 | ||
318 | inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ) | 319 | inline__ int toxav_recv_video ( ToxAv* av, vpx_image_t **output) |
319 | { | 320 | { |
320 | if ( !dest ) return ErrorInternal; | 321 | if ( !output ) return ErrorInternal; |
322 | uint8_t packet [RTP_PAYLOAD_SIZE]; | ||
323 | int recved_size = 0; | ||
324 | do { | ||
325 | recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet); | ||
326 | if (recved_size > 0) { | ||
327 | printf("decode: %s\n", vpx_codec_err_to_string(vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0))); | ||
328 | } | ||
329 | }while (recved_size > 0); | ||
330 | vpx_codec_iter_t iter = NULL; | ||
331 | vpx_image_t *img; | ||
332 | img = vpx_codec_get_frame(&av->cs->v_decoder, &iter); | ||
333 | if (img == NULL) | ||
334 | return ErrorInternal; | ||
321 | 335 | ||
322 | return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1); | 336 | *output = img; |
337 | return 0; | ||
323 | } | 338 | } |
324 | 339 | ||
325 | inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ) | 340 | inline__ int toxav_send_video ( ToxAv* av, vpx_image_t *input) |
326 | { | 341 | { |
327 | if ( !dest ) | 342 | if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) { |
343 | printf("could not encode video frame\n"); | ||
328 | return ErrorInternal; | 344 | return ErrorInternal; |
345 | } | ||
346 | ++av->cs->frame_counter; | ||
347 | |||
348 | vpx_codec_iter_t iter = NULL; | ||
349 | const vpx_codec_cx_pkt_t *pkt; | ||
350 | int sent = 0; | ||
351 | while( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { | ||
352 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { | ||
353 | if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) | ||
354 | ++sent; | ||
355 | } | ||
356 | } | ||
357 | if (sent > 0) | ||
358 | return 0; | ||
329 | 359 | ||
330 | return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE); | 360 | return ErrorInternal; |
361 | } | ||
362 | |||
363 | inline__ int toxav_recv_audio ( ToxAv* av, int frame_size, int16_t* dest ) | ||
364 | { | ||
365 | if ( !dest ) return ErrorInternal; | ||
366 | uint8_t packet [RTP_PAYLOAD_SIZE]; | ||
367 | |||
368 | int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet); | ||
369 | |||
370 | if ( recved_size == ErrorAudioPacketLost ) { | ||
371 | printf("Lost packet\n"); | ||
372 | return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1); | ||
373 | } else if ( recved_size ){ | ||
374 | return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); | ||
375 | } else { | ||
376 | return ErrorInternal; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | inline__ int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size) | ||
381 | { | ||
382 | uint8_t temp_data[RTP_PAYLOAD_SIZE]; | ||
383 | int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data)); | ||
384 | if (ret <= 0) | ||
385 | return ErrorInternal; | ||
386 | |||
387 | return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); | ||
331 | } | 388 | } |
332 | 389 | ||
333 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) | 390 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ) |
@@ -343,10 +400,3 @@ void* toxav_get_agent_handler ( ToxAv* av ) | |||
343 | { | 400 | { |
344 | return av->agent_handler; | 401 | return av->agent_handler; |
345 | } | 402 | } |
346 | |||
347 | |||
348 | /* Only temporary */ | ||
349 | void* get_cs_temp(ToxAv* av) | ||
350 | { | ||
351 | return av->cs; | ||
352 | } | ||
diff --git a/toxav/toxav.h b/toxav/toxav.h index 96a666a2..63dbf162 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h | |||
@@ -27,6 +27,9 @@ | |||
27 | #define __TOXAV | 27 | #define __TOXAV |
28 | #include <inttypes.h> | 28 | #include <inttypes.h> |
29 | 29 | ||
30 | /* vpx_image_t */ | ||
31 | #include <vpx/vpx_image.h> | ||
32 | |||
30 | typedef void* ( *ToxAVCallback ) ( void* arg ); | 33 | typedef void* ( *ToxAVCallback ) ( void* arg ); |
31 | typedef struct _ToxAv ToxAv; | 34 | typedef struct _ToxAv ToxAv; |
32 | 35 | ||
@@ -35,7 +38,29 @@ typedef struct _ToxAv ToxAv; | |||
35 | typedef struct Tox Tox; | 38 | typedef struct Tox Tox; |
36 | #endif | 39 | #endif |
37 | 40 | ||
38 | #define RTP_PAYLOAD_SIZE 10400 | 41 | #define RTP_PAYLOAD_SIZE 65535 |
42 | |||
43 | /* Default video bitrate in bytes/s */ | ||
44 | #define VIDEO_BITRATE 10*1000*100 | ||
45 | |||
46 | /* Default audio bitrate in bits/s */ | ||
47 | #define AUDIO_BITRATE 64000 | ||
48 | |||
49 | /* Number of audio channels. */ | ||
50 | #define AUDIO_CHANNELS 1 | ||
51 | |||
52 | /* Audio frame duration in miliseconds */ | ||
53 | #define AUDIO_FRAME_DURATION 20 | ||
54 | |||
55 | /* Audio sample rate recommended to be 48kHz for Opus */ | ||
56 | #define AUDIO_SAMPLE_RATE 48000 | ||
57 | |||
58 | /* The amount of samples in one audio frame */ | ||
59 | #define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000 | ||
60 | |||
61 | /* Assume 60 fps*/ | ||
62 | #define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) | ||
63 | |||
39 | 64 | ||
40 | /** | 65 | /** |
41 | * @brief Callbacks ids that handle the call states | 66 | * @brief Callbacks ids that handle the call states |
@@ -55,7 +80,7 @@ typedef enum { | |||
55 | 80 | ||
56 | /* Protocol */ | 81 | /* Protocol */ |
57 | OnError, | 82 | OnError, |
58 | OnTimeout | 83 | OnRequestTimeout |
59 | 84 | ||
60 | } ToxAvCallbackID; | 85 | } ToxAvCallbackID; |
61 | 86 | ||
@@ -86,7 +111,7 @@ typedef enum { | |||
86 | } ToxAvError; | 111 | } ToxAvError; |
87 | 112 | ||
88 | 113 | ||
89 | ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name); | 114 | ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name, uint16_t video_width, uint16_t video_height) ; |
90 | void toxav_kill(ToxAv* av); | 115 | void toxav_kill(ToxAv* av); |
91 | 116 | ||
92 | void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); | 117 | void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); |
@@ -103,27 +128,25 @@ int toxav_prepare_transmission(ToxAv* av); | |||
103 | int toxav_kill_transmission(ToxAv* av); | 128 | int toxav_kill_transmission(ToxAv* av); |
104 | 129 | ||
105 | 130 | ||
106 | int toxav_send_rtp_payload(ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length); | 131 | |
107 | 132 | ||
108 | /* Return length of received packet. Returns 0 if nothing recved. Dest has to have | 133 | /* Return length of received packet. Returns 0 if nothing recved. Dest has to have |
109 | * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque. | 134 | * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque. |
110 | * For video packets set 'ready' at _any_ value. | 135 | * For video packets set 'ready' at _any_ value. |
111 | */ | 136 | */ |
112 | int toxav_recv_rtp_payload(ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest); | ||
113 | |||
114 | |||
115 | 137 | ||
138 | /* returns 0 on success */ | ||
139 | int toxav_recv_video ( ToxAv* av, vpx_image_t **output); | ||
116 | 140 | ||
117 | int toxav_decode_audio( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest ); | 141 | int toxav_recv_audio( ToxAv* av, int frame_size, int16_t* dest ); |
118 | 142 | ||
119 | /* Please make sure 'dest' has enough storage for RTP_PAYLOAD_SIZE length of data */ | 143 | int toxav_send_video ( ToxAv* av, vpx_image_t *input); |
120 | int toxav_encode_audio( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ); | 144 | /* Encode and send audio frame. */ |
145 | int toxav_send_audio ( ToxAv* av, const int16_t* frame, int frame_size); | ||
121 | 146 | ||
122 | 147 | ||
123 | 148 | ||
124 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); | 149 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); |
125 | void* toxav_get_agent_handler ( ToxAv* av ); | 150 | void* toxav_get_agent_handler ( ToxAv* av ); |
126 | 151 | ||
127 | /* Use this to get handle of CodecState from ToxAv struct */ | ||
128 | void* get_cs_temp( ToxAv* av ); | ||
129 | #endif /* __TOXAV */ \ No newline at end of file | 152 | #endif /* __TOXAV */ \ No newline at end of file |
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 02175c2a..982b06c4 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -379,6 +379,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n | |||
379 | int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, | 379 | int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN, |
380 | uint8_t want_good) | 380 | uint8_t want_good) |
381 | { | 381 | { |
382 | memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format)); | ||
382 | #ifdef ENABLE_ASSOC_DHT | 383 | #ifdef ENABLE_ASSOC_DHT |
383 | 384 | ||
384 | if (!dht->assoc) | 385 | if (!dht->assoc) |
@@ -1249,9 +1250,9 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id) | |||
1249 | --dht->num_friends; | 1250 | --dht->num_friends; |
1250 | 1251 | ||
1251 | if (dht->num_friends != i) { | 1252 | if (dht->num_friends != i) { |
1252 | memcpy( dht->friends_list[i].client_id, | 1253 | memcpy( &dht->friends_list[i], |
1253 | dht->friends_list[dht->num_friends].client_id, | 1254 | &dht->friends_list[dht->num_friends], |
1254 | CLIENT_ID_SIZE ); | 1255 | sizeof(DHT_Friend) ); |
1255 | } | 1256 | } |
1256 | 1257 | ||
1257 | if (dht->num_friends == 0) { | 1258 | if (dht->num_friends == 0) { |
@@ -1553,7 +1554,7 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt | |||
1553 | IP_Port ip_list[MAX_FRIEND_CLIENTS]; | 1554 | IP_Port ip_list[MAX_FRIEND_CLIENTS]; |
1554 | int ip_num = friend_iplist(dht, ip_list, num); | 1555 | int ip_num = friend_iplist(dht, ip_list, num); |
1555 | 1556 | ||
1556 | if (ip_num < (MAX_FRIEND_CLIENTS / 2)) | 1557 | if (ip_num < (MAX_FRIEND_CLIENTS / 4)) |
1557 | return 0; /* Reason for that? */ | 1558 | return 0; /* Reason for that? */ |
1558 | 1559 | ||
1559 | DHT_Friend *friend = &dht->friends_list[num]; | 1560 | 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, | |||
2394 | num = length / sizeof(DHT_Friend); | 2395 | num = length / sizeof(DHT_Friend); |
2395 | 2396 | ||
2396 | for (i = 0; i < num; ++i) { | 2397 | for (i = 0; i < num; ++i) { |
2397 | DHT_addfriend(dht, friend_list[i].client_id); | ||
2398 | 2398 | ||
2399 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { | 2399 | for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { |
2400 | Client_data *client = &friend_list[i].client_list[j]; | 2400 | Client_data *client = &friend_list[i].client_list[j]; |
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index c1301767..692d3d0e 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -43,6 +43,71 @@ static uint8_t friend_not_valid(Messenger *m, int friendnumber) | |||
43 | return (unsigned int)friendnumber >= m->numfriends; | 43 | return (unsigned int)friendnumber >= m->numfriends; |
44 | } | 44 | } |
45 | 45 | ||
46 | static int add_online_friend(Messenger *m, int friendnumber) | ||
47 | { | ||
48 | if (friend_not_valid(m, friendnumber)) | ||
49 | return -1; | ||
50 | |||
51 | IP_Port temp_ip_port = get_friend_ipport(m, friendnumber); | ||
52 | |||
53 | if (temp_ip_port.port == 0) | ||
54 | return -1; | ||
55 | |||
56 | uint32_t i; | ||
57 | |||
58 | for (i = 0; i < m->numonline_friends; ++i) { | ||
59 | if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | Online_Friend *temp; | ||
64 | temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends + 1)); | ||
65 | |||
66 | if (temp == NULL) | ||
67 | return -1; | ||
68 | |||
69 | m->online_friendlist = temp; | ||
70 | m->online_friendlist[m->numonline_friends].friend_num = friendnumber; | ||
71 | m->online_friendlist[m->numonline_friends].ip_port = temp_ip_port; | ||
72 | ++m->numonline_friends; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | |||
77 | static int remove_online_friend(Messenger *m, int friendnumber) | ||
78 | { | ||
79 | uint32_t i; | ||
80 | Online_Friend *temp; | ||
81 | |||
82 | for (i = 0; i < m->numonline_friends; ++i) { | ||
83 | /* Equal */ | ||
84 | if (m->online_friendlist[i].friend_num == (uint32_t)friendnumber) { | ||
85 | --m->numonline_friends; | ||
86 | |||
87 | if (m->numonline_friends != i) { | ||
88 | memcpy( &m->online_friendlist[i], | ||
89 | &m->online_friendlist[m->numonline_friends], | ||
90 | sizeof(Online_Friend) ); | ||
91 | } | ||
92 | |||
93 | if (m->numonline_friends == 0) { | ||
94 | free(m->online_friendlist); | ||
95 | m->online_friendlist = NULL; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | temp = realloc(m->online_friendlist, sizeof(Online_Friend) * (m->numonline_friends)); | ||
100 | |||
101 | if (temp == NULL) | ||
102 | return -1; | ||
103 | |||
104 | m->online_friendlist = temp; | ||
105 | return 0; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | return -1; | ||
110 | } | ||
46 | /* Set the size of the friend list to numfriends. | 111 | /* Set the size of the friend list to numfriends. |
47 | * | 112 | * |
48 | * return -1 if realloc fails. | 113 | * return -1 if realloc fails. |
@@ -273,6 +338,9 @@ int m_delfriend(Messenger *m, int friendnumber) | |||
273 | if (friend_not_valid(m, friendnumber)) | 338 | if (friend_not_valid(m, friendnumber)) |
274 | return -1; | 339 | return -1; |
275 | 340 | ||
341 | if (m->friendlist[friendnumber].status == FRIEND_ONLINE) | ||
342 | remove_online_friend(m, friendnumber); | ||
343 | |||
276 | onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); | 344 | onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum); |
277 | crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); | 345 | crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id); |
278 | free(m->friendlist[friendnumber].statusmessage); | 346 | free(m->friendlist[friendnumber].statusmessage); |
@@ -650,12 +718,17 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in | |||
650 | m->friend_connectionstatuschange = function; | 718 | m->friend_connectionstatuschange = function; |
651 | m->friend_connectionstatuschange_userdata = userdata; | 719 | m->friend_connectionstatuschange_userdata = userdata; |
652 | } | 720 | } |
721 | |||
722 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), | ||
723 | void *userdata) | ||
724 | { | ||
725 | m->friend_connectionstatuschange_internal = function; | ||
726 | m->friend_connectionstatuschange_internal_userdata = userdata; | ||
727 | } | ||
728 | |||
653 | static void break_files(Messenger *m, int friendnumber); | 729 | static void break_files(Messenger *m, int friendnumber); |
654 | static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) | 730 | static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_t status) |
655 | { | 731 | { |
656 | if (!m->friend_connectionstatuschange) | ||
657 | return; | ||
658 | |||
659 | if (status == NOFRIEND) | 732 | if (status == NOFRIEND) |
660 | return; | 733 | return; |
661 | 734 | ||
@@ -665,10 +738,19 @@ static void check_friend_connectionstatus(Messenger *m, int friendnumber, uint8_ | |||
665 | onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); | 738 | onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online); |
666 | 739 | ||
667 | if (is_online != was_online) { | 740 | if (is_online != was_online) { |
668 | if (was_online) | 741 | if (was_online) { |
669 | break_files(m, friendnumber); | 742 | break_files(m, friendnumber); |
743 | remove_online_friend(m, friendnumber); | ||
744 | } else { | ||
745 | add_online_friend(m, friendnumber); | ||
746 | } | ||
747 | |||
748 | if (m->friend_connectionstatuschange) | ||
749 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); | ||
670 | 750 | ||
671 | m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata); | 751 | if (m->friend_connectionstatuschange_internal) |
752 | m->friend_connectionstatuschange_internal(m, friendnumber, is_online, | ||
753 | m->friend_connectionstatuschange_internal_userdata); | ||
672 | } | 754 | } |
673 | } | 755 | } |
674 | 756 | ||
@@ -814,6 +896,8 @@ static void group_message_function(Group_Chat *chat, int peer_number, uint8_t *m | |||
814 | if (i == -1) | 896 | if (i == -1) |
815 | return; | 897 | return; |
816 | 898 | ||
899 | message[length - 1] = 0; /* Force NULL terminator */ | ||
900 | |||
817 | if (m->group_message) | 901 | if (m->group_message) |
818 | (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); | 902 | (*m->group_message)(m, i, peer_number, message, length, m->group_message_userdata); |
819 | } | 903 | } |
@@ -826,6 +910,8 @@ static void group_action_function(Group_Chat *chat, int peer_number, uint8_t *ac | |||
826 | if (i == -1) | 910 | if (i == -1) |
827 | return; | 911 | return; |
828 | 912 | ||
913 | action[length - 1] = 0; /* Force NULL terminator */ | ||
914 | |||
829 | if (m->group_action) | 915 | if (m->group_action) |
830 | (*m->group_action)(m, i, peer_number, action, length, m->group_action_userdata); | 916 | (*m->group_action)(m, i, peer_number, action, length, m->group_action_userdata); |
831 | } | 917 | } |
@@ -1489,6 +1575,60 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) | |||
1489 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); | 1575 | return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length); |
1490 | } | 1576 | } |
1491 | 1577 | ||
1578 | static int friendnum_from_ip_port(Messenger *m, IP_Port ip_port) | ||
1579 | { | ||
1580 | uint32_t i; | ||
1581 | |||
1582 | for (i = 0; i < m->numonline_friends; ++i) { | ||
1583 | if (ipport_equal(&m->online_friendlist[i].ip_port, &ip_port)) | ||
1584 | return m->online_friendlist[i].friend_num; | ||
1585 | } | ||
1586 | |||
1587 | return -1; | ||
1588 | } | ||
1589 | |||
1590 | static int handle_custom_user_packet(void *object, IP_Port source, uint8_t *packet, uint32_t length) | ||
1591 | { | ||
1592 | Messenger *m = object; | ||
1593 | int friend_num = friendnum_from_ip_port(m, source); | ||
1594 | |||
1595 | if (friend_num == -1) | ||
1596 | return 1; | ||
1597 | |||
1598 | if (m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function) | ||
1599 | return m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].function( | ||
1600 | m->friendlist[friend_num].packethandlers[packet[0] % TOTAL_USERPACKETS].object, source, packet, length); | ||
1601 | |||
1602 | return 1; | ||
1603 | } | ||
1604 | |||
1605 | |||
1606 | int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, | ||
1607 | void *object) | ||
1608 | { | ||
1609 | if (friend_not_valid(m, friendnumber)) | ||
1610 | return -1; | ||
1611 | |||
1612 | if (byte < NET_PACKET_CUSTOM_RANGE_START || byte >= NET_PACKET_CUSTOM_RANGE_END) | ||
1613 | return -1; | ||
1614 | |||
1615 | m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].function = cb; | ||
1616 | m->friendlist[friendnumber].packethandlers[byte % TOTAL_USERPACKETS].object = object; | ||
1617 | networking_registerhandler(m->net, byte, handle_custom_user_packet, m); | ||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length) | ||
1622 | { | ||
1623 | IP_Port ip_port = get_friend_ipport(m, friendnumber); | ||
1624 | |||
1625 | if (ip_port.port == 0) | ||
1626 | return -1; | ||
1627 | |||
1628 | return sendpacket(m->net, ip_port, data, length); | ||
1629 | } | ||
1630 | |||
1631 | |||
1492 | /* Function to filter out some friend requests*/ | 1632 | /* Function to filter out some friend requests*/ |
1493 | static int friend_already_added(uint8_t *client_id, void *data) | 1633 | static int friend_already_added(uint8_t *client_id, void *data) |
1494 | { | 1634 | { |
@@ -1841,6 +1981,8 @@ void do_friends(Messenger *m) | |||
1841 | m->friendlist[i].file_receiving[filenumber].size = filesize; | 1981 | m->friendlist[i].file_receiving[filenumber].size = filesize; |
1842 | m->friendlist[i].file_receiving[filenumber].transferred = 0; | 1982 | m->friendlist[i].file_receiving[filenumber].transferred = 0; |
1843 | 1983 | ||
1984 | data[data_length - 1] = 0; /* Force NULL terminate file name. */ | ||
1985 | |||
1844 | if (m->file_sendrequest) | 1986 | if (m->file_sendrequest) |
1845 | (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), | 1987 | (*m->file_sendrequest)(m, i, filenumber, filesize, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t), |
1846 | m->file_sendrequest_userdata); | 1988 | m->file_sendrequest_userdata); |
@@ -2360,6 +2502,12 @@ uint32_t count_friendlist(Messenger *m) | |||
2360 | return ret; | 2502 | return ret; |
2361 | } | 2503 | } |
2362 | 2504 | ||
2505 | /* Return the number of online friends in the instance m. */ | ||
2506 | uint32_t get_num_online_friends(Messenger *m) | ||
2507 | { | ||
2508 | return m->numonline_friends; | ||
2509 | } | ||
2510 | |||
2363 | /* Copy a list of valid friend IDs into the array out_list. | 2511 | /* Copy a list of valid friend IDs into the array out_list. |
2364 | * If out_list is NULL, returns 0. | 2512 | * If out_list is NULL, returns 0. |
2365 | * Otherwise, returns the number of elements copied. | 2513 | * Otherwise, returns the number of elements copied. |
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index e09b2f30..ccca8fba 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -155,8 +155,15 @@ typedef struct { | |||
155 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; | 155 | struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; |
156 | int invited_groups[MAX_INVITED_GROUPS]; | 156 | int invited_groups[MAX_INVITED_GROUPS]; |
157 | uint16_t invited_groups_num; | 157 | uint16_t invited_groups_num; |
158 | |||
159 | Packet_Handles packethandlers[TOTAL_USERPACKETS]; | ||
158 | } Friend; | 160 | } Friend; |
159 | 161 | ||
162 | typedef struct { | ||
163 | uint32_t friend_num; | ||
164 | IP_Port ip_port; | ||
165 | } Online_Friend; | ||
166 | |||
160 | typedef struct Messenger { | 167 | typedef struct Messenger { |
161 | 168 | ||
162 | Networking_Core *net; | 169 | Networking_Core *net; |
@@ -179,6 +186,9 @@ typedef struct Messenger { | |||
179 | Friend *friendlist; | 186 | Friend *friendlist; |
180 | uint32_t numfriends; | 187 | uint32_t numfriends; |
181 | 188 | ||
189 | Online_Friend *online_friendlist; | ||
190 | uint32_t numonline_friends; | ||
191 | |||
182 | Group_Chat **chats; | 192 | Group_Chat **chats; |
183 | uint32_t numchats; | 193 | uint32_t numchats; |
184 | 194 | ||
@@ -200,6 +210,8 @@ typedef struct Messenger { | |||
200 | void *friend_statuschange_userdata; | 210 | void *friend_statuschange_userdata; |
201 | void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); | 211 | void (*friend_connectionstatuschange)(struct Messenger *m, int, uint8_t, void *); |
202 | void *friend_connectionstatuschange_userdata; | 212 | void *friend_connectionstatuschange_userdata; |
213 | void (*friend_connectionstatuschange_internal)(struct Messenger *m, int, uint8_t, void *); | ||
214 | void *friend_connectionstatuschange_internal_userdata; | ||
203 | 215 | ||
204 | void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); | 216 | void (*group_invite)(struct Messenger *m, int, uint8_t *, void *); |
205 | void *group_invite_userdata; | 217 | void *group_invite_userdata; |
@@ -450,6 +462,9 @@ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int, u | |||
450 | * It's assumed that when adding friends, their connection status is offline. | 462 | * It's assumed that when adding friends, their connection status is offline. |
451 | */ | 463 | */ |
452 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); | 464 | void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), void *userdata); |
465 | /* Same as previous but for internal A/V core usage only */ | ||
466 | void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int, uint8_t, void *), | ||
467 | void *userdata); | ||
453 | 468 | ||
454 | /**********GROUP CHATS************/ | 469 | /**********GROUP CHATS************/ |
455 | 470 | ||
@@ -627,6 +642,22 @@ int m_msi_packet(Messenger *m, int friendnumber, uint8_t *data, uint16_t length) | |||
627 | 642 | ||
628 | /**********************************************/ | 643 | /**********************************************/ |
629 | 644 | ||
645 | /* Set handlers for custom user packets (RTP packets for example.) | ||
646 | * | ||
647 | * return -1 on failure. | ||
648 | * return 0 on success. | ||
649 | */ | ||
650 | int custom_user_packet_registerhandler(Messenger *m, int friendnumber, uint8_t byte, packet_handler_callback cb, | ||
651 | void *object); | ||
652 | |||
653 | /* High level function to send custom user packets. | ||
654 | * | ||
655 | * return -1 on failure. | ||
656 | * return number of bytes sent on success. | ||
657 | */ | ||
658 | int send_custom_user_packet(Messenger *m, int friendnumber, uint8_t *data, uint32_t length); | ||
659 | |||
660 | /**********************************************/ | ||
630 | /* Run this at startup. | 661 | /* Run this at startup. |
631 | * return allocated instance of Messenger on success. | 662 | * return allocated instance of Messenger on success. |
632 | * return 0 if there are problems. | 663 | * return 0 if there are problems. |
@@ -682,6 +713,9 @@ int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8 | |||
682 | * for copy_friendlist. */ | 713 | * for copy_friendlist. */ |
683 | uint32_t count_friendlist(Messenger *m); | 714 | uint32_t count_friendlist(Messenger *m); |
684 | 715 | ||
716 | /* Return the number of online friends in the instance m. */ | ||
717 | uint32_t get_num_online_friends(Messenger *m); | ||
718 | |||
685 | /* Copy a list of valid friend IDs into the array out_list. | 719 | /* Copy a list of valid friend IDs into the array out_list. |
686 | * If out_list is NULL, returns 0. | 720 | * If out_list is NULL, returns 0. |
687 | * Otherwise, returns the number of elements copied. | 721 | * Otherwise, returns the number of elements copied. |
diff --git a/toxcore/event.c b/toxcore/event.c index 05e2a03c..2fdc9442 100755 --- a/toxcore/event.c +++ b/toxcore/event.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "event.h" | 31 | #include "event.h" |
32 | 32 | ||
33 | #include "util.h" | 33 | #include "util.h" |
34 | #include "network.h" | ||
34 | 35 | ||
35 | #define _GNU_SOURCE | 36 | #define _GNU_SOURCE |
36 | 37 | ||
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c index 5c294c76..9ac72097 100644 --- a/toxcore/friend_requests.c +++ b/toxcore/friend_requests.c | |||
@@ -140,6 +140,9 @@ static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t | |||
140 | return 1; | 140 | return 1; |
141 | 141 | ||
142 | addto_receivedlist(fr, source_pubkey); | 142 | addto_receivedlist(fr, source_pubkey); |
143 | |||
144 | packet[length - 1] = 0; /* Force NULL terminator. */ | ||
145 | |||
143 | (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); | 146 | (*fr->handle_friendrequest)(source_pubkey, packet + 4, length - 4, fr->handle_friendrequest_userdata); |
144 | return 0; | 147 | return 0; |
145 | } | 148 | } |
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index 90ffdd14..6dff52ef 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c | |||
@@ -75,6 +75,32 @@ static int peer_in_chat(Group_Chat *chat, uint8_t *client_id) | |||
75 | return -1; | 75 | return -1; |
76 | } | 76 | } |
77 | 77 | ||
78 | /* Compares client_id1 and client_id2 with client_id. | ||
79 | * | ||
80 | * return 0 if both are same distance. | ||
81 | * return 1 if client_id1 is closer. | ||
82 | * return 2 if client_id2 is closer. | ||
83 | */ | ||
84 | static int id_closest_groupchats(uint8_t *id, uint8_t *id1, uint8_t *id2) | ||
85 | { | ||
86 | size_t i; | ||
87 | uint8_t distance1, distance2; | ||
88 | |||
89 | for (i = 0; i < CLIENT_ID_SIZE; ++i) { | ||
90 | |||
91 | distance1 = abs(((int8_t *)id)[i] - ((int8_t *)id1)[i]); | ||
92 | distance2 = abs(((int8_t *)id)[i] - ((int8_t *)id2)[i]); | ||
93 | |||
94 | if (distance1 < distance2) | ||
95 | return 1; | ||
96 | |||
97 | if (distance1 > distance2) | ||
98 | return 2; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
78 | #define BAD_GROUPNODE_TIMEOUT 30 | 104 | #define BAD_GROUPNODE_TIMEOUT 30 |
79 | 105 | ||
80 | /* | 106 | /* |
@@ -100,7 +126,7 @@ static int peer_okping(Group_Chat *chat, uint8_t *client_id) | |||
100 | if (id_equal(chat->close[i].client_id, client_id)) | 126 | if (id_equal(chat->close[i].client_id, client_id)) |
101 | return -1; | 127 | return -1; |
102 | 128 | ||
103 | if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) | 129 | if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) |
104 | ++j; | 130 | ++j; |
105 | } | 131 | } |
106 | 132 | ||
@@ -137,7 +163,7 @@ static int add_closepeer(Group_Chat *chat, uint8_t *client_id, IP_Port ip_port) | |||
137 | } | 163 | } |
138 | 164 | ||
139 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ | 165 | for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { /* Replace nodes if given one is closer. */ |
140 | if (id_closest(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { | 166 | if (id_closest_groupchats(chat->self_public_key, chat->close[i].client_id, client_id) == 2) { |
141 | id_copy(chat->close[i].client_id, client_id); | 167 | id_copy(chat->close[i].client_id, client_id); |
142 | chat->close[i].ip_port = ip_port; | 168 | chat->close[i].ip_port = ip_port; |
143 | chat->close[i].last_recv = unix_time(); | 169 | chat->close[i].last_recv = unix_time(); |
diff --git a/toxcore/network.c b/toxcore/network.c index 1186a468..839618bf 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -540,8 +540,10 @@ Networking_Core *new_networking(IP ip, uint16_t port) | |||
540 | addr6->sin6_scope_id = 0; | 540 | addr6->sin6_scope_id = 0; |
541 | 541 | ||
542 | portptr = &addr6->sin6_port; | 542 | portptr = &addr6->sin6_port; |
543 | } else | 543 | } else { |
544 | free(temp); | ||
544 | return NULL; | 545 | return NULL; |
546 | } | ||
545 | 547 | ||
546 | if (ip.family == AF_INET6) { | 548 | if (ip.family == AF_INET6) { |
547 | char ipv6only = 0; | 549 | char ipv6only = 0; |
diff --git a/toxcore/network.h b/toxcore/network.h index 4c7f1a83..aaf89f19 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -129,6 +129,12 @@ typedef int sock_t; | |||
129 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ | 129 | #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ |
130 | #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ | 130 | #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ |
131 | 131 | ||
132 | /* Range of ids that custom user packets can use. */ | ||
133 | #define NET_PACKET_CUSTOM_RANGE_START 64 | ||
134 | #define NET_PACKET_CUSTOM_RANGE_END 96 | ||
135 | |||
136 | #define TOTAL_USERPACKETS (NET_PACKET_CUSTOM_RANGE_END - NET_PACKET_CUSTOM_RANGE_START) | ||
137 | |||
132 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ | 138 | /* See: docs/Prevent_Tracking.txt and onion.{c, h} */ |
133 | #define NET_PACKET_ONION_SEND_INITIAL 128 | 139 | #define NET_PACKET_ONION_SEND_INITIAL 128 |
134 | #define NET_PACKET_ONION_SEND_1 129 | 140 | #define NET_PACKET_ONION_SEND_1 129 |
@@ -143,6 +149,9 @@ typedef int sock_t; | |||
143 | #define NET_PACKET_ONION_RECV_2 141 | 149 | #define NET_PACKET_ONION_RECV_2 141 |
144 | #define NET_PACKET_ONION_RECV_1 142 | 150 | #define NET_PACKET_ONION_RECV_1 142 |
145 | 151 | ||
152 | /* Only used for bootstrap servers */ | ||
153 | #define BOOTSTRAP_INFO_PACKET_ID 240 | ||
154 | |||
146 | 155 | ||
147 | #define TOX_PORTRANGE_FROM 33445 | 156 | #define TOX_PORTRANGE_FROM 33445 |
148 | #define TOX_PORTRANGE_TO 33545 | 157 | #define TOX_PORTRANGE_TO 33545 |
diff --git a/toxcore/onion.c b/toxcore/onion.c index 961f5bd5..578621cc 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | #include "onion.h" | 26 | #include "onion.h" |
27 | #include "util.h" | ||
27 | 28 | ||
28 | #define MAX_ONION_SIZE MAX_DATA_SIZE | 29 | #define MAX_ONION_SIZE MAX_DATA_SIZE |
29 | 30 | ||
@@ -36,6 +37,16 @@ | |||
36 | #define SEND_2 ONION_SEND_2 | 37 | #define SEND_2 ONION_SEND_2 |
37 | #define SEND_1 ONION_SEND_1 | 38 | #define SEND_1 ONION_SEND_1 |
38 | 39 | ||
40 | /* Change symmetric keys every hour to make paths expire eventually. */ | ||
41 | #define KEY_REFRESH_INTERVAL (60 * 60) | ||
42 | static void change_symmetric_key(Onion *onion) | ||
43 | { | ||
44 | if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) { | ||
45 | new_symmetric_key(onion->secret_symmetric_key); | ||
46 | onion->timestamp = unix_time(); | ||
47 | } | ||
48 | } | ||
49 | |||
39 | /* Create and send a onion packet. | 50 | /* Create and send a onion packet. |
40 | * | 51 | * |
41 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data | 52 | * 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 | |||
126 | if (length <= 1 + SEND_1) | 137 | if (length <= 1 + SEND_1) |
127 | return 1; | 138 | return 1; |
128 | 139 | ||
140 | change_symmetric_key(onion); | ||
141 | |||
129 | uint8_t plain[MAX_ONION_SIZE]; | 142 | uint8_t plain[MAX_ONION_SIZE]; |
130 | 143 | ||
131 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 144 | 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 | |||
170 | if (length <= 1 + SEND_2) | 183 | if (length <= 1 + SEND_2) |
171 | return 1; | 184 | return 1; |
172 | 185 | ||
186 | change_symmetric_key(onion); | ||
187 | |||
173 | uint8_t plain[MAX_ONION_SIZE]; | 188 | uint8_t plain[MAX_ONION_SIZE]; |
174 | 189 | ||
175 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 190 | 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 | |||
217 | if (length <= 1 + SEND_3) | 232 | if (length <= 1 + SEND_3) |
218 | return 1; | 233 | return 1; |
219 | 234 | ||
235 | change_symmetric_key(onion); | ||
236 | |||
220 | uint8_t plain[MAX_ONION_SIZE]; | 237 | uint8_t plain[MAX_ONION_SIZE]; |
221 | 238 | ||
222 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 239 | 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 | |||
263 | if (length <= 1 + RETURN_3) | 280 | if (length <= 1 + RETURN_3) |
264 | return 1; | 281 | return 1; |
265 | 282 | ||
283 | change_symmetric_key(onion); | ||
284 | |||
266 | uint8_t plain[sizeof(IP_Port) + RETURN_2]; | 285 | uint8_t plain[sizeof(IP_Port) + RETURN_2]; |
267 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, | 286 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, |
268 | sizeof(IP_Port) + RETURN_2 + crypto_secretbox_MACBYTES, plain); | 287 | 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 | |||
295 | if (length <= 1 + RETURN_2) | 314 | if (length <= 1 + RETURN_2) |
296 | return 1; | 315 | return 1; |
297 | 316 | ||
317 | change_symmetric_key(onion); | ||
318 | |||
298 | uint8_t plain[sizeof(IP_Port) + RETURN_1]; | 319 | uint8_t plain[sizeof(IP_Port) + RETURN_1]; |
299 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, | 320 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, |
300 | sizeof(IP_Port) + RETURN_1 + crypto_secretbox_MACBYTES, plain); | 321 | 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 | |||
327 | if (length <= 1 + RETURN_1) | 348 | if (length <= 1 + RETURN_1) |
328 | return 1; | 349 | return 1; |
329 | 350 | ||
351 | change_symmetric_key(onion); | ||
352 | |||
330 | IP_Port send_to; | 353 | IP_Port send_to; |
331 | 354 | ||
332 | int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, | 355 | 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) | |||
358 | onion->dht = dht; | 381 | onion->dht = dht; |
359 | onion->net = dht->c->lossless_udp->net; | 382 | onion->net = dht->c->lossless_udp->net; |
360 | new_symmetric_key(onion->secret_symmetric_key); | 383 | new_symmetric_key(onion->secret_symmetric_key); |
384 | onion->timestamp = unix_time(); | ||
361 | 385 | ||
362 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); | 386 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); |
363 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); | 387 | networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); |
diff --git a/toxcore/onion.h b/toxcore/onion.h index b46dbdfe..a52bcb86 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h | |||
@@ -29,6 +29,7 @@ typedef struct { | |||
29 | DHT *dht; | 29 | DHT *dht; |
30 | Networking_Core *net; | 30 | Networking_Core *net; |
31 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; | 31 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; |
32 | uint64_t timestamp; | ||
32 | } Onion; | 33 | } Onion; |
33 | 34 | ||
34 | #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) | 35 | #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) |
diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 2ca53896..da40584d 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c | |||
@@ -325,7 +325,7 @@ Onion_Announce *new_onion_announce(DHT *dht) | |||
325 | return NULL; | 325 | return NULL; |
326 | 326 | ||
327 | onion_a->dht = dht; | 327 | onion_a->dht = dht; |
328 | onion_a->net = dht->c->lossless_udp->net; | 328 | onion_a->net = dht->net; |
329 | new_symmetric_key(onion_a->secret_bytes); | 329 | new_symmetric_key(onion_a->secret_bytes); |
330 | 330 | ||
331 | networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); | 331 | networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); |
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 93697c28..c03dfcea 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c | |||
@@ -390,6 +390,8 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t | |||
390 | crypto_box_PUBLICKEYBYTES) != 0) { | 390 | crypto_box_PUBLICKEYBYTES) != 0) { |
391 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); | 391 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); |
392 | 392 | ||
393 | onion_c->friends_list[friend_num].last_seen = unix_time(); | ||
394 | |||
393 | if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { | 395 | if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { |
394 | return 1; | 396 | return 1; |
395 | } | 397 | } |
@@ -712,6 +714,9 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
712 | if ((uint32_t)friend_num >= onion_c->num_friends) | 714 | if ((uint32_t)friend_num >= onion_c->num_friends) |
713 | return -1; | 715 | return -1; |
714 | 716 | ||
717 | if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1) | ||
718 | onion_c->friends_list[friend_num].last_seen = unix_time(); | ||
719 | |||
715 | onion_c->friends_list[friend_num].is_online = is_online; | 720 | onion_c->friends_list[friend_num].is_online = is_online; |
716 | 721 | ||
717 | /* This should prevent some clock related issues */ | 722 | /* This should prevent some clock related issues */ |
@@ -767,7 +772,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
767 | } | 772 | } |
768 | 773 | ||
769 | if (count != MAX_ONION_CLIENTS) { | 774 | if (count != MAX_ONION_CLIENTS) { |
770 | if (count < rand() % MAX_ONION_CLIENTS) { | 775 | if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { |
771 | Node_format nodes_list[MAX_SENT_NODES]; | 776 | Node_format nodes_list[MAX_SENT_NODES]; |
772 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->friends_list[friendnum].real_client_id, nodes_list, | 777 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->friends_list[friendnum].real_client_id, nodes_list, |
773 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); | 778 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); |
@@ -788,6 +793,25 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
788 | 793 | ||
789 | } | 794 | } |
790 | } | 795 | } |
796 | |||
797 | /* Timeout before which a peer is considered dead and removed from the DHT search. */ | ||
798 | #define DEAD_ONION_TIMEOUT (10 * 60) | ||
799 | |||
800 | static void cleanup_friend(Onion_Client *onion_c, uint16_t friendnum) | ||
801 | { | ||
802 | if (friendnum >= onion_c->num_friends) | ||
803 | return; | ||
804 | |||
805 | if (onion_c->friends_list[friendnum].status == 0) | ||
806 | return; | ||
807 | |||
808 | if (onion_c->friends_list[friendnum].is_fake_clientid && !onion_c->friends_list[friendnum].is_online | ||
809 | && is_timeout(onion_c->friends_list[friendnum].last_seen, DEAD_ONION_TIMEOUT)) { | ||
810 | onion_c->friends_list[friendnum].is_fake_clientid = 0; | ||
811 | DHT_delfriend(onion_c->dht, onion_c->friends_list[friendnum].fake_client_id); | ||
812 | } | ||
813 | } | ||
814 | |||
791 | /* Function to call when onion data packet with contents beginning with byte is received. */ | 815 | /* Function to call when onion data packet with contents beginning with byte is received. */ |
792 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) | 816 | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) |
793 | { | 817 | { |
@@ -823,7 +847,7 @@ static void do_announce(Onion_Client *onion_c) | |||
823 | } | 847 | } |
824 | 848 | ||
825 | if (count != MAX_ONION_CLIENTS) { | 849 | if (count != MAX_ONION_CLIENTS) { |
826 | if (count < rand() % MAX_ONION_CLIENTS) { | 850 | if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { |
827 | Node_format nodes_list[MAX_SENT_NODES]; | 851 | Node_format nodes_list[MAX_SENT_NODES]; |
828 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, | 852 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, |
829 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); | 853 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); |
@@ -845,6 +869,7 @@ void do_onion_client(Onion_Client *onion_c) | |||
845 | 869 | ||
846 | for (i = 0; i < onion_c->num_friends; ++i) { | 870 | for (i = 0; i < onion_c->num_friends; ++i) { |
847 | do_friend(onion_c, i); | 871 | do_friend(onion_c, i); |
872 | cleanup_friend(onion_c, i); | ||
848 | } | 873 | } |
849 | 874 | ||
850 | onion_c->last_run = unix_time(); | 875 | onion_c->last_run = unix_time(); |
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 708d9093..36b5b5c3 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h | |||
@@ -61,6 +61,8 @@ typedef struct { | |||
61 | uint64_t last_fakeid_dht_sent; | 61 | uint64_t last_fakeid_dht_sent; |
62 | 62 | ||
63 | uint64_t last_noreplay; | 63 | uint64_t last_noreplay; |
64 | |||
65 | uint64_t last_seen; | ||
64 | } Onion_Friend; | 66 | } Onion_Friend; |
65 | 67 | ||
66 | typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); | 68 | typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); |
diff --git a/toxcore/tox.c b/toxcore/tox.c index 04e412be..f4690080 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -289,6 +289,13 @@ uint32_t tox_count_friendlist(Tox *tox) | |||
289 | return count_friendlist(m); | 289 | return count_friendlist(m); |
290 | } | 290 | } |
291 | 291 | ||
292 | /* Return the number of online friends in the instance m. */ | ||
293 | uint32_t tox_get_num_online_friends(Tox *tox) | ||
294 | { | ||
295 | Messenger *m = tox; | ||
296 | return get_num_online_friends(m); | ||
297 | } | ||
298 | |||
292 | /* Copy a list of valid friend IDs into the array out_list. | 299 | /* Copy a list of valid friend IDs into the array out_list. |
293 | * If out_list is NULL, returns 0. | 300 | * If out_list is NULL, returns 0. |
294 | * Otherwise, returns the number of elements copied. | 301 | * Otherwise, returns the number of elements copied. |
diff --git a/toxcore/tox.h b/toxcore/tox.h index f3118270..447a1146 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -128,6 +128,13 @@ TOX_USERSTATUS; | |||
128 | typedef struct Tox Tox; | 128 | typedef struct Tox Tox; |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | /* NOTE: Strings in Tox are all UTF-8, also the last byte in all strings must be NULL (0). | ||
132 | * | ||
133 | * The length when passing those strings to the core includes that NULL character. | ||
134 | * | ||
135 | * If you send non NULL terminated strings Tox will force NULL terminates them when it receives them. | ||
136 | */ | ||
137 | |||
131 | /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. | 138 | /* return TOX_FRIEND_ADDRESS_SIZE byte address to give to others. |
132 | * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] | 139 | * format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] |
133 | */ | 140 | */ |
@@ -284,6 +291,9 @@ void tox_set_sends_receipts(Tox *tox, int friendnumber, int yesno); | |||
284 | * for copy_friendlist. */ | 291 | * for copy_friendlist. */ |
285 | uint32_t tox_count_friendlist(Tox *tox); | 292 | uint32_t tox_count_friendlist(Tox *tox); |
286 | 293 | ||
294 | /* Return the number of online friends in the instance m. */ | ||
295 | uint32_t tox_get_num_online_friends(Tox *tox); | ||
296 | |||
287 | /* Copy a list of valid friend IDs into the array out_list. | 297 | /* Copy a list of valid friend IDs into the array out_list. |
288 | * If out_list is NULL, returns 0. | 298 | * If out_list is NULL, returns 0. |
289 | * Otherwise, returns the number of elements copied. | 299 | * Otherwise, returns the number of elements copied. |